#ifndef MODE_H #define MODE_H #include "BASICS.h" #include "display/Display.h" enum ModeId { NONE, BORDER, CLOCK, GAME_OF_LIFE_BLACK_WHITE, GAME_OF_LIFE_GRAYSCALE, GAME_OF_LIFE_COLOR_FADE, GAME_OF_LIFE_RANDOM_COLOR, PONG, SPACE_INVADERS, NEW_YEAR, STARFIELD, }; class Mode { private: struct Timer { milliseconds_t interval; milliseconds_t last; }; Display &_display; bool dirty = true; Timer timers[2] = { {0, 0}, {0, 0}, }; int8_t lastSecond = -1; milliseconds_t lastSecondChange_Milliseconds = 0; protected: const uint8_t width; const uint8_t height; bool realtimeOK = false; bool realtimeChanged = false; tm now = {0, 0, 0, 0, 0, 0, 0, 0, 0}; milliseconds_t realtimeMilliseconds; time_t epoch = 0; virtual void tick(uint8_t index, milliseconds_t milliseconds) {}; virtual void step(microseconds_t microseconds) {}; virtual void draw(Display &display) {}; void timer(uint8_t index, milliseconds_t interval) { if (index >= countof(timers)) { return; } timers[index].interval = interval; timers[index].last = millis(); } void markDirty() { dirty = true; } public: explicit Mode(Display &display) : _display(display), width(display.width), height(display.height) { // nothing } virtual ~Mode() = default; virtual const char *getName() = 0; void loop(microseconds_t micros) { handleRealtime(); handleTimers(); step(micros); if (dirty) { dirty = false; draw(_display); } } private: void handleRealtime() { time_t tmp; time(&tmp); realtimeOK = tmp > 1600000000; if (realtimeOK) { realtimeChanged = epoch != tmp; if (realtimeChanged) { epoch = tmp; localtime_r(&tmp, &now); now.tm_year += 1900; now.tm_mon += 1; } } else { realtimeChanged = false; } if (lastSecond < 0 || lastSecond != now.tm_sec) { lastSecond = (int8_t) now.tm_sec; lastSecondChange_Milliseconds = millis(); } realtimeMilliseconds = millis() - lastSecondChange_Milliseconds; } void handleTimers() { milliseconds_t ms = millis(); for (Timer *timer = timers; timer < timers + countof(timers); timer++) { if (timer->interval > 0) { milliseconds_t milliseconds = ms - timer->last; if (milliseconds >= timer->interval) { timer->last = ms; tick(timer - timers, milliseconds); } } } } }; #endif