#ifndef CONTIKI_CLOCK_AVR_H
#define CONTIKI_CLOCK_AVR_H

#if defined (__AVR_ATmega128__)

#define AVR_OUTPUT_COMPARE_INT TIMER0_COMP_vect

#define OCRSetup() \
  /* Select internal clock */ \
  ASSR = 0x00; 				  \
\
  /* Set counter to zero */   \
  TCNT0 = 0;				  \
\
  /*						  \
   * Set comparison register: \
   * Crystal freq. is F_CPU,\
   * pre-scale factor is 1024, we want CLOCK_CONF_SECOND ticks / sec: \
   * F_CPU = 1024 * CLOCK_CONF_SECOND * OCR0 \
   */ \
  OCR0 = F_CPU/1024UL/CLOCK_CONF_SECOND; \
\
  /* 								\
   * Set timer control register: 	\
   *  - prescale: 1024 (CS00 - CS02) \
   *  - counter reset via comparison register (WGM01) \
   */ 								\
  TCCR0 =  _BV(CS00) | _BV(CS01) |  _BV(CS02) |  _BV(WGM01); \
\
  /* Clear interrupt flag register */ \
  TIFR = 0x00; \
\
  /* \
   * Raise interrupt when value in OCR0 is reached. Note that the \
   * counter value in TCNT0 is cleared automatically. \
   */ \
  TIMSK = _BV (OCIE0);

#elif defined (__AVR_ATmega128RFA1__) && 0
/* Uses the general routine below at present */

#define AVR_OUTPUT_COMPARE_INT TIMER0_COMPA_vect
#define OCRSetup() \
  /* Select internal clock */ \
  ASSR = 0x00; 				  \
\
  /* Set counter to zero */   \
  TCNT0 = 0;				  \
\
  /*						  \
   * Set comparison register: \
   * Crystal freq. is F_CPU,\
   * pre-scale factor is 1024, we want CLOCK_CONF_SECOND ticks / sec: \
   * F_CPU = 1024 * CLOCK_CONF_SECOND * OCR0A, less 1 for CTC mode \
   */ \
  OCR0A = F_CPU/1024/CLOCK_CONF_SECOND - 1; \
\
  /* 								\
   * Set timer control register: 	\
   *  - prescale: 1024 (CS00 - CS02) \
   *  - counter reset via comparison register (WGM01) \
   */ 								\
  TCCR0A = _BV(WGM01); \
  TCCR0B =  _BV(CS00) | _BV(CS02); \
\
  /* Clear interrupt flag register */ \
  TIFR0 = TIFR0; \
\
  /* \
   * Raise interrupt when value in OCR0 is reached. Note that the \
   * counter value in TCNT0 is cleared automatically. \
   */ \
  TIMSK0 = _BV (OCIE0A);

  
#elif defined (__AVR_ATmega1284P__) || (__AVR_AT90USB1287__) || (__AVR_ATmega1281__) || defined (__AVR_ATmega128RFA1__)
/*
  The Raven has a 32768Hz watch crystal that can be used to clock the timer
  while the 1284p is sleeping. The Jackdaw has pads for a crystal. The crystal
  can be used to clock the 8 bit timer2.
  The 1284p routine also uses TIMER2 to sleep a variable number of seconds.
  It restores the values here after a wake.
*/
#if AVR_CONF_USE32KCRYSTAL
#define AVR_OUTPUT_COMPARE_INT TIMER2_COMPA_vect
#define OCRSetup() \
  /* Clock from crystal on TOSC0-1 */ \
  ASSR = _BV(AS2);		      \
\
  /* Set counter to zero */   \
  TCNT2 = 0;				  \
\
  /*						  \
   * Set comparison register: \
   * Crystal freq. is 32768,\
   * pre-scale factor is 8, we want CLOCK_CONF_SECOND ticks / sec: \
   * 32768 = 8 * CLOCK_CONF_SECOND * OCR2A, less 1 for CTC mode\
   */ \
  OCR2A = 32768/8/CLOCK_CONF_SECOND - 1; \
\
  /* 								\
   * Set timer control register: 	\
   *  - prescale: 8 (CS21) \
   *  - counter reset via comparison register (WGM21) \
   */ 								\
  TCCR2A = _BV(WGM21); \
  TCCR2B = _BV(CS21);  \
\
  /* Clear interrupt flag register */ \
  TIFR2 = TIFR2; \
\
  /* \
   * Raise interrupt when value in OCR2 is reached. Note that the \
   * counter value in TCNT2 is cleared automatically. \
   */ \
  TIMSK2 = _BV (OCIE2A);
#else /* !AVR_CONF_USE32KCRYSTAL */

/* Determine the largest value that can be used with 8 bit timer0 */
#ifndef F_CPU
#error "Please define CPU clock speed for your platform. #define F_CPU 8000000UL is typical."
#endif
#if CLOCK_CONF_SECOND == 0
#error "Please define timer ticks per second for your platform. #define CLOCK_CONF_SECOND 128 is typical."
#endif

#ifdef AVR_CONF_TMR0_PRESCALE
#elif F_CPU/CLOCK_CONF_SECOND < 256
  #define AVR_CONF_TMR0_PRESCALE 1
#elif F_CPU/CLOCK_CONF_SECOND < 256 * 8
  #define AVR_CONF_TMR0_PRESCALE 8
#elif F_CPU/CLOCK_CONF_SECOND < 256 * 64
  #define AVR_CONF_TMR0_PRESCALE 64
#elif F_CPU/CLOCK_CONF_SECOND < 256 * 256
  #define AVR_CONF_TMR0_PRESCALE 256
#else
  #define AVR_CONF_TMR0_PRESCALE 1024
#endif

#if F_CPU/CLOCK_CONF_SECOND/AVR_CONF_TMR0_PRESCALE > 255
#error "Can not prescale CPU clock to get specified ticks per second. F_CPU/CLOCK_CONF_SECOND/1024 must be less than 256."
#endif

#if AVR_CONF_TMR0_PRESCALE == 1
  #define AVR_TCCR0B_CONF _BV(CS00)
#elif AVR_CONF_TMR0_PRESCALE == 8
  #define AVR_TCCR0B_CONF _BV(CS01)
#elif AVR_CONF_TMR0_PRESCALE == 64
  #define AVR_TCCR0B_CONF _BV(CS01) | _BV(CS00)
#elif AVR_CONF_TMR0_PRESCALE == 256
  #define AVR_TCCR0B_CONF _BV(CS02)
#elif AVR_CONF_TMR0_PRESCALE == 1024
  #define AVR_TCCR0B_CONF _BV(CS02) | _BV(CS00)
#else
#error "Prescale factor not supported. Allowed values are 1,8,64,256,1024."
#endif

#define AVR_OUTPUT_COMPARE_INT TIMER0_COMPA_vect

#define OCRSetup() \
  /* Select internal clock */ \
  ASSR = 0x00; 				  \
\
  /* Set counter to zero */   \
  TCNT0 = 0;				  \
\
  /*						  \
   * Set comparison register: \
   * Crystal freq. is F_CPU, prescale is given, \
   * We want CLOCK_CONF_SECOND ticks / sec: \
   * F_CPU = AVR_CONF_TMR0_PRESCALE * CLOCK_CONF_SECOND * OCR2A, less 1 for CTC mode \
   */ \
  OCR0A = F_CPU/AVR_CONF_TMR0_PRESCALE/CLOCK_CONF_SECOND - 1; \
\
  /* 								\
   * Set timer control register: 	\
   *  - prescale according to AVR_CONF_TMR0_PRESCALE \
   *  - counter reset via comparison register (WGM01) \
   */ 								\
  TCCR0A = _BV(WGM01); \
  TCCR0B =  AVR_TCCR0B_CONF; \
\
  /* Clear interrupt flag register */ \
  TIFR0 = TIFR0; \
\
  /* \
   * Raise interrupt when value in OCR0 is reached. Note that the \
   * counter value in TCNT0 is cleared automatically. \
   */ \
  TIMSK0 = _BV (OCIE0A);
#endif /* AVR_CONF_USE32KCRYSTAL */

#elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega328P__)

#define OCRSetup() \
  /* Set counter to zero */   \
  TCNT0 = 0;   \
\
  /*   \
   * Set comparison register: \
   * Crystal freq. is F_CPU,\
   * pre-scale factor is 256, want CLOCK_CONF_SECOND ticks / sec: \
   */ \
  OCR0A = F_CPU/256UL/CLOCK_CONF_SECOND - 1; \
\
  /* \
   * Set timer control register: \
   *  - prescale: 256 (CS02) \
   *  - counter reset via comparison register (WGM01) \
   */ \
  TCCR0A =  _BV(WGM01); \
  TCCR0B =  _BV(CS02); \
\
  /* Clear interrupt flag register */ \
  TIFR0 = 0x00; \
\
  /* \
   * Raise interrupt when value in OCR0 is reached. Note that the \
   * counter value in TCNT0 is cleared automatically. \
   */ \
  TIMSK0 = _BV (OCIE0A);

#define AVR_OUTPUT_COMPARE_INT TIMER0_COMPA_vect

#elif defined (__AVR_ATmega8515__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__)

#define AVR_OUTPUT_COMPARE_INT TIMER0_COMP_vect

#define OCRSetup() \
  /* Set counter to zero */   \
  TCNT0 = 0;   \
\
  /*   \
   * Set comparison register: \
   * Crystal freq. is F_CPU,\
   * pre-scale factor is 256, we want CLOCK_CONF_SECOND ticks / sec: \
   * F_CPU = 256 * CLOCK_CONF_SECOND * OCR0 \
   */ \
  OCR0 = F_CPU/256UL/CLOCK_CONF_SECOND; \
\
  /* \
   * Set timer control register: \
   *  - prescale: 256 (CS02) \
   *  - counter reset via comparison register (WGM01) \
   */ \
  TCCR0 =  _BV(CS02) |  _BV(WGM01); \
\
  /* Clear interrupt flag register */ \
  TIFR = 0x00; \
\
  /* \
   * Raise interrupt when value in OCR0 is reached. Note that the \
   * counter value in TCNT0 is cleared automatically. \
   */ \
  TIMSK = _BV (OCIE0);

#elif defined (__AVR_ATmega8__)

#define AVR_OUTPUT_COMPARE_INT TIMER2_COMP_vect

#define OCRSetup() \
  /* Set counter to zero */   \
  TCNT2 = 0;   \
\
  /*   \
   * Set comparison register: \
   * Crystal freq. is F_CPU,\
   * pre-scale factor is 256, we want CLOCK_CONF_SECOND ticks / sec: \
   * F_CPU = 256 * CLOCK_CONF_SECOND * OCR2 \
   */ \
  OCR2 = F_CPU/256UL/CLOCK_CONF_SECOND; \
\
  /* \
   * Set timer control register: \
   *  - prescale: 256 (CS21 CS22) \
   *  - counter reset via comparison register (WGM21) \
   */ \
  TCCR2 =  _BV(CS22) | _BV(CS21) |  _BV(WGM21); \
\
  /* Clear interrupt flag register */ \
  TIFR = 0x00; \
\
  /* \
   * Raise interrupt when value in OCR2 is reached. Note that the \
   * counter value in TCNT2 is cleared automatically. \
   */ \
  TIMSK = _BV (OCIE2);
#else
#error "Setup CPU in clock-avr.h"
#endif

#endif //CONTIKI_CLOCK_AVR_H
