text: /*
   * Copyright (c) 2007, Swedish Institute of Computer Science.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   * 3. Neither the name of the Institute nor the names of its contributors
   *    may be used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   *
   * This file is part of the Contiki operating system.
   *
   */
  
  /**
   * \file
   *         AVR-specific rtimer code
   *         Defaults to Timer3 for those ATMEGAs that have it.
   *         If Timer3 not present Timer1 will be used.
   * \author
   *         Fredrik Osterlind <fros@sics.se>
   *         Joakim Eriksson <joakime@sics.se>
   */
  
  /* OBS: 8 seconds maximum time! */
  
  #include <avr/io.h>
  #include <avr/interrupt.h>
  #include <stdio.h>
  
  #include "sys/energest.h"
  #include "sys/rtimer.h"
  #include "rtimer-arch.h"
  
  #if defined(__AVR_ATmega1284P__)
  #define ETIMSK TIMSK3
  #define ETIFR TIFR3
  #define TICIE3 ICIE3
  
  //Has no 'C', so we just set it to B. The code doesn't really use C so this
  //is safe to do but lets it compile. Probably should enable the warning if
  //it is ever used on other platforms.
  //#warning no OCIE3C in timer3 architecture, hopefully it won't be needed!
  
  #define OCIE3C	OCIE3B
  #define OCF3C	OCF3B
  #endif
  
  #if defined(__AVR_ATmega1281__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega128RFA1__)
  #define ETIMSK TIMSK3
  #define ETIFR TIFR3
  #define TICIE3 ICIE3
  #endif
  
  #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega644__)
  #define TIMSK TIMSK1
  #define TICIE1 ICIE1
  #define TIFR TIFR1
  #endif
  
  /* Track flow through rtimer interrupts*/
  #if DEBUGFLOWSIZE&&0
  extern uint8_t debugflowsize,debugflow[DEBUGFLOWSIZE];
  #define DEBUGFLOW(c) if (debugflowsize<(DEBUGFLOWSIZE-1)) debugflow[debugflowsize++]=c
  #else
  #define DEBUGFLOW(c)
  #endif
  
  /*---------------------------------------------------------------------------*/
  #if defined(TCNT3) && RTIMER_ARCH_PRESCALER
  ISR (TIMER3_COMPA_vect) {
    DEBUGFLOW('/');
    ENERGEST_ON(ENERGEST_TYPE_IRQ);
  
    /* Disable rtimer interrupts */
    ETIMSK &= ~((1 << OCIE3A) | (1 << OCIE3B) | (1 << TOIE3) |
        (1 << TICIE3) | (1 << OCIE3C));
  
  #if RTIMER_CONF_NESTED_INTERRUPTS
    /* Enable nested interrupts. Allows radio interrupt during rtimer interrupt. */
    /* All interrupts are enabled including recursive rtimer, so use with caution */
    sei();
  #endif
  
    /* Call rtimer callback */
    rtimer_run_next();
  
    ENERGEST_OFF(ENERGEST_TYPE_IRQ);
    DEBUGFLOW('\\');
  }
  
  #elif RTIMER_ARCH_PRESCALER
  #warning "No Timer3 in rtimer-arch.c - using Timer1 instead"
  ISR (TIMER1_COMPA_vect) {
    DEBUGFLOW('/');
    TIMSK &= ~((1<<TICIE1)|(1<<OCIE1A)|(1<<OCIE1B)|(1<<TOIE1));
  
    rtimer_run_next();
    DEBUGFLOW('\\');
  }
  
  #endif
  /*---------------------------------------------------------------------------*/
  void
  rtimer_arch_init(void)
  {
  #if RTIMER_ARCH_PRESCALER
    /* Disable interrupts (store old state) */
    uint8_t sreg;
    sreg = SREG;
    cli ();
  
  #ifdef TCNT3
    /* Disable all timer functions */
    ETIMSK &= ~((1 << OCIE3A) | (1 << OCIE3B) | (1 << TOIE3) |
        (1 << TICIE3) | (1 << OCIE3C));
    /* Write 1s to clear existing timer function flags */
    ETIFR |= (1 << ICF3) | (1 << OCF3A) | (1 << OCF3B) | (1 << TOV3) |
    (1 << OCF3C); 
  
    /* Default timer behaviour */
    TCCR3A = 0;
    TCCR3B = 0;
    TCCR3C = 0;
  
    /* Reset counter */
    TCNT3 = 0;
  
  #if RTIMER_ARCH_PRESCALER==1024
    TCCR3B |= 5;
  #elif RTIMER_ARCH_PRESCALER==256
    TCCR3B |= 4;
  #elif RTIMER_ARCH_PRESCALER==64
    TCCR3B |= 3;
  #elif RTIMER_ARCH_PRESCALER==8
    TCCR3B |= 2;
  #elif RTIMER_ARCH_PRESCALER==1
    TCCR3B |= 1;
  #else
  #error Timer3 PRESCALER factor not supported.
  #endif
  
  #elif RTIMER_ARCH_PRESCALER
    /* Leave timer1 alone if PRESCALER set to zero */
    /* Obviously you can not then use rtimers */
  
    TIMSK &= ~((1<<TICIE1)|(1<<OCIE1A)|(1<<OCIE1B)|(1<<TOIE1));
    TIFR |= (1 << ICF1) | (1 << OCF1A) | (1 << OCF1B) | (1 << TOV1);
  
    /* Default timer behaviour */
    TCCR1A = 0;
    TCCR1B = 0;
  
    /* Reset counter */
    TCNT1 = 0;
  
    /* Start clock */
  #if RTIMER_ARCH_PRESCALER==1024
    TCCR1B |= 5;
  #elif RTIMER_ARCH_PRESCALER==256
    TCCR1B |= 4;
  #elif RTIMER_ARCH_PRESCALER==64
    TCCR1B |= 3;
  #elif RTIMER_ARCH_PRESCALER==8
    TCCR1B |= 2;
  #elif RTIMER_ARCH_PRESCALER==1
    TCCR1B |= 1;
  #else
  #error Timer1 PRESCALER factor not supported.
  #endif
  
  #endif /* TCNT3 */
  
    /* Restore interrupt state */
    SREG = sreg;
  #endif /* RTIMER_ARCH_PRESCALER */
  }
  /*---------------------------------------------------------------------------*/
  void
  rtimer_arch_schedule(rtimer_clock_t t)
  {
  #if RTIMER_ARCH_PRESCALER
    /* Disable interrupts (store old state) */
    uint8_t sreg;
    sreg = SREG;
    cli ();
    DEBUGFLOW(':');
  #ifdef TCNT3
    /* Set compare register */
    OCR3A = t;
    /* Write 1s to clear all timer function flags */
    ETIFR |= (1 << ICF3) | (1 << OCF3A) | (1 << OCF3B) | (1 << TOV3) |
    (1 << OCF3C);
    /* Enable interrupt on OCR3A match */
    ETIMSK |= (1 << OCIE3A);
  
  #elif RTIMER_ARCH_PRESCALER
    /* Set compare register */
    OCR1A = t;
    TIFR |= (1 << ICF1) | (1 << OCF1A) | (1 << OCF1B) | (1 << TOV1);
    TIMSK |= (1 << OCIE1A);
  
  #endif
  
    /* Restore interrupt state */
    SREG = sreg;
  #endif /* RTIMER_ARCH_PRESCALER */
  }
  
  #if RDC_CONF_MCU_SLEEP
  /*---------------------------------------------------------------------------*/
  void
  rtimer_arch_sleep(rtimer_clock_t howlong)
  {
  /* Deep Sleep for howlong rtimer ticks. This will stop all timers except
   * for TIMER2 which can be clocked using an external crystal.
   * Unfortunately this is an 8 bit timer; a lower prescaler gives higher
   * precision but smaller maximum sleep time.
   * Here a maximum 128msec (contikimac 8Hz channel check sleep) is assumed.
   * The rtimer and system clocks are adjusted to reflect the sleep time.
   */
  #include <avr/sleep.h>
  #include <dev/watchdog.h>
  uint32_t longhowlong;
  #if AVR_CONF_USE32KCRYSTAL
  /* Save TIMER2 configuration if clock.c is using it */
      uint8_t savedTCNT2=TCNT2, savedTCCR2A=TCCR2A, savedTCCR2B = TCCR2B, savedOCR2A = OCR2A;
  #endif
      cli();
  	watchdog_stop();
  	set_sleep_mode(SLEEP_MODE_PWR_SAVE);
  
  /* Set TIMER2 clock asynchronus from external source, CTC mode */
      ASSR |= (1 << AS2);
      TCCR2A =(1<<WGM21);
  /* Set prescaler and TIMER2 output compare register */
  #if 0    //Prescale by 1024 -   32 ticks/sec, 8 seconds max sleep
      TCCR2B =((1<<CS22)|(1<<CS21)|(1<<CS20));
  	longhowlong=howlong*32UL; 
  #elif 0  // Prescale by 256 -  128 ticks/sec, 2 seconds max sleep
  	TCCR2B =((1<<CS22)|(1<<CS21)|(0<<CS20));
  	longhowlong=howlong*128UL;
  #elif 0  // Prescale by 128 -  256 ticks/sec, 1 seconds max sleep
  	TCCR2B =((1<<CS22)|(0<<CS21)|(1<<CS20));
  	longhowlong=howlong*256UL;
  #elif 0  // Prescale by  64 -  512 ticks/sec, 500 msec max sleep
  	TCCR2B =((1<<CS22)|(0<<CS21)|(0<<CS20));
  	longhowlong=howlong*512UL;
  #elif 1  // Prescale by  32 - 1024 ticks/sec, 250 msec max sleep
  	TCCR2B =((0<<CS22)|(1<<CS21)|(1<<CS20));
  	longhowlong=howlong*1024UL;
  #elif 0  // Prescale by   8 - 4096 ticks/sec, 62.5 msec max sleep
  	TCCR2B =((0<<CS22)|(1<<CS21)|(0<<CS20));
  	longhowlong=howlong*4096UL;
  #else    // No Prescale -    32768 ticks/sec, 7.8 msec max sleep
  	TCCR2B =((0<<CS22)|(0<<CS21)|(1<<CS20));
  	longhowlong=howlong*32768UL;
  #endif
  	OCR2A = longhowlong/RTIMER_ARCH_SECOND;
  
  /* Reset timer count, wait for the write (which assures TCCR2x and OCR2A are finished) */
      TCNT2 = 0; 
      while(ASSR & (1 << TCN2UB));
  
  /* Enable TIMER2 output compare interrupt, sleep mode and sleep */
      TIMSK2 |= (1 << OCIE2A);
      SMCR |= (1 <<  SE);
  	sei();
  	ENERGEST_OFF(ENERGEST_TYPE_CPU);
  	if (OCR2A) sleep_mode();
  	  //...zzZZZzz...Ding!//
  
  /* Disable sleep mode after wakeup, so random code cant trigger sleep */
      SMCR  &= ~(1 << SE);
  
  /* Adjust rtimer ticks if rtimer is enabled. TIMER3 is preferred, else TIMER1 */
  #if RTIMER_ARCH_PRESCALER
  #ifdef TCNT3
      TCNT3 += howlong;
  #else
      TCNT1 += howlong;
  #endif
  #endif
  	ENERGEST_ON(ENERGEST_TYPE_CPU);
  
  #if AVR_CONF_USE32KCRYSTAL
  /* Restore clock.c configuration */
      cli();
      TCCR2A = savedTCCR2A;
      TCCR2B = savedTCCR2B;
      OCR2A  = savedOCR2A;
      TCNT2  = savedTCNT2;
      sei();
  #else
  /* Disable TIMER2 interrupt */
      TIMSK2 &= ~(1 << OCIE2A);
  #endif
      watchdog_start();
  
  /* Adjust clock.c for the time spent sleeping */
  	longhowlong=CLOCK_CONF_SECOND;
  	longhowlong*=howlong;
      clock_adjust_ticks(longhowlong/RTIMER_ARCH_SECOND);
  
  }
  #if !AVR_CONF_USE32KCRYSTAL
  /*---------------------------------------------------------------------------*/
  /* TIMER2 Interrupt service */
  
  ISR(TIMER2_COMPA_vect)
  {
  //    TIMSK2 &= ~(1 << OCIE2A);       //Just one interrupt needed for waking
  }
  #endif /* !AVR_CONF_USE32KCRYSTAL */
  #endif /* RDC_CONF_MCU_SLEEP */
  
  