Skip to content

Commit f08aa48

Browse files
authored
Merge pull request #115 from PRosenb/mock_for_sleep_and_wdt
Mock for sleep and wdt
2 parents c5f5732 + 2600fb5 commit f08aa48

File tree

16 files changed

+354
-2
lines changed

16 files changed

+354
-2
lines changed

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
4343
### Added
4444
- Proper `ostream operator <<` for `nullptr`
4545
- Proper comparison operations fro `nullptr`
46+
- Mocks for avr/sleep.h and avr/wdt.h
47+
- Definitions for ISR and ADCSRA
4648

4749
### Changed
4850
- `Compare.h` heavily refactored to use a smallish macro
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
compile:
2+
libraries: ~
3+
platforms:
4+
- uno
5+
- leonardo
6+
7+
unittest:
8+
libraries: ~
9+
platforms:
10+
- uno
11+
- leonardo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <avr/sleep.h>
2+
3+
#define BUTTON_INT_PIN 2
4+
5+
void setup() {
6+
Serial.begin(115200);
7+
Serial.println("start");
8+
delay(200);
9+
pinMode(BUTTON_INT_PIN, INPUT_PULLUP);
10+
attachInterrupt(digitalPinToInterrupt(BUTTON_INT_PIN), isrButtonTrigger, FALLING);
11+
}
12+
13+
void loop() {
14+
// sleep unti an interrupt occurs
15+
sleep_enable(); // enables the sleep bit, a safety pin
16+
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
17+
sleep_cpu(); // here the device is actually put to sleep
18+
sleep_disable(); // disables the sleep bit, a safety pin
19+
20+
Serial.println("interrupt");
21+
delay(200);
22+
}
23+
24+
void isrButtonTrigger() {
25+
// nothing to do, wakes up the CPU
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
compile:
2+
libraries: ~
3+
platforms:
4+
- uno
5+
- leonardo
6+
7+
unittest:
8+
libraries: ~
9+
platforms:
10+
- uno
11+
- leonardo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <avr/wdt.h>
2+
3+
void setup() {
4+
pinMode(LED_BUILTIN, OUTPUT);
5+
digitalWrite(LED_BUILTIN, LOW);
6+
7+
wdt_enable(WDTO_4S);
8+
// First timeout executes interrupt, second does reset.
9+
// So first LED 4s off
10+
// then LED 4s on
11+
// then reset CPU and start again
12+
WDTCSR |= (1 << WDIE);
13+
}
14+
15+
void loop() {
16+
// the program is alive...for now.
17+
wdt_reset();
18+
19+
while (1)
20+
; // do nothing. the program will lockup here.
21+
22+
// Can not get here
23+
}
24+
25+
ISR (WDT_vect) {
26+
// WDIE & WDIF is cleared in hardware upon entering this ISR
27+
digitalWrite(LED_BUILTIN, HIGH);
28+
}
29+

Diff for: SampleProjects/TestSomething/test/adc.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <ArduinoUnitTests.h>
2+
#include <Arduino.h>
3+
4+
unittest(check_ADCSRA_read_write) {
5+
ADCSRA = 123;
6+
7+
assertEqual(123, ADCSRA);
8+
}
9+
10+
unittest_main()

Diff for: SampleProjects/TestSomething/test/interrupts.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ unittest(interrupt_attachment) {
2323
assertFalse(state->interrupt[0].attached);
2424
}
2525

26-
26+
// Just check if declaration compiles.
27+
// WDT_vect defines the interrupt of the watchdog timer
28+
// if configured accordinly.
29+
// See avr/interrupt.h
30+
ISR (WDT_vect) {
31+
}
2732

2833
unittest_main()

Diff for: SampleProjects/TestSomething/test/sleep.cpp

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include <ArduinoUnitTests.h>
2+
#include <avr/sleep.h>
3+
4+
GodmodeState* state = GODMODE();
5+
6+
unittest(sleep_enable) {
7+
state->reset();
8+
assertFalse(state->sleep.sleep_enable);
9+
assertEqual(0, state->sleep.sleep_enable_count);
10+
11+
sleep_enable();
12+
13+
assertTrue(state->sleep.sleep_enable);
14+
assertEqual(1, state->sleep.sleep_enable_count);
15+
}
16+
17+
unittest(sleep_disable) {
18+
state->reset();
19+
assertEqual(0, state->sleep.sleep_disable_count);
20+
21+
sleep_disable();
22+
23+
assertFalse(state->sleep.sleep_enable);
24+
assertEqual(1, state->sleep.sleep_disable_count);
25+
}
26+
27+
unittest(set_sleep_mode) {
28+
state->reset();
29+
assertEqual(0, state->sleep.sleep_mode);
30+
31+
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
32+
33+
assertEqual(SLEEP_MODE_PWR_DOWN, state->sleep.sleep_mode);
34+
}
35+
36+
unittest(sleep_bod_disable) {
37+
state->reset();
38+
assertEqual(0, state->sleep.sleep_bod_disable_count);
39+
40+
sleep_bod_disable();
41+
42+
assertEqual(1, state->sleep.sleep_bod_disable_count);
43+
}
44+
45+
unittest(sleep_cpu) {
46+
state->reset();
47+
assertEqual(0, state->sleep.sleep_cpu_count);
48+
49+
sleep_cpu();
50+
51+
assertEqual(1, state->sleep.sleep_cpu_count);
52+
}
53+
54+
unittest(sleep_mode) {
55+
state->reset();
56+
assertEqual(0, state->sleep.sleep_mode_count);
57+
58+
sleep_mode();
59+
60+
assertEqual(1, state->sleep.sleep_mode_count);
61+
assertEqual(1, state->sleep.sleep_enable_count);
62+
assertEqual(1, state->sleep.sleep_disable_count);
63+
}
64+
65+
unittest_main()

Diff for: SampleProjects/TestSomething/test/wdt.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <ArduinoUnitTests.h>
2+
#include <avr/wdt.h>
3+
4+
GodmodeState* state = GODMODE();
5+
6+
unittest(taskWdtEnable_checkTimeout) {
7+
state->reset();
8+
assertEqual(0, state->wdt.timeout);
9+
10+
wdt_enable(WDTO_1S);
11+
12+
assertTrue(state->wdt.wdt_enable);
13+
assertEqual(WDTO_1S, state->wdt.timeout);
14+
assertEqual(1, state->wdt.wdt_enable_count);
15+
}
16+
17+
unittest(taskWdtEnableDisable) {
18+
state->reset();
19+
assertEqual(0, state->wdt.wdt_enable_count);
20+
21+
wdt_enable(WDTO_1S);
22+
23+
assertTrue(state->wdt.wdt_enable);
24+
assertEqual(1, state->wdt.wdt_enable_count);
25+
26+
wdt_disable();
27+
28+
assertFalse(state->wdt.wdt_enable);
29+
assertEqual(1, state->wdt.wdt_enable_count);
30+
}
31+
32+
unittest(wdt_reset) {
33+
state->reset();
34+
assertEqual(0, state->wdt.wdt_reset_count);
35+
36+
wdt_reset();
37+
38+
assertEqual(1, state->wdt.wdt_reset_count);
39+
}
40+
41+
unittest_main()

Diff for: cpp/arduino/Arduino.h

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ typedef uint8_t byte;
2424
// Math and Trig
2525
#include "AvrMath.h"
2626

27+
#include "AvrAdc.h"
28+
#include "avr/interrupt.h"
29+
2730
#include "Godmode.h"
2831

2932

Diff for: cpp/arduino/AvrAdc.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#include "AvrAdc.h"
2+
3+
// mock storage to allow access to ADCSRA
4+
unsigned char sfr_store;

Diff for: cpp/arduino/AvrAdc.h

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
// ADCSRA is defined in the CPU specific header files
4+
// like iom328p.h.
5+
// It is liked to _SFR_MEM8 what does not exists in the test environment.
6+
// Therefore we define _SFR_MEM8 here and provide it a storage
7+
// location so that the test code can read/write on it.
8+
extern unsigned char sfr_store;
9+
#define _SFR_MEM8(mem_addr) sfr_store

Diff for: cpp/arduino/Godmode.h

+41-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ class GodmodeState {
4545

4646
static GodmodeState* instance;
4747

48+
struct SleepDef {
49+
bool sleep_enable = false;
50+
unsigned int sleep_enable_count = 0;
51+
unsigned int sleep_disable_count = 0;
52+
unsigned char sleep_mode = 0;
53+
unsigned int sleep_cpu_count = 0;
54+
unsigned int sleep_mode_count = 0;
55+
unsigned int sleep_bod_disable_count = 0;
56+
};
57+
58+
struct WdtDef {
59+
bool wdt_enable = false;
60+
unsigned char timeout = 0;
61+
unsigned int wdt_enable_count = 0;
62+
unsigned int wdt_disable_count = 0;
63+
unsigned int wdt_reset_count = 0;
64+
};
65+
4866
public:
4967
unsigned long micros;
5068
unsigned long seed;
@@ -54,6 +72,8 @@ class GodmodeState {
5472
struct PortDef serialPort[NUM_SERIAL_PORTS];
5573
struct InterruptDef interrupt[MOCK_PINS_COUNT]; // not sure how to get actual number
5674
struct PortDef spi;
75+
struct SleepDef sleep;
76+
struct WdtDef wdt;
5777

5878
void resetPins() {
5979
for (int i = 0; i < MOCK_PINS_COUNT; ++i) {
@@ -87,12 +107,32 @@ class GodmodeState {
87107
spi.readDelayMicros = 0;
88108
}
89109

110+
void resetSleep() {
111+
sleep.sleep_enable = false;
112+
sleep.sleep_enable_count = 0;
113+
sleep.sleep_disable_count = 0;
114+
sleep.sleep_mode = 0;
115+
sleep.sleep_cpu_count = 0;
116+
sleep.sleep_mode_count = 0;
117+
sleep.sleep_bod_disable_count = 0;
118+
}
119+
120+
void resetWdt() {
121+
wdt.wdt_enable = false;
122+
wdt.timeout = 0;
123+
wdt.wdt_enable_count = 0;
124+
wdt.wdt_disable_count = 0;
125+
wdt.wdt_reset_count = 0;
126+
}
127+
90128
void reset() {
91129
resetClock();
92130
resetPins();
93131
resetInterrupts();
94132
resetPorts();
95133
resetSPI();
134+
resetSleep();
135+
resetWdt();
96136
seed = 1;
97137
}
98138

@@ -132,7 +172,7 @@ int analogRead(uint8_t);
132172
void analogWrite(uint8_t, int);
133173
#define analogReadResolution(...) _NOP()
134174
#define analogWriteResolution(...) _NOP()
135-
void attachInterrupt(uint8_t interrupt, void ISR(void), uint8_t mode);
175+
void attachInterrupt(uint8_t interrupt, void isr(void), uint8_t mode);
136176
void detachInterrupt(uint8_t interrupt);
137177

138178
// TODO: issue #26 to track the commanded state here

Diff for: cpp/arduino/avr/interrupt.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
This header file defines the macros required for the production
3+
code for AVR CPUs to declare ISRs in the test environment.
4+
See for more details
5+
https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
6+
*/
7+
#pragma once
8+
9+
// Allows the production code to define an ISR method.
10+
// These definitions come from the original avr/interrupt.h file
11+
// https://www.nongnu.org/avr-libc/user-manual/interrupt_8h_source.html
12+
#define _VECTOR(N) __vector_ ## N
13+
#define ISR(vector, ...) \
14+
extern "C" void vector (void) __VA_ARGS__; \
15+
void vector (void)

Diff for: cpp/arduino/avr/sleep.h

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
This header file defines the functionality to put AVR CPUs to sleep mode.
3+
For details see
4+
https://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html
5+
*/
6+
#pragma once
7+
8+
#include <Godmode.h>
9+
10+
void sleep_enable() {
11+
GodmodeState* godmode = GODMODE();
12+
godmode->sleep.sleep_enable = true;
13+
godmode->sleep.sleep_enable_count++;
14+
}
15+
16+
void sleep_disable() {
17+
GodmodeState* godmode = GODMODE();
18+
godmode->sleep.sleep_enable = false;
19+
godmode->sleep.sleep_disable_count++;
20+
}
21+
22+
void set_sleep_mode(unsigned char mode) {
23+
GodmodeState* godmode = GODMODE();
24+
godmode->sleep.sleep_mode = mode;
25+
}
26+
27+
void sleep_bod_disable() {
28+
GodmodeState* godmode = GODMODE();
29+
godmode->sleep.sleep_bod_disable_count++;
30+
}
31+
32+
void sleep_cpu() {
33+
GodmodeState* godmode = GODMODE();
34+
godmode->sleep.sleep_cpu_count++;
35+
}
36+
37+
void sleep_mode() {
38+
GodmodeState* godmode = GODMODE();
39+
sleep_enable();
40+
godmode->sleep.sleep_mode_count++;
41+
sleep_disable();
42+
}

0 commit comments

Comments
 (0)