diff --git a/platformio.ini b/platformio.ini index 889b5f2..9b00ef1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,7 @@ platform = espressif32 board = esp32dev framework = arduino lib_deps = https://github.com/adafruit/Adafruit_NeoPixel -build_flags = -D PROG_ALL=true +build_flags = -D ENABLE_ALL=true -D ENABLE_OTA=false ;upload_port = 10.0.0.120 ;upload_protocol = espota upload_port = /dev/ttyUSB0 diff --git a/src/main.cpp b/src/main.cpp index 6a60990..2306d1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,14 @@ #include + +#if ENABLE_OTA #include +#endif + #include "mode/Mode.h" #include "display/Display.h" #include -#if PROG_ALL +#if ENABLE_ALL #include "mode/GameOfLife/GameOfLife.h" #include "mode/Pong/Pong.h" @@ -18,7 +22,7 @@ enum ModeId { NONE, -#if PROG_ALL +#if ENABLE_ALL BORDER, CLOCK, GAME_OF_LIFE_BLACK_WHITE, @@ -41,7 +45,7 @@ ModeId currentModeId = NONE; microseconds_t lastMicros = 0; -Mode *mode = nullptr; +ModeBase *mode = nullptr; double speed = 1.0; @@ -107,6 +111,8 @@ void setup() { Serial.println("\n\n\nStartup!"); WiFi.begin("HappyNet", "1Grausame!Sackratte7"); + +#if ENABLE_OTA ArduinoOTA.onStart([]() { display.clear(); display.loop(); @@ -127,6 +133,7 @@ void setup() { display.loop(); }); ArduinoOTA.begin(); +#endif server.on("", web_index); server.on("/", web_index); @@ -144,7 +151,9 @@ void setup() { void setSpeed(double value); void loop() { +#if ENABLE_OTA ArduinoOTA.handle(); +#endif server.handleClient(); bool hasIp = (uint32_t) WiFi.localIP() != 0; if (!connected) { @@ -225,7 +234,7 @@ void loadNewMode() { switch (currentModeId) { case NONE: break; -#if PROG_ALL +#if ENABLE_ALL case BORDER: mode = new Border(&display); break; diff --git a/src/mode/Clock/Clock.cpp b/src/mode/Clock/Clock.cpp new file mode 100644 index 0000000..cb3d55b --- /dev/null +++ b/src/mode/Clock/Clock.cpp @@ -0,0 +1,4 @@ +#include "Clock.h" + +template<> +Clock *Mode::instance = nullptr; \ No newline at end of file diff --git a/src/mode/Clock/Clock.h b/src/mode/Clock/Clock.h index f97aace..d5ee527 100644 --- a/src/mode/Clock/Clock.h +++ b/src/mode/Clock/Clock.h @@ -3,7 +3,7 @@ #include "mode/Mode.h" -class Clock : public Mode { +class Clock : public Mode { public: diff --git a/src/mode/GameOfLife/GameOfLife.cpp b/src/mode/GameOfLife/GameOfLife.cpp new file mode 100644 index 0000000..87d21d9 --- /dev/null +++ b/src/mode/GameOfLife/GameOfLife.cpp @@ -0,0 +1,4 @@ +#include "GameOfLife.h" + +template<> +GameOfLife *Mode::instance = nullptr; \ No newline at end of file diff --git a/src/mode/GameOfLife/GameOfLife.h b/src/mode/GameOfLife/GameOfLife.h index 8db088c..446eb10 100644 --- a/src/mode/GameOfLife/GameOfLife.h +++ b/src/mode/GameOfLife/GameOfLife.h @@ -9,7 +9,7 @@ enum ColorMode { BLACK_WHITE, GRAYSCALE, COLOR_FADE, RANDOM_COLOR }; -class GameOfLife : public Mode { +class GameOfLife : public Mode { private: diff --git a/src/mode/Mode.cpp b/src/mode/Mode.cpp new file mode 100644 index 0000000..ae24ac5 --- /dev/null +++ b/src/mode/Mode.cpp @@ -0,0 +1,4 @@ +#include "Mode.h" + +//template +//T *Mode::instance = nullptr; \ No newline at end of file diff --git a/src/mode/Mode.h b/src/mode/Mode.h index 75f7158..f217339 100644 --- a/src/mode/Mode.h +++ b/src/mode/Mode.h @@ -6,84 +6,20 @@ #include "BASICS.h" #include "display/Display.h" #include "Timer.h" +#include "ModeBase.h" -class Mode { - -private: - - Timer *timers[TIMER_COUNT]{}; - - uint8_t timerCount = 0; +template +class Mode : public ModeBase { protected: - Display *display; + static T *instance; public: explicit Mode(Display *display) : - display(display) { - for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { - *timer = nullptr; - } - } - - virtual ~Mode() { - destroyAllTimers(); - }; - - virtual const char *getName() = 0; - - void step(microseconds_t dt) { - for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { - if (*timer != nullptr) { - (*timer)->step(dt); - } - } - doStep(dt); - } - -protected: - - virtual void doStep(microseconds_t dt) {}; - - Timer *createTimer(long long millisecondsInterval, Timer::Callback callback) { - for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { - if (*timer == nullptr) { - *timer = new Timer(millisecondsInterval * 1000, callback); - timerCount++; - return *timer; - } - } - Serial.printf("ERROR: Cannot create more than %d timers!\n", TIMER_COUNT); - return nullptr; - } - - bool destroyTimer(Timer *t) { - for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { - if (*timer == t) { - _destroyTimer(timer); - return true; - } - } - Serial.printf("ERROR: No such timer.\n"); - return false; - } - - void destroyAllTimers() { - for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { - if (*timer != nullptr) { - _destroyTimer(timer); - } - } - } - -private: - - void _destroyTimer(Timer **timer) { - timerCount--; - free(*timer); - *timer = nullptr; + ModeBase(display) { + instance = (T *) this; } }; diff --git a/src/mode/ModeBase.h b/src/mode/ModeBase.h new file mode 100644 index 0000000..5d333c1 --- /dev/null +++ b/src/mode/ModeBase.h @@ -0,0 +1,91 @@ +#ifndef MODE_BASE_H +#define MODE_BASE_H + +#define TIMER_COUNT 10 + +#include "BASICS.h" +#include "display/Display.h" +#include "Timer.h" + +class ModeBase { + +private: + + Timer *timers[TIMER_COUNT]{}; + + uint8_t timerCount = 0; + +protected: + + Display *display; + +public: + + explicit ModeBase(Display *display) : + display(display) { + for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { + *timer = nullptr; + } + } + + virtual ~ModeBase() { + destroyAllTimers(); + }; + + virtual const char *getName() = 0; + + void step(microseconds_t dt) { + for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { + if (*timer != nullptr) { + (*timer)->step(dt); + } + } + doStep(dt); + } + +protected: + + virtual void doStep(microseconds_t dt) {}; + + Timer *createTimer(long long millisecondsInterval, Timer::Callback callback) { + for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { + if (*timer == nullptr) { + *timer = new Timer(millisecondsInterval * 1000, callback); + timerCount++; + return *timer; + } + } + Serial.printf("ERROR: Cannot create more than %d timers!\n", TIMER_COUNT); + return nullptr; + } + + bool destroyTimer(Timer *t) { + for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { + if (*timer == t) { + _destroyTimer(timer); + return true; + } + } + Serial.printf("ERROR: No such timer.\n"); + return false; + } + + void destroyAllTimers() { + for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { + if (*timer != nullptr) { + _destroyTimer(timer); + } + } + } + +private: + + void _destroyTimer(Timer **timer) { + timerCount--; + free(*timer); + *timer = nullptr; + } + +}; + +#endif diff --git a/src/mode/NewYear/NewYear.cpp b/src/mode/NewYear/NewYear.cpp index 112db2e..d2784f2 100644 --- a/src/mode/NewYear/NewYear.cpp +++ b/src/mode/NewYear/NewYear.cpp @@ -1,3 +1,4 @@ #include "NewYear.h" -NewYear *NewYear::instance = nullptr; \ No newline at end of file +template<> +NewYear *Mode::instance = nullptr; \ No newline at end of file diff --git a/src/mode/NewYear/NewYear.h b/src/mode/NewYear/NewYear.h index 49fcf48..2a80c55 100644 --- a/src/mode/NewYear/NewYear.h +++ b/src/mode/NewYear/NewYear.h @@ -6,9 +6,7 @@ #include "mode/Mode.h" #include "Firework.h" -class NewYear : public Mode { - - static NewYear *instance; +class NewYear : public Mode { Firework fireworksBegin[MAX_FIREWORKS]; Firework *fireworksEnd = fireworksBegin + MAX_FIREWORKS; @@ -23,68 +21,39 @@ class NewYear : public Mode { } void step(Timer *timer, uint32_t counter, uint32_t currentCount) { - display->clear(); tm t{}; getLocalTime(&t); - int year = t.tm_year + 1900; - int mon = t.tm_mon + 1; - int day = t.tm_mday; - int hour = t.tm_hour; - int min = t.tm_min; - int sec = t.tm_sec; -#if PROG_ALL -#else - hour = 23; - min = 59; - sec = 55 + (int) (counter * 50 / 1000); - while (sec >= 60) { - min++; - sec -= 60; - } - while (min >= 60) { - hour++; - min -= 60; - } - while (hour >= 24) { - day++; - hour -= 24; - } - while (day > 31) { - mon++; - day -= 31; - } - while (mon > 12) { - year++; - mon -= 12; - } - Serial.printf("%04i-%02i-%02i %02i:%02i:%02i\n", year, mon, day, hour, min, sec); -#endif - if (mon == 12 && day == 31) { - size_t h = (24 - hour - (min > 0 || sec > 0 ? 1 : 0)); - size_t m = (60 - min - (sec > 0 ? 1 : 0)) % 60; - size_t s = (60 - sec) % 60; - uint8_t x = 0; - if (h >= 10) { - display->print(&x, 1, h / 10, COLOR_WHITE); - } else { - x += 3; - } - x++; - display->print(&x, 1, h % 10, COLOR_WHITE); - display->print(&x, 1, 10, COLOR_WHITE); - display->print(&x, 1, m / 10, COLOR_WHITE); - x++; - display->print(&x, 1, m % 10, COLOR_WHITE); - display->print(&x, 1, 10, COLOR_WHITE); - display->print(&x, 1, s / 10, COLOR_WHITE); - x++; - display->print(&x, 1, s % 10, COLOR_WHITE); + display->clear(); + if (t.tm_mon + 1 == 12 && t.tm_mday == 31) { + drawCountdown(t); } else { - drawYear(counter, year); - drawFirework(timer); + drawYear(counter, t.tm_year + 1900); + drawFirework(timer->interval); } } + void drawCountdown(const tm &time) { + size_t h = (24 - time.tm_hour - (time.tm_min > 0 || time.tm_sec > 0 ? 1 : 0)); + size_t m = (60 - time.tm_min - (time.tm_sec > 0 ? 1 : 0)) % 60; + size_t s = (60 - time.tm_sec) % 60; + uint8_t x = 0; + if (h >= 10) { + display->print(&x, 1, h / 10, COLOR_WHITE); + } else { + x += 3; + } + x++; + display->print(&x, 1, h % 10, COLOR_WHITE); + display->print(&x, 1, 10, COLOR_WHITE); + display->print(&x, 1, m / 10, COLOR_WHITE); + x++; + display->print(&x, 1, m % 10, COLOR_WHITE); + display->print(&x, 1, 10, COLOR_WHITE); + display->print(&x, 1, s / 10, COLOR_WHITE); + x++; + display->print(&x, 1, s % 10, COLOR_WHITE); + } + void drawYear(uint32_t counter, int year) { uint8_t x = 8; display->print(&x, 1, year / 1000 % 10, counter % 64 != 0 ? COLOR_WHITE : COLOR_BLACK); @@ -96,10 +65,10 @@ class NewYear : public Mode { display->print(&x, 1, year / 1 % 10, counter % 64 != 3 ? COLOR_WHITE : COLOR_BLACK); } - void drawFirework(const Timer *timer) const { + void drawFirework(microseconds_t dt) const { for (auto *firework = (Firework *) fireworksBegin; firework < fireworksEnd; firework++) { if (firework->isAlive()) { - firework->step(timer->interval); + firework->step(dt); firework->draw(); } } @@ -111,7 +80,6 @@ public: Mode(display) { createTimer(500, [](Timer *timer, uint32_t counter, uint32_t currentCount) { instance->launch(timer, counter, currentCount); }); createTimer(50, [](Timer *timer, uint32_t counter, uint32_t currentCount) { instance->step(timer, counter, currentCount); }); - instance = this; for (Firework *firework = fireworksBegin; firework < fireworksEnd; firework++) { firework->init(display); } diff --git a/src/mode/Pong/Pong.cpp b/src/mode/Pong/Pong.cpp index 7f39ccf..5708197 100644 --- a/src/mode/Pong/Pong.cpp +++ b/src/mode/Pong/Pong.cpp @@ -1,12 +1,4 @@ #include "Pong.h" -Pong *Pong::instance = nullptr; - -void Pong::resetPlayer() { - player0.size = 3; - player0.score = 0; - player0.position = (display->height - player0.size) / 2; - player1.size = 3; - player1.score = 0; - player1.position = (display->height - player1.size) / 2; -} +template<> +Pong *Mode::instance = nullptr; \ No newline at end of file diff --git a/src/mode/Pong/Pong.h b/src/mode/Pong/Pong.h index 2e83f92..852f1fa 100644 --- a/src/mode/Pong/Pong.h +++ b/src/mode/Pong/Pong.h @@ -5,7 +5,7 @@ #include "Player.h" #include "display/Vector.h" -class Pong : public Mode { +class Pong : public Mode { private: @@ -13,8 +13,6 @@ private: SCORE, PLAY, OVER }; - static Pong *instance; - Player player0; Player player1; @@ -27,13 +25,16 @@ private: microseconds_t timeout = 0; - static void tick(Timer *timer, uint32_t totalCount, uint32_t currentCount) { - instance->_tick(timer, totalCount, currentCount); + void resetPlayer() { + player0.size = 3; + player0.score = 0; + player0.position = (display->height - player0.size) / 2; + player1.size = 3; + player1.score = 0; + player1.position = (display->height - player1.size) / 2; } - void resetPlayer(); - - void _tick(Timer *timer, uint32_t totalCount, uint32_t currentCount) { + void tick(Timer *timer, uint32_t totalCount, uint32_t currentCount) { switch (status) { case SCORE: timeout -= currentCount * timer->interval; @@ -133,7 +134,7 @@ public: position(display->width / 2.0, display->height / 2.0), velocity(random(360), exp10(1)) { instance = this; - createTimer(100, &tick); + createTimer(100, [](Timer *timer, uint32_t counter, uint32_t currentCount) { instance->tick(timer, counter, currentCount); }); spawnBall(random(2) == 0 ? -1 : +1); resetPlayer(); } diff --git a/src/mode/SpaceInvaders/SpaceInvaders.cpp b/src/mode/SpaceInvaders/SpaceInvaders.cpp new file mode 100644 index 0000000..fd8855c --- /dev/null +++ b/src/mode/SpaceInvaders/SpaceInvaders.cpp @@ -0,0 +1,4 @@ +#include "SpaceInvaders.h" + +template<> +SpaceInvaders *Mode::instance = nullptr; \ No newline at end of file diff --git a/src/mode/SpaceInvaders/SpaceInvaders.h b/src/mode/SpaceInvaders/SpaceInvaders.h index 243b8d4..b4cd0f0 100644 --- a/src/mode/SpaceInvaders/SpaceInvaders.h +++ b/src/mode/SpaceInvaders/SpaceInvaders.h @@ -18,7 +18,7 @@ struct Invader { uint8_t y; }; -class SpaceInvaders : public Mode { +class SpaceInvaders : public Mode { private: @@ -80,7 +80,7 @@ public: Serial.println("WINNER!"); reset(); } - if (swarmY + (invadersCountY - 1) * 2 >= display->height - 1) { // TODO this is only correct if there still are any invaders in the accu row (otherwise we "Game Over" too early) + if (swarmY + (invadersCountY - 1) * 2 >= display->height - 1) { // TODO this is only correct if there still are any invaders in the last row (otherwise we "Game Over" too early) Serial.println("GAME OVER"); reset(); } diff --git a/src/mode/Test/Border.cpp b/src/mode/Test/Border.cpp new file mode 100644 index 0000000..23638d7 --- /dev/null +++ b/src/mode/Test/Border.cpp @@ -0,0 +1,4 @@ +#include "Border.h" + +template<> +Border *Mode::instance = nullptr; \ No newline at end of file diff --git a/src/mode/Test/Border.h b/src/mode/Test/Border.h index 75e3b74..ec55e21 100644 --- a/src/mode/Test/Border.h +++ b/src/mode/Test/Border.h @@ -3,7 +3,7 @@ #include "mode/Mode.h" -class Border : public Mode { +class Border : public Mode { public: