AskSin++
Activity.h
1 //- -----------------------------------------------------------------------------------------------------------------------
2 // AskSin++
3 // 2016-10-31 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
4 //- -----------------------------------------------------------------------------------------------------------------------
5 
6 #ifndef __ACTIVITY_H__
7 #define __ACTIVITY_H__
8 
9 #include <Debug.h>
10 #include <AlarmClock.h>
11 #include <Radio.h>
12 #if defined(ARDUINO_ARCH_AVR) && ! ( defined(ARDUINO_AVR_ATmega32) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega128__))
13 #include <LowPower.h>
14 #endif
15 
16 namespace as {
17 
18 #if defined(ARDUINO_ARCH_AVR) && ! (defined(ARDUINO_AVR_ATmega32) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega128__))
19 
20 
21 template <bool ENABLETIMER2=false, bool ENABLEADC=false>
22 class Idle {
23 public:
24 
25  static void waitSerial () {
26 // DPRINT(F("Go sleep - ")); DHEXLN((uint16_t)sysclock.next());
27  Serial.flush();
28  while (!(UCSR0A & (1 << UDRE0))) { // Wait for empty transmit buffer
29  UCSR0A |= 1 << TXC0; // mark transmission not complete
30  }
31  while (!(UCSR0A & (1 << TXC0))); // Wait for the transmission to complete
32  }
33 
34  template <class Hal>
35  static void powerSave (__attribute__((unused)) Hal& hal) {
36 #if defined __AVR_ATmega644P__ || defined (__AVR_ATmega1284P__)
37  LowPower.idle(SLEEP_FOREVER,ENABLEADC==true?ADC_ON:ADC_OFF,ENABLETIMER2==false?TIMER2_OFF:TIMER2_ON,TIMER1_ON,TIMER0_OFF,SPI_ON,USART1_OFF,USART0_ON,TWI_OFF);
38 #elif defined __AVR_ATmega2560__
39  //there is an issue, so you have to manual change something in Low-Power.cpp: https://github.com/rocketscream/Low-Power/issues/30#issuecomment-336801240
40  LowPower.idle(SLEEP_FOREVER,ENABLEADC==true?ADC_ON:ADC_OFF, TIMER5_OFF, TIMER4_OFF, TIMER3_OFF,ENABLETIMER2==false?TIMER2_OFF:TIMER2_ON, TIMER1_ON, TIMER0_OFF, SPI_ON, USART3_OFF,USART2_OFF, USART1_OFF, USART0_ON, TWI_OFF);
41 #else
42  LowPower.idle(SLEEP_FOREVER,ENABLEADC==true?ADC_ON:ADC_OFF,ENABLETIMER2==false?TIMER2_OFF:TIMER2_ON,TIMER1_ON,TIMER0_OFF,SPI_ON,USART0_ON,TWI_OFF);
43 #endif
44  }
45 
46 };
47 
48 template <bool ENABLETIMER2=false>
49 class Sleep : public Idle<ENABLETIMER2> {
50 public:
51  static uint32_t doSleep (uint32_t ticks) {
52  uint32_t offset = 0;
53  period_t sleeptime = SLEEP_FOREVER;
54 
55  if( ticks > seconds2ticks(8) ) { offset = seconds2ticks(8); sleeptime = SLEEP_8S; }
56 // else if( ticks > seconds2ticks(4) ) { offset = seconds2ticks(4); sleeptime = SLEEP_4S; }
57 // else if( ticks > seconds2ticks(2) ) { offset = seconds2ticks(2); sleeptime = SLEEP_2S; }
58  else if( ticks > seconds2ticks(1) ) { offset = seconds2ticks(1); sleeptime = SLEEP_1S; }
59 // else if( ticks > millis2ticks(500) ) { offset = millis2ticks(500); sleeptime = SLEEP_500MS; }
60 // else if( ticks > millis2ticks(250) ) { offset = millis2ticks(250); sleeptime = SLEEP_250MS; }
61  else if( ticks > millis2ticks(120) ) { offset = millis2ticks(120); sleeptime = SLEEP_120MS; }
62 // else if( ticks > millis2ticks(60) ) { offset = millis2ticks(60); sleeptime = SLEEP_60MS; }
63 // else if( ticks > millis2ticks(30) ) { offset = millis2ticks(30); sleeptime = SLEEP_30MS; }
64  else if( ticks > millis2ticks(15) ) { offset = millis2ticks(15); sleeptime = SLEEP_15MS; }
65 
66  if( ENABLETIMER2 == false ) {
67  LowPower.powerDown(sleeptime,ADC_OFF,BOD_OFF);
68  }
69  else {
70  LowPower.powerExtStandby(sleeptime,ADC_OFF,BOD_OFF,TIMER2_ON);
71  }
72  return offset;
73  }
74 
75  template <class Hal>
76  static void powerSave (Hal& hal) {
77  sysclock.disable();
78  uint32_t ticks = sysclock.next();
79  if( sysclock.isready() == false ) {
80  if( ticks == 0 || ticks > millis2ticks(15) ) {
81  hal.setIdle();
82  uint32_t offset = doSleep(ticks);
83  hal.unsetIdle();
84  sysclock.correct(offset);
85  sysclock.enable();
86  }
87  else{
88  sysclock.enable();
89  //Idle<ENABLETIMER2>::powerSave(hal);
90  }
91  }
92  else {
93  sysclock.enable();
94  }
95  }
96 };
97 
98 #ifndef NORTC
99 class SleepRTC : public Idle<true> {
100 public:
101  static uint32_t doSleep (uint32_t ticks) {
102  uint32_t offset = 0;
103  period_t sleeptime = SLEEP_FOREVER;
104 
105  if( ticks > seconds2ticks(1) ) { sleeptime = SLEEP_FOREVER; }
106  else if( ticks > millis2ticks(500) ) { sleeptime = SLEEP_500MS; }
107  else if( ticks > millis2ticks(250) ) { sleeptime = SLEEP_250MS; }
108  else if( ticks > millis2ticks(120) ) { sleeptime = SLEEP_120MS; }
109  else if( ticks > millis2ticks(60) ) { sleeptime = SLEEP_60MS; }
110  else if( ticks > millis2ticks(30) ) { sleeptime = SLEEP_30MS; }
111  else if( ticks > millis2ticks(15) ) { sleeptime = SLEEP_15MS; }
112 
113  uint32_t c1 = rtc.getCounter(true);
114  LowPower.powerSave(sleeptime,ADC_OFF,BOD_OFF,TIMER2_ON);
115  uint32_t c2 = rtc.getCounter(false);
116  offset = (c2 - c1) * seconds2ticks(1) / 256;
117  // DHEX(ticks);DPRINT(" ");DHEX(c1);DPRINT(":");DHEX(c2);DPRINT(" ");DHEXLN(offset);
118 
119  return min(ticks,offset);
120  }
121 
122  template <class Hal>
123  static void powerSave (Hal& hal) {
124  sysclock.disable();
125  uint32_t ticks = sysclock.next();
126  if( sysclock.isready() == false ) {
127  if( ticks == 0 || ticks > millis2ticks(15) ) {
128  hal.setIdle();
129  uint32_t offset = doSleep(ticks);
130  hal.unsetIdle();
131  sysclock.correct(offset);
132  sysclock.enable();
133  }
134  else{
135  sysclock.enable();
137  }
138  }
139  else {
140  sysclock.enable();
141  }
142  }
143 };
144 #endif // NORTC
145 
146 #endif
147 
148 class Activity : public Alarm {
149 
150  volatile bool awake;
151 
152 public:
153 
154  Activity () : Alarm(0), awake(false) {
155  async(true);
156  }
157 
158  virtual ~Activity () {}
159 
160  virtual void trigger (__attribute__((unused)) AlarmClock& clock) {
161  awake = false;
162  }
163 
164  // do not sleep for time in ticks
165  void stayAwake (uint32_t time) {
166  uint32_t old = sysclock.get(*this);
167  if( old < time ) {
168  awake = true;
169  sysclock.cancel(*this);
170  tick = time;
171  sysclock.add(*this);
172  }
173  }
174 
175  bool stayAwake () const {
176  return awake;
177  }
178 
179  template <class Saver,class Hal>
180  void savePower (Hal& hal) {
181  if( awake == false ) {
182 #ifndef NDEBUG
183  Saver::waitSerial();
184 #endif
185  Saver::powerSave(hal);
186  }
187  else {
188  // ensure radio is up and running
189  hal.wakeup();
190  }
191  }
192 
193  template <class Hal>
194  void sleepForever (Hal& hal) {
195  hal.setIdle();
196  while( true ) {
197 #if defined(ARDUINO_ARCH_AVR) && ! (defined(ARDUINO_AVR_ATmega32) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega128__))
198  LowPower.powerDown(SLEEP_FOREVER,ADC_OFF,BOD_OFF);
199 #endif
200  }
201  }
202 
203 };
204 
205 template <class HalType>
206 class BurstDetector : public Alarm {
207  bool burst;
208  HalType& hal;
209 public:
210  BurstDetector (HalType& h) : Alarm(millis2ticks(250)), burst(false), hal(h) {}
211  virtual ~BurstDetector () {}
212  virtual void trigger (AlarmClock& clock) {
213  uint32_t next = millis2ticks(250);
214  if( hal.activity.stayAwake() == false ) {
215  bool detect = hal.radio.detectBurst();
216  if( detect == true ) {
217  if( burst == false ) {
218  burst = true;
219  next = millis2ticks(30);
220  // DPRINTLN("1");
221  }
222  else {
223  burst = false;
224  hal.activity.stayAwake(millis2ticks(500));
225  // DPRINTLN("2");
226  }
227  }
228  else {
229  burst = false;
230  }
231  }
232  set(next);
233  clock.add(*this);
234  }
235  void enable(AlarmClock& clock) {
236  clock.add(*this);
237  }
238 };
239 
240 
241 }
242 
243 #endif
as::Activity
Definition: Activity.h:148
as::BurstDetector
Definition: Activity.h:206
as::Alarm
Definition: Alarm.h:15
as::Sleep
Definition: Activity.h:49
as::AlarmClock
Definition: AlarmClock.h:32
as::SleepRTC
Definition: Activity.h:99
as::Idle
Definition: Activity.h:22