constexpr uint8_t MAX_STATES {4};
constexpr uint8_t BIT_MASK {0x4};
// Class/struct definitions
class Timer {
public:
void start() { timeStamp = millis(); }
bool operator()(const uint32_t duration) { return (millis() - timeStamp >= duration) ? true : false; }
private:
uint32_t timeStamp {0};
};
namespace TL {
struct Control {
const uint16_t duration[MAX_STATES];
const uint8_t ledPin[3];
const uint8_t mask[MAX_STATES];
};
enum class Phase : uint8_t { red, redYellow, green, yellow, wait }; // Definition of TLPhase
Phase &operator++(Phase &phase) {
return phase = (phase > Phase::green) ? Phase::red : static_cast<Phase>(static_cast<uint8_t>(phase) + 1);
};
class Device {
public:
Device(Timer &timer_, const Control &ctrl_, TL::Phase switchLight = TL::Phase::red) : timer {timer_}, ctrl {ctrl_} {}
void begin() {
for (auto p : ctrl.ledPin) { pinMode(p, OUTPUT); }
}
void switchLight() {
timer.start();
idx = static_cast<uint8_t>(pNow);
pNext = ++pNow;
pNow = Phase::wait;
uint8_t i {0};
for (auto p : ctrl.ledPin) {
((ctrl.mask[idx] << i) & BIT_MASK) ? digitalWrite(p, HIGH) : digitalWrite(p, LOW);
++i;
}
}
void check() {
if (timer(ctrl.duration[idx]) == true) { pNow = pNext; }
}
Phase phase() const { return pNow; }
private:
Timer &timer;
const Control &ctrl;
Phase pNow;
Phase pNext;
uint8_t idx;
};
} // namespace TL
//
// Global variables, objects
//
Timer timer;
TL::Control tlCtrl {
{15000, 3000, 15000, 3000}, // Length of the light phase in milliseconds
{6, 5, 4}, // Pins to which the LEDs are connected
{4, 6, 1, 2} // Bit pattern for switching the LEDs
};
TL::Device tLight {timer, tlCtrl};
//
// Function(s)
//
void fstm(TL::Device &tl) {
switch (tl.phase()) {
case TL::Phase::red: [[fallthrough]];
case TL::Phase::redYellow: [[fallthrough]];
case TL::Phase::green: [[fallthrough]];
case TL::Phase::yellow: tl.switchLight(); break;
case TL::Phase::wait: tl.check(); break;
}
}
//
// Main Program
//
void setup() { tLight.begin(); }
void loop() { fstm(tLight); }
red
red-yellow
yellow
green
15 sec
3 sec
3 sec
15 sec