|
#include <stdio.h> |
|
#include <assert.h> |
|
#include <vector> |
|
#include <functional> |
|
|
|
// Scenario: a button is connected to an input pin, |
|
// and it toggles an output pin, connect to an output |
|
// pin on and off. So when button is pressed, lamp |
|
// goes on. Then the button is released, and the lamp |
|
// stays on. Not until we press button again, does |
|
// the lamp turn off. When the button is released, |
|
// we are back in initial state (no button pressed, |
|
// lamp off). |
|
|
|
// This behaviour is nicely captured by two devices: |
|
// One for the button (states released and pressed), |
|
// One for the lamp (state on and off). |
|
// They communicate via a signal "toggleButton", |
|
// which is published when the button is pressed |
|
// (but not released) |
|
|
|
struct Signals { |
|
enum { |
|
PIN0_HIGH, |
|
PIN0_LOW, |
|
PIN1_HIGH, |
|
PIN1_LOW, |
|
TOGGLE |
|
}; |
|
}; |
|
|
|
typedef std::function<void(int)> PublishCallback; |
|
|
|
struct Button { |
|
enum { |
|
RELEASED, |
|
PUSHED |
|
}; |
|
int state; |
|
Button(PublishCallback publish) { |
|
state = RELEASED; |
|
_publish = publish; |
|
} |
|
void handleSignal(int signal) { |
|
switch(state) { |
|
case RELEASED: |
|
switch(signal) { |
|
case Signals::PIN0_HIGH: |
|
_publish(Signals::TOGGLE); |
|
state = PUSHED; |
|
break; |
|
default: |
|
break; |
|
} |
|
break; |
|
case PUSHED: |
|
switch(signal) { |
|
case Signals::PIN0_LOW: |
|
state = RELEASED; |
|
break; |
|
default: |
|
break; |
|
} |
|
break; |
|
} |
|
} |
|
private: |
|
PublishCallback _publish; |
|
}; |
|
|
|
void testButton() { |
|
// Apart from changing it's own state, each |
|
// device needs to be able to publish signals. |
|
// It does that by calling publish(signal), |
|
// a callback it gets in its constructor. |
|
// In this test, we fake it. |
|
std::vector<int> published_signals; |
|
PublishCallback fakePublish = (PublishCallback)([&](int signal) { published_signals.push_back(signal); }); |
|
|
|
// Test button behaviour |
|
Button button(fakePublish); |
|
|
|
// It starts in released state |
|
assert(button.state == Button::RELEASED); |
|
|
|
// When pin 0 is high, it means button has |
|
// been pushed as pin 0s circuit is shortcut |
|
button.handleSignal(Signals::PIN0_HIGH); |
|
|
|
// When the button goes down, the toggle signal |
|
// is emitted |
|
assert(published_signals.at(0) == Signals::TOGGLE); |
|
|
|
// .. and we check that the button switches |
|
// state appropriately |
|
assert(button.state == Button::PUSHED); |
|
|
|
// Just check that it does not react to |
|
// wrong pin |
|
button.handleSignal(Signals::PIN1_LOW); |
|
assert(button.state == Button::PUSHED); |
|
|
|
// Verify that button goes back to initial released |
|
// state when pin goes low again |
|
button.handleSignal(Signals::PIN0_LOW); |
|
assert(button.state == Button::RELEASED); |
|
|
|
// .. and that no more signal has been emitted |
|
assert(published_signals.size() == 1); |
|
} |
|
|
|
int main() |
|
{ |
|
testButton(); |
|
return 0; |
|
} |