Skip to content

Commit bd37109

Browse files
committed
Use singleton GodmodeState, add pinhistory with timestamp
1 parent ac1f761 commit bd37109

File tree

4 files changed

+96
-68
lines changed

4 files changed

+96
-68
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1818
* Construction of `MockEventQueue` now includes a constructor argument for the time-fetching function
1919
* Construction of `PinHistory` now includes a constructor argument for the time-fetching function
2020
* `PinHistory` can now return an array of timestamps for its events
21+
* `GodmodeState` is now a singleton pattern, which is necessary to support the globality of Arduino functions
22+
* `GodmodeState` now uses timestamped PinHistory for Analog and Digital
2123

2224
### Deprecated
2325

SampleProjects/TestSomething/test/godmode.cpp

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#include <ArduinoUnitTests.h>
22
#include <Arduino.h>
3+
#include "fibonacciClock.h"
34

45
GodmodeState* state = GODMODE();
56

6-
unittest_setup()
7-
{
7+
unittest_setup() {
8+
resetFibClock();
89
state->reset();
910
}
1011

11-
unittest(millis_micros_and_delay)
12-
{
12+
unittest(millis_micros_and_delay) {
1313
assertEqual(0, millis());
1414
assertEqual(0, micros());
1515
delay(3);
@@ -20,8 +20,7 @@ unittest(millis_micros_and_delay)
2020
assertEqual(14000, micros());
2121
}
2222

23-
unittest(random)
24-
{
23+
unittest(random) {
2524
randomSeed(1);
2625
assertEqual(state->seed, 1);
2726

@@ -37,8 +36,7 @@ unittest(random)
3736
assertEqual(state->seed, 4294967282);
3837
}
3938

40-
unittest(pins)
41-
{
39+
unittest(pins) {
4240
pinMode(1, OUTPUT); // this is a no-op in unit tests. it's just here to prove compilation
4341
digitalWrite(1, HIGH);
4442
assertEqual(HIGH, state->digitalPin[1]);
@@ -64,8 +62,7 @@ unittest(pins)
6462
assertEqual(56, analogRead(1));
6563
}
6664

67-
unittest(pin_read_history)
68-
{
65+
unittest(pin_read_history) {
6966
int future[6] = {33, 22, 55, 11, 44, 66};
7067
state->analogPin[1].fromArray(future, 6);
7168
for (int i = 0; i < 6; ++i)
@@ -88,20 +85,20 @@ unittest(pin_read_history)
8885
}
8986
}
9087

91-
unittest(pin_write_history)
92-
{
88+
unittest(digital_pin_write_history_with_timing) {
9389
int numMoved;
90+
bool expectedD[6] = {LOW, HIGH, LOW, LOW, HIGH, HIGH};
91+
bool actualD[6];
92+
unsigned long expectedT[6] = {0, 1, 1, 2, 3, 5};
93+
unsigned long actualT[6];
9494

95-
// history for digital pin
96-
digitalWrite(1, HIGH);
97-
digitalWrite(1, LOW);
98-
digitalWrite(1, LOW);
99-
digitalWrite(1, HIGH);
100-
digitalWrite(1, HIGH);
95+
// history for digital pin. start from 1 since LOW is the initial value
96+
for (int i = 1; i < 6; ++i) {
97+
state->micros = fibMicros();
98+
digitalWrite(1, expectedD[i]);
99+
}
101100

102101
assertEqual(6, state->digitalPin[1].historySize());
103-
bool expectedD[6] = {LOW, HIGH, LOW, LOW, HIGH, HIGH};
104-
bool actualD[6];
105102
numMoved = state->digitalPin[1].toArray(actualD, 6);
106103
assertEqual(6, numMoved);
107104
// assert non-destructive
@@ -113,6 +110,19 @@ unittest(pin_write_history)
113110
assertEqual(expectedD[i], actualD[i]);
114111
}
115112

113+
numMoved = state->digitalPin[1].toTimestampArray(actualT, 6);
114+
assertEqual(6, numMoved);
115+
for (int i = 0; i < numMoved; ++i)
116+
{
117+
assertEqual(expectedT[i], actualT[i]);
118+
}
119+
}
120+
121+
unittest(analog_pin_write_history) {
122+
int numMoved;
123+
int expectedA[6] = {0, 11, 22, 33, 44, 55};
124+
int actualA[6];
125+
116126
// history for analog pin
117127
analogWrite(1, 11);
118128
analogWrite(1, 22);
@@ -121,8 +131,7 @@ unittest(pin_write_history)
121131
analogWrite(1, 55);
122132

123133
assertEqual(6, state->analogPin[1].historySize());
124-
int expectedA[6] = {0, 11, 22, 33, 44, 55};
125-
int actualA[6];
134+
126135
numMoved = state->analogPin[1].toArray(actualA, 6);
127136
assertEqual(6, numMoved);
128137
// assert non-destructive
@@ -133,7 +142,9 @@ unittest(pin_write_history)
133142
{
134143
assertEqual(expectedA[i], actualA[i]);
135144
}
145+
}
136146

147+
unittest(ascii_pin_write_history) {
137148
// digitial history as serial data, big-endian
138149
bool binaryAscii[24] = {
139150
0, 1, 0, 1, 1, 0, 0, 1,
@@ -207,8 +218,7 @@ unittest(spi) {
207218
}
208219
}
209220

210-
unittest(does_nothing_if_no_data)
211-
{
221+
unittest(does_nothing_if_no_data) {
212222
int myPin = 3;
213223
state->serialPort[0].dataIn = "";
214224
state->serialPort[0].dataOut = "";
@@ -218,8 +228,7 @@ unittest(spi) {
218228
assertEqual("", state->serialPort[0].dataOut);
219229
}
220230

221-
unittest(keeps_pin_low_and_acks)
222-
{
231+
unittest(keeps_pin_low_and_acks) {
223232
int myPin = 3;
224233
state->serialPort[0].dataIn = "0";
225234
state->serialPort[0].dataOut = "";
@@ -230,8 +239,7 @@ unittest(spi) {
230239
assertEqual("Ack 3 0", state->serialPort[0].dataOut);
231240
}
232241

233-
unittest(flips_pin_high_and_acks)
234-
{
242+
unittest(flips_pin_high_and_acks) {
235243
int myPin = 3;
236244
state->serialPort[0].dataIn = "1";
237245
state->serialPort[0].dataOut = "";
@@ -242,8 +250,7 @@ unittest(spi) {
242250
assertEqual("Ack 3 1", state->serialPort[0].dataOut);
243251
}
244252

245-
unittest(two_flips)
246-
{
253+
unittest(two_flips) {
247254
int myPin = 3;
248255
state->serialPort[0].dataIn = "10junk";
249256
state->serialPort[0].dataOut = "";

cpp/arduino/Godmode.cpp

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,45 @@
22
#include "HardwareSerial.h"
33
#include "SPI.h"
44

5-
GodmodeState godmode = GodmodeState();
6-
75
GodmodeState* GODMODE() {
8-
return &godmode;
6+
return GodmodeState::getInstance();
7+
}
8+
9+
GodmodeState* GodmodeState::instance = nullptr;
10+
11+
GodmodeState* GodmodeState::getInstance()
12+
{
13+
if (instance == nullptr)
14+
{
15+
instance = new GodmodeState();
16+
for (int i = 0; i < MOCK_PINS_COUNT; ++i) {
17+
instance->digitalPin[i].setMicrosRetriever(&GodmodeState::getMicros);
18+
instance->analogPin[i].setMicrosRetriever(&GodmodeState::getMicros);
19+
}
20+
}
21+
22+
return instance;
923
}
1024

1125
unsigned long millis() {
12-
GodmodeState* godmode = GODMODE();
13-
return godmode->micros / 1000;
26+
return GODMODE()->micros / 1000;
1427
}
1528

1629
unsigned long micros() {
17-
GodmodeState* godmode = GODMODE();
18-
return godmode->micros;
30+
return GODMODE()->micros;
1931
}
2032

2133
void delay(unsigned long millis) {
22-
GodmodeState* godmode = GODMODE();
23-
godmode->micros += millis * 1000;
34+
GODMODE()->micros += millis * 1000;
2435
}
2536

2637
void delayMicroseconds(unsigned long micros) {
27-
GodmodeState* godmode = GODMODE();
28-
godmode->micros += micros;
38+
GODMODE()->micros += micros;
2939
}
3040

31-
3241
void randomSeed(unsigned long seed)
3342
{
34-
GodmodeState* godmode = GODMODE();
35-
godmode->seed = seed;
43+
GODMODE()->seed = seed;
3644
}
3745

3846
long random(long vmax)
@@ -81,16 +89,16 @@ void detachInterrupt(uint8_t interrupt) {
8189

8290
// Serial ports
8391
#if defined(HAVE_HWSERIAL0)
84-
HardwareSerial Serial(&godmode.serialPort[0].dataIn, &godmode.serialPort[0].dataOut, &godmode.serialPort[0].readDelayMicros);
92+
HardwareSerial Serial(&GODMODE()->serialPort[0].dataIn, &GODMODE()->serialPort[0].dataOut, &GODMODE()->serialPort[0].readDelayMicros);
8593
#endif
8694
#if defined(HAVE_HWSERIAL1)
87-
HardwareSerial Serial1(&godmode.serialPort[1].dataIn, &godmode.serialPort[1].dataOut, &godmode.serialPort[1].readDelayMicros);
95+
HardwareSerial Serial1(&GODMODE()->serialPort[1].dataIn, &GODMODE()->serialPort[1].dataOut, &GODMODE()->serialPort[1].readDelayMicros);
8896
#endif
8997
#if defined(HAVE_HWSERIAL2)
90-
HardwareSerial Serial2(&godmode.serialPort[2].dataIn, &godmode.serialPort[2].dataOut, &godmode.serialPort[2].readDelayMicros);
98+
HardwareSerial Serial2(&GODMODE()->serialPort[2].dataIn, &GODMODE()->serialPort[2].dataOut, &GODMODE()->serialPort[2].readDelayMicros);
9199
#endif
92100
#if defined(HAVE_HWSERIAL3)
93-
HardwareSerial Serial3(&godmode.serialPort[3].dataIn, &godmode.serialPort[3].dataOut, &godmode.serialPort[3].readDelayMicros);
101+
HardwareSerial Serial3(&GODMODE()->serialPort[3].dataIn, &GODMODE()->serialPort[3].dataOut, &GODMODE()->serialPort[3].readDelayMicros);
94102
#endif
95103

96104
template <typename T>
@@ -100,4 +108,4 @@ inline std::ostream& operator << ( std::ostream& out, const PinHistory<T>& ph )
100108
}
101109

102110
// defined in SPI.h
103-
SPIClass SPI = SPIClass(&godmode.spi.dataIn, &godmode.spi.dataOut);
111+
SPIClass SPI = SPIClass(&GODMODE()->spi.dataIn, &GODMODE()->spi.dataOut);

cpp/arduino/Godmode.h

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ void delayMicroseconds(unsigned long micros);
1616
unsigned long millis();
1717
unsigned long micros();
1818

19-
2019
#define MOCK_PINS_COUNT 256
2120

2221
#if defined(UBRR3H)
@@ -32,16 +31,19 @@ unsigned long micros();
3231
#endif
3332

3433
class GodmodeState {
35-
struct PortDef {
36-
String dataIn;
37-
String dataOut;
38-
unsigned long readDelayMicros;
39-
};
34+
private:
35+
struct PortDef {
36+
String dataIn;
37+
String dataOut;
38+
unsigned long readDelayMicros;
39+
};
40+
41+
struct InterruptDef {
42+
bool attached;
43+
uint8_t mode;
44+
};
4045

41-
struct InterruptDef {
42-
bool attached;
43-
uint8_t mode;
44-
};
46+
static GodmodeState* instance;
4547

4648
public:
4749
unsigned long micros;
@@ -98,8 +100,24 @@ class GodmodeState {
98100
return NUM_SERIAL_PORTS;
99101
}
100102

101-
GodmodeState()
102-
{
103+
// Using this for anything other than unit testing arduino_ci itself
104+
// is unsupported at the moment
105+
void overrideClockTruth(unsigned long (*getMicros)(void)) {
106+
}
107+
108+
// singleton pattern
109+
static GodmodeState* getInstance();
110+
111+
static unsigned long getMicros() {
112+
return instance->micros;
113+
}
114+
115+
// C++ 11, declare as public for better compiler error messages
116+
GodmodeState(GodmodeState const&) = delete;
117+
void operator=(GodmodeState const&) = delete;
118+
119+
private:
120+
GodmodeState() {
103121
reset();
104122
}
105123
};
@@ -123,10 +141,3 @@ inline void noTone(uint8_t _pin) {}
123141

124142

125143
GodmodeState* GODMODE();
126-
127-
// defined here to break a circular dependency on GODMODE
128-
// reasons: https://stackoverflow.com/a/1639821/2063546
129-
template <typename T>
130-
bool MockEventQueue<T>::push(const T& v) {
131-
return pushEvent(v, GODMODE()->micros);
132-
}

0 commit comments

Comments
 (0)