Skip to content

Combined efforts on AVR mocks #117

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Proper `ostream operator <<` for `nullptr`
- Proper comparison operations fro `nullptr`
- Mocks for avr/sleep.h and avr/wdt.h
- Definitions for ISR and ADCSRA

### Changed
- `Compare.h` heavily refactored to use a smallish macro
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
compile:
libraries: ~
platforms:
- uno
- leonardo

unittest:
libraries: ~
platforms:
- uno
- leonardo
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <avr/sleep.h>

#define BUTTON_INT_PIN 2

void setup() {
Serial.begin(115200);
Serial.println("start");
delay(200);
pinMode(BUTTON_INT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_INT_PIN), isrButtonTrigger, FALLING);
}

void loop() {
// sleep unti an interrupt occurs
sleep_enable(); // enables the sleep bit, a safety pin
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_cpu(); // here the device is actually put to sleep
sleep_disable(); // disables the sleep bit, a safety pin

Serial.println("interrupt");
delay(200);
}

void isrButtonTrigger() {
// nothing to do, wakes up the CPU
}

11 changes: 11 additions & 0 deletions SampleProjects/DoSomething/examples/AvrWdtReset/.arduino-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
compile:
libraries: ~
platforms:
- uno
- leonardo

unittest:
libraries: ~
platforms:
- uno
- leonardo
29 changes: 29 additions & 0 deletions SampleProjects/DoSomething/examples/AvrWdtReset/AvrWdtReset.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <avr/wdt.h>

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);

wdt_enable(WDTO_4S);
// First timeout executes interrupt, second does reset.
// So first LED 4s off
// then LED 4s on
// then reset CPU and start again
WDTCSR |= (1 << WDIE);
}

void loop() {
// the program is alive...for now.
wdt_reset();

while (1)
; // do nothing. the program will lockup here.

// Can not get here
}

ISR (WDT_vect) {
// WDIE & WDIF is cleared in hardware upon entering this ISR
digitalWrite(LED_BUILTIN, HIGH);
}

10 changes: 10 additions & 0 deletions SampleProjects/TestSomething/test/adc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <ArduinoUnitTests.h>
#include <Arduino.h>

unittest(check_ADCSRA_read_write) {
ADCSRA = 123;

assertEqual(123, ADCSRA);
}

unittest_main()
7 changes: 6 additions & 1 deletion SampleProjects/TestSomething/test/interrupts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ unittest(interrupt_attachment) {
assertFalse(state->interrupt[0].attached);
}


// Just check if declaration compiles.
// WDT_vect defines the interrupt of the watchdog timer
// if configured accordinly.
// See avr/interrupt.h
ISR (WDT_vect) {
}

unittest_main()
65 changes: 65 additions & 0 deletions SampleProjects/TestSomething/test/sleep.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <ArduinoUnitTests.h>
#include <avr/sleep.h>

GodmodeState* state = GODMODE();

unittest(sleep_enable) {
state->reset();
assertFalse(state->sleep.sleep_enable);
assertEqual(0, state->sleep.sleep_enable_count);

sleep_enable();

assertTrue(state->sleep.sleep_enable);
assertEqual(1, state->sleep.sleep_enable_count);
}

unittest(sleep_disable) {
state->reset();
assertEqual(0, state->sleep.sleep_disable_count);

sleep_disable();

assertFalse(state->sleep.sleep_enable);
assertEqual(1, state->sleep.sleep_disable_count);
}

unittest(set_sleep_mode) {
state->reset();
assertEqual(0, state->sleep.sleep_mode);

set_sleep_mode(SLEEP_MODE_PWR_DOWN);

assertEqual(SLEEP_MODE_PWR_DOWN, state->sleep.sleep_mode);
}

unittest(sleep_bod_disable) {
state->reset();
assertEqual(0, state->sleep.sleep_bod_disable_count);

sleep_bod_disable();

assertEqual(1, state->sleep.sleep_bod_disable_count);
}

unittest(sleep_cpu) {
state->reset();
assertEqual(0, state->sleep.sleep_cpu_count);

sleep_cpu();

assertEqual(1, state->sleep.sleep_cpu_count);
}

unittest(sleep_mode) {
state->reset();
assertEqual(0, state->sleep.sleep_mode_count);

sleep_mode();

assertEqual(1, state->sleep.sleep_mode_count);
assertEqual(1, state->sleep.sleep_enable_count);
assertEqual(1, state->sleep.sleep_disable_count);
}

unittest_main()
41 changes: 41 additions & 0 deletions SampleProjects/TestSomething/test/wdt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <ArduinoUnitTests.h>
#include <avr/wdt.h>

GodmodeState* state = GODMODE();

unittest(taskWdtEnable_checkTimeout) {
state->reset();
assertEqual(0, state->wdt.timeout);

wdt_enable(WDTO_1S);

assertTrue(state->wdt.wdt_enable);
assertEqual(WDTO_1S, state->wdt.timeout);
assertEqual(1, state->wdt.wdt_enable_count);
}

unittest(taskWdtEnableDisable) {
state->reset();
assertEqual(0, state->wdt.wdt_enable_count);

wdt_enable(WDTO_1S);

assertTrue(state->wdt.wdt_enable);
assertEqual(1, state->wdt.wdt_enable_count);

wdt_disable();

assertFalse(state->wdt.wdt_enable);
assertEqual(1, state->wdt.wdt_enable_count);
}

unittest(wdt_reset) {
state->reset();
assertEqual(0, state->wdt.wdt_reset_count);

wdt_reset();

assertEqual(1, state->wdt.wdt_reset_count);
}

unittest_main()
3 changes: 3 additions & 0 deletions cpp/arduino/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ typedef uint8_t byte;
// Math and Trig
#include "AvrMath.h"

#include "AvrAdc.h"
#include "avr/interrupt.h"

#include "Godmode.h"


Expand Down
4 changes: 4 additions & 0 deletions cpp/arduino/AvrAdc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include "AvrAdc.h"

// mock storage to allow access to ADCSRA
unsigned char sfr_store;
9 changes: 9 additions & 0 deletions cpp/arduino/AvrAdc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

// ADCSRA is defined in the CPU specific header files
// like iom328p.h.
// It is liked to _SFR_MEM8 what does not exists in the test environment.
// Therefore we define _SFR_MEM8 here and provide it a storage
// location so that the test code can read/write on it.
extern unsigned char sfr_store;
#define _SFR_MEM8(mem_addr) sfr_store
42 changes: 41 additions & 1 deletion cpp/arduino/Godmode.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ class GodmodeState {

static GodmodeState* instance;

struct SleepDef {
bool sleep_enable = false;
unsigned int sleep_enable_count = 0;
unsigned int sleep_disable_count = 0;
unsigned char sleep_mode = 0;
unsigned int sleep_cpu_count = 0;
unsigned int sleep_mode_count = 0;
unsigned int sleep_bod_disable_count = 0;
};

struct WdtDef {
bool wdt_enable = false;
unsigned char timeout = 0;
unsigned int wdt_enable_count = 0;
unsigned int wdt_disable_count = 0;
unsigned int wdt_reset_count = 0;
};

public:
unsigned long micros;
unsigned long seed;
Expand All @@ -54,6 +72,8 @@ class GodmodeState {
struct PortDef serialPort[NUM_SERIAL_PORTS];
struct InterruptDef interrupt[MOCK_PINS_COUNT]; // not sure how to get actual number
struct PortDef spi;
struct SleepDef sleep;
struct WdtDef wdt;

void resetPins() {
for (int i = 0; i < MOCK_PINS_COUNT; ++i) {
Expand Down Expand Up @@ -87,12 +107,32 @@ class GodmodeState {
spi.readDelayMicros = 0;
}

void resetSleep() {
sleep.sleep_enable = false;
sleep.sleep_enable_count = 0;
sleep.sleep_disable_count = 0;
sleep.sleep_mode = 0;
sleep.sleep_cpu_count = 0;
sleep.sleep_mode_count = 0;
sleep.sleep_bod_disable_count = 0;
}

void resetWdt() {
wdt.wdt_enable = false;
wdt.timeout = 0;
wdt.wdt_enable_count = 0;
wdt.wdt_disable_count = 0;
wdt.wdt_reset_count = 0;
}

void reset() {
resetClock();
resetPins();
resetInterrupts();
resetPorts();
resetSPI();
resetSleep();
resetWdt();
seed = 1;
}

Expand Down Expand Up @@ -132,7 +172,7 @@ int analogRead(uint8_t);
void analogWrite(uint8_t, int);
#define analogReadResolution(...) _NOP()
#define analogWriteResolution(...) _NOP()
void attachInterrupt(uint8_t interrupt, void ISR(void), uint8_t mode);
void attachInterrupt(uint8_t interrupt, void isr(void), uint8_t mode);
void detachInterrupt(uint8_t interrupt);

// TODO: issue #26 to track the commanded state here
Expand Down
15 changes: 15 additions & 0 deletions cpp/arduino/avr/interrupt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
This header file defines the macros required for the production
code for AVR CPUs to declare ISRs in the test environment.
See for more details
https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
*/
#pragma once

// Allows the production code to define an ISR method.
// These definitions come from the original avr/interrupt.h file
// https://www.nongnu.org/avr-libc/user-manual/interrupt_8h_source.html
#define _VECTOR(N) __vector_ ## N
#define ISR(vector, ...) \
extern "C" void vector (void) __VA_ARGS__; \
void vector (void)
42 changes: 42 additions & 0 deletions cpp/arduino/avr/sleep.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
This header file defines the functionality to put AVR CPUs to sleep mode.
For details see
https://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html
*/
#pragma once

#include <Godmode.h>

void sleep_enable() {
GodmodeState* godmode = GODMODE();
godmode->sleep.sleep_enable = true;
godmode->sleep.sleep_enable_count++;
}

void sleep_disable() {
GodmodeState* godmode = GODMODE();
godmode->sleep.sleep_enable = false;
godmode->sleep.sleep_disable_count++;
}

void set_sleep_mode(unsigned char mode) {
GodmodeState* godmode = GODMODE();
godmode->sleep.sleep_mode = mode;
}

void sleep_bod_disable() {
GodmodeState* godmode = GODMODE();
godmode->sleep.sleep_bod_disable_count++;
}

void sleep_cpu() {
GodmodeState* godmode = GODMODE();
godmode->sleep.sleep_cpu_count++;
}

void sleep_mode() {
GodmodeState* godmode = GODMODE();
sleep_enable();
godmode->sleep.sleep_mode_count++;
sleep_disable();
}
Loading