Skip to content

Combined efforts on AVR mocks #117

New issue

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

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

Already on GitHub? Sign in 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