aboutsummaryrefslogtreecommitdiff
path: root/examples/Scheduler_example7_WDT/Scheduler_example7_WDT.ino
blob: ab880d259506a888b9e548eceb4e66f6951067ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/** 
 *  TaskScheduler Test sketch - use of task IDs and watchdog timer to identify hung tasks
 *  Test case: 
 *    Watchdog timer is set to 2 seconds (interrupt + reset)
 *    A hearbeat task (resetting the watchdog timer) is scheduled with 500 ms interval
 *    A number of tasks are running every 1 second and "rolling the dice" 0..9.  If 5, task is made to enter infinite loop
 *    Device should reset in 2 seconds after a task enters infinite loop
 *    A task id and a control point number are saved to EEPROM prior to device reset, and are displayed after reboot.
 *    In real life, device might chose to NOT activate certain tasks which failed previously (failed sensors for instance)
 */

#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_WDT_IDS
#include <TaskScheduler.h>

#include <EEPROM.h>
#include <avr/wdt.h>

Scheduler ts;

// Three tasks emulating accidental infinite loop
Task tTask1(1000, -1, &TaskCB, &ts, true);
Task tTask2(1000, -1, &TaskCB, &ts, true);
Task tTask3(1000, -1, &TaskCB, &ts, true);

// Heartbeat task - resetting the watchdog timer periodically
// Initiates WDT on enable, and deactivates it on disable
Task tHB(500, -1, &HB, &ts, false, &HBOn, &HBOff);

/**
 * Emulating task callback function
 *   Prints task id and randomly "hangs" in two places.
 *   Control points are stored on the task prior to section which might hang,
 *   making this information available to the WDT interrupt handler
 */
void TaskCB() {
  Task& T = ts.currentTask();
  
  Serial.print("Task #:"); 
  Serial.print(T.getId()); 
  Serial.print(" current iteration = "); 
  Serial.println(T.getRunCounter());

// Hang if random number between 0 and 9 is 5 (10% probability)
  T.setControlPoint(10);
  if (random(10) == 5) for(;;);
  
// Hang if random number between 0 and 99 is more that 85 (15% probability)
  T.setControlPoint(85);
  if (random(100) > 84) for(;;);
}

/**
 * This On Enable method sets up the WDT
 * for interrupt and reset after 2 seconds
 */
bool HBOn() {
  
  //disable interrupts
  cli();
  //reset watchdog
  wdt_reset();
  //set up WDT interrupt
  WDTCSR = (1<<WDCE)|(1<<WDE);
  //Start watchdog timer with aDelay prescaller
  WDTCSR = (1<<WDIE)|(1<<WDE)|(WDTO_2S & 0x2F);
//  WDTCSR = (1<<WDIE)|(WDTO_2S & 0x2F);  // interrupt only without reset
  //Enable global interrupts
  sei();
}

/**
 * This On Disable method disables WDT
 */
void HBOff() {
  wdt_disable();
}

/**
 * This is a periodic reset of WDT
 */
void HB() {
  wdt_reset();

}

/**
 * Watchdog timeout ISR
 * 
 */
ISR(WDT_vect)
{
  Task& T = ts.currentTask();

  digitalWrite(13, HIGH);
  EEPROM.write(0, (byte)T.getId());
  EEPROM.write(1, (byte)T.getControlPoint());
  digitalWrite(13, LOW);
}

/**
 * Standard arduino setup routine
 */
void setup() {
  
  Serial.begin(115200);

  randomSeed(analogRead(0)+analogRead(5));
  
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW); 
  
 
  Serial.println("WDT heartbeat test");
  Serial.print("Last task before reset="); Serial.println(EEPROM.read(0));
  Serial.print("Last control point before reset="); Serial.println(EEPROM.read(1));
  
  delay(2000);

  tHB.enableDelayed();
}

/**
 * Not much is left for the loop()
 */
void loop() {
  ts.execute();
}