#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, MATRIX, }; class Mode { private: struct Timer { millis_t interval; millis_t last; }; Display &_display; bool dirty = true; Timer timers[2] = { {0, 0}, {0, 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}; time_t epoch = 0; virtual void tick(uint8_t index, millis_t dt) {}; virtual void step(microseconds_t dt) {}; virtual void draw(Display &display) {}; void timer(uint8_t index, millis_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 dt) { Serial.print("[MODE] realtime\n"); realtime(); Serial.print("[MODE] handleTimers\n"); handleTimers(); Serial.print("[MODE] step\n"); step(dt); if (dirty) { dirty = false; Serial.print("[MODE] draw\n"); draw(_display); } } private: void realtime() { 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; } } void handleTimers() { millis_t ms = millis(); for (Timer *timer = timers; timer < timers + sizeof(timers); timer++) { if (timer->interval > 0) { millis_t dt = ms - timer->last; if (dt >= timer->interval) { timer->last = ms; tick(timer - timers, dt); } } } } }; #endif