FastArduino  v1.7
C++ library to build fast but small Arduino/AVR projects
watchdog.h
Go to the documentation of this file.
1 // Copyright 2016-2021 Jean-Francois Poilpret
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
21 #ifndef WATCHDOG_HH
22 #define WATCHDOG_HH
23 
24 #include "boards/board.h"
25 #include "boards/board_traits.h"
26 #include <avr/interrupt.h>
27 #include "interrupts.h"
28 #include "events.h"
29 
36 #define REGISTER_WATCHDOG_CLOCK_ISR(EVENT) \
37  ISR(WDT_vect) \
38  { \
39  watchdog::isr_handler::watchdog_clock<EVENT>(); \
40  }
41 
47 #define REGISTER_WATCHDOG_RTT_ISR() \
48  ISR(WDT_vect) \
49  { \
50  watchdog::isr_handler::watchdog_rtt(); \
51  }
52 
61 #define REGISTER_WATCHDOG_ISR_METHOD(HANDLER, CALLBACK) \
62  ISR(WDT_vect) \
63  { \
64  watchdog::isr_handler::watchdog_method<HANDLER, CALLBACK>(); \
65  }
66 
74 #define REGISTER_WATCHDOG_ISR_FUNCTION(CALLBACK) \
75  ISR(WDT_vect) \
76  { \
77  watchdog::isr_handler::watchdog_function<CALLBACK>() : \
78  }
79 
85 #define REGISTER_WATCHDOG_ISR_EMPTY() EMPTY_INTERRUPT(WDT_vect)
86 
93 #define DECL_WATCHDOG_ISR_HANDLERS_FRIEND \
94  friend struct watchdog::isr_handler; \
95  friend void ::WDT_vect();
96 
100 namespace watchdog
101 {
109  enum class TimeOut : uint8_t
110  {
112  TO_16ms = 0,
114  TO_32ms,
116  TO_64ms,
118  TO_125ms,
120  TO_250ms,
122  TO_500ms,
124  TO_1s,
126  TO_2s,
128  TO_4s,
130  TO_8s
131  };
132 
145  {
146  public:
147  WatchdogSignal() = default;
148  WatchdogSignal(const WatchdogSignal&) = delete;
149  WatchdogSignal& operator=(const WatchdogSignal&) = delete;
150 
157  void begin(TimeOut timeout = TimeOut::TO_16ms)
158  {
159  uint8_t config = bits::BV8(WDIE) | (uint8_t(timeout) & MASK_WDP012) |
160  ((uint8_t(timeout) & MASK_WDP3) ? bits::BV8(WDP3) : 0);
161  synchronized begin_with_config(config);
162  }
163 
167  void end()
168  {
169  synchronized
170  {
171  WDTCSR_ = bits::BV8(WDCE, WDE);
172  WDTCSR_ = 0;
173  }
174  }
175 
176  protected:
178  void begin_with_config(uint8_t config) INLINE
179  {
180  __asm__ __volatile__("wdr");
181  MCUSR_ |= 1 << WDRF;
182  WDTCSR_ = bits::BV8(WDCE, WDE);
183  WDTCSR_ = config;
184  }
185 
186  static constexpr const uint8_t MASK_WDP012 = bits::BV8(WDP0, WDP1, WDP2);
187  static constexpr const uint8_t MASK_WDP3 = 0x08U;
189 
190  private:
191  using REG8 = board_traits::REG8;
192  static constexpr const REG8 MCUSR_{MCUSR};
193  static constexpr const REG8 WDTCSR_{WDTCSR};
194  };
195 
202  {
203  public:
210  {
212  }
213 
215  WatchdogRTT(const WatchdogRTT&) = delete;
216  WatchdogRTT& operator=(const WatchdogRTT&) = delete;
218 
225  void begin(TimeOut timeout = TimeOut::TO_16ms)
226  {
227  uint16_t ms_per_tick = bits::BV16(uint8_t(timeout) + 4);
228  uint8_t config = bits::BV8(WDIE) | (uint8_t(timeout) & MASK_WDP012) |
229  ((uint8_t(timeout) & MASK_WDP3) ? bits::BV8(WDP3) : 0);
230 
231  synchronized
232  {
233  begin_with_config(config);
234  millis_per_tick_ = ms_per_tick;
235  millis_ = 0;
236  }
237  }
238 
245  uint32_t millis() const
246  {
247  synchronized return millis_;
248  }
249 
254  void reset()
255  {
256  synchronized millis_ = 0;
257  }
258 
271  void delay(uint32_t ms)
272  {
273  uint32_t limit = millis() + ms;
274  while (millis() < limit)
275  {
276  time::yield();
277  }
278  }
279 
280  protected:
282  // This constructor is used by subclass to avoid calling register_handler()
283  explicit WatchdogRTT(bool dummy UNUSED) {}
284 
285  void on_tick()
286  {
287  millis_ += millis_per_tick_;
288  }
290 
291  private:
292  volatile uint32_t millis_ = 0UL;
293  uint16_t millis_per_tick_ = 0U;
294 
295  friend struct isr_handler;
296  };
297 
304  template<typename EVENT> class Watchdog : public WatchdogRTT
305  {
306  static_assert(events::Event_trait<EVENT>::IS_EVENT, "EVENT type must be an events::Event<T>");
307 
308  public:
319  explicit Watchdog(containers::Queue<EVENT>& event_queue) : WatchdogRTT{true}, event_queue_{event_queue}
320  {
322  }
323 
325  Watchdog(const Watchdog&) = delete;
326  Watchdog& operator=(const Watchdog&) = delete;
328 
329  private:
330  void on_tick()
331  {
332  WatchdogRTT::on_tick();
333  event_queue_.push_(EVENT{events::Type::WDT_TIMER});
334  }
335 
336  containers::Queue<EVENT>& event_queue_;
337 
338  friend struct isr_handler;
339  };
340 
342  struct isr_handler
343  {
344  template<typename EVENT> static void watchdog_clock()
345  {
346  interrupt::HandlerHolder<watchdog::Watchdog<EVENT>>::handler()->on_tick();
347  }
348 
349  static void watchdog_rtt()
350  {
351  interrupt::HandlerHolder<watchdog::WatchdogRTT>::handler()->on_tick();
352  }
353 
354  template<typename HANDLER, void (HANDLER::*CALLBACK)()> static void watchdog_method()
355  {
356  interrupt::CallbackHandler<void (HANDLER::*)(), CALLBACK>::call();
357  }
358 
359  template<void (*CALLBACK)()> static void watchdog_function()
360  {
361  interrupt::CallbackHandler<void (*)(), CALLBACK>::call();
362  }
363  };
365 }
366 
367 #endif /* WATCHDOG_HH */
368 
watchdog
Defines the simple API for Watchdog timer management.
Definition: watchdog.h:101
watchdog::TimeOut
TimeOut
Defines the watchdog timeout period; watchdog interrupts will be triggered at the selected period.
Definition: watchdog.h:110
watchdog::WatchdogSignal::begin
void begin(TimeOut timeout=TimeOut::TO_16ms)
Start the watchdog timer with the given timeout period.
Definition: watchdog.h:157
watchdog::WatchdogRTT::begin
void begin(TimeOut timeout=TimeOut::TO_16ms)
Start the watchdog clock with the given timeout period.
Definition: watchdog.h:225
watchdog::WatchdogRTT
Simple API to use watchdog timer as a real-time clock.
Definition: watchdog.h:202
containers::Queue< EVENT >
watchdog::WatchdogSignal
Simple API to handle watchdog signals.
Definition: watchdog.h:145
time::yield
void yield()
Utility method used by many FastArduino API in order to "yield" some processor time; concretely it ju...
Definition: time.cpp:22
watchdog::WatchdogSignal::end
void end()
Stop this watchdog timer.
Definition: watchdog.h:167
bits::BV8
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Definition: bits.h:41
events.h
Support for events management.
watchdog::WatchdogRTT::reset
void reset()
Reset current counter to 0.
Definition: watchdog.h:254
watchdog::WatchdogRTT::WatchdogRTT
WatchdogRTT()
Construct a new watchdog-based clock that will count elapsed milliseconds since it was started with b...
Definition: watchdog.h:209
watchdog::WatchdogRTT::delay
void delay(uint32_t ms)
Delay program execution for the given amount of milliseconds.
Definition: watchdog.h:271
UNUSED
#define UNUSED
Specific GCC attribute to declare an argument or variable unused, so that the compiler does not emit ...
Definition: defines.h:45
containers::Queue::push_
bool push_(TREF item)
Push item to the end of this queue, provided there is still available space in its ring buffer.
watchdog::Watchdog
Simple API to use watchdog timer as a clock for events generation.
Definition: watchdog.h:305
watchdog::Watchdog::Watchdog
Watchdog(containers::Queue< EVENT > &event_queue)
Construct a new watchdog-based clock that will, for each watchdog timeout, add an event to the given ...
Definition: watchdog.h:319
watchdog::WatchdogRTT::millis
uint32_t millis() const
Get the number of milliseconds that elapsed since begin() was called.
Definition: watchdog.h:245
bits::BV16
static constexpr uint16_t BV16(uint8_t bit)
Create a uint16_t bitmask for the given bit number.
Definition: bits.h:148
events::Type::WDT_TIMER
const uint8_t WDT_TIMER
Type of events generated by watchdog::Watchdog for each watchdog timeout interrupt.
Definition: events.h:105
interrupts.h
General API for handling AVR interrupt vectors.
interrupt::register_handler
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Definition: interrupts.h:157
watchdog::TimeOut::TO_16ms
@ TO_16ms
Watchdog timeout 16 ms.
INLINE
#define INLINE
Specific GCC attribute to force the compiler to always inline code of a given function.
Definition: defines.h:57