ModeBase with 'instance'

This commit is contained in:
Patrick Haßel 2022-01-01 12:45:27 +01:00
parent 328785d187
commit e47bc86299
17 changed files with 180 additions and 162 deletions

View File

@ -13,7 +13,7 @@ platform = espressif32
board = esp32dev board = esp32dev
framework = arduino framework = arduino
lib_deps = https://github.com/adafruit/Adafruit_NeoPixel 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_port = 10.0.0.120
;upload_protocol = espota ;upload_protocol = espota
upload_port = /dev/ttyUSB0 upload_port = /dev/ttyUSB0

View File

@ -1,10 +1,14 @@
#include <WiFi.h> #include <WiFi.h>
#if ENABLE_OTA
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#endif
#include "mode/Mode.h" #include "mode/Mode.h"
#include "display/Display.h" #include "display/Display.h"
#include <WebServer.h> #include <WebServer.h>
#if PROG_ALL #if ENABLE_ALL
#include "mode/GameOfLife/GameOfLife.h" #include "mode/GameOfLife/GameOfLife.h"
#include "mode/Pong/Pong.h" #include "mode/Pong/Pong.h"
@ -18,7 +22,7 @@
enum ModeId { enum ModeId {
NONE, NONE,
#if PROG_ALL #if ENABLE_ALL
BORDER, BORDER,
CLOCK, CLOCK,
GAME_OF_LIFE_BLACK_WHITE, GAME_OF_LIFE_BLACK_WHITE,
@ -41,7 +45,7 @@ ModeId currentModeId = NONE;
microseconds_t lastMicros = 0; microseconds_t lastMicros = 0;
Mode *mode = nullptr; ModeBase *mode = nullptr;
double speed = 1.0; double speed = 1.0;
@ -107,6 +111,8 @@ void setup() {
Serial.println("\n\n\nStartup!"); Serial.println("\n\n\nStartup!");
WiFi.begin("HappyNet", "1Grausame!Sackratte7"); WiFi.begin("HappyNet", "1Grausame!Sackratte7");
#if ENABLE_OTA
ArduinoOTA.onStart([]() { ArduinoOTA.onStart([]() {
display.clear(); display.clear();
display.loop(); display.loop();
@ -127,6 +133,7 @@ void setup() {
display.loop(); display.loop();
}); });
ArduinoOTA.begin(); ArduinoOTA.begin();
#endif
server.on("", web_index); server.on("", web_index);
server.on("/", web_index); server.on("/", web_index);
@ -144,7 +151,9 @@ void setup() {
void setSpeed(double value); void setSpeed(double value);
void loop() { void loop() {
#if ENABLE_OTA
ArduinoOTA.handle(); ArduinoOTA.handle();
#endif
server.handleClient(); server.handleClient();
bool hasIp = (uint32_t) WiFi.localIP() != 0; bool hasIp = (uint32_t) WiFi.localIP() != 0;
if (!connected) { if (!connected) {
@ -225,7 +234,7 @@ void loadNewMode() {
switch (currentModeId) { switch (currentModeId) {
case NONE: case NONE:
break; break;
#if PROG_ALL #if ENABLE_ALL
case BORDER: case BORDER:
mode = new Border(&display); mode = new Border(&display);
break; break;

4
src/mode/Clock/Clock.cpp Normal file
View File

@ -0,0 +1,4 @@
#include "Clock.h"
template<>
Clock *Mode<Clock>::instance = nullptr;

View File

@ -3,7 +3,7 @@
#include "mode/Mode.h" #include "mode/Mode.h"
class Clock : public Mode { class Clock : public Mode<Clock> {
public: public:

View File

@ -0,0 +1,4 @@
#include "GameOfLife.h"
template<>
GameOfLife *Mode<GameOfLife>::instance = nullptr;

View File

@ -9,7 +9,7 @@ enum ColorMode {
BLACK_WHITE, GRAYSCALE, COLOR_FADE, RANDOM_COLOR BLACK_WHITE, GRAYSCALE, COLOR_FADE, RANDOM_COLOR
}; };
class GameOfLife : public Mode { class GameOfLife : public Mode<GameOfLife> {
private: private:

4
src/mode/Mode.cpp Normal file
View File

@ -0,0 +1,4 @@
#include "Mode.h"
//template<typename T>
//T *Mode<T>::instance = nullptr;

View File

@ -6,84 +6,20 @@
#include "BASICS.h" #include "BASICS.h"
#include "display/Display.h" #include "display/Display.h"
#include "Timer.h" #include "Timer.h"
#include "ModeBase.h"
class Mode { template<typename T>
class Mode : public ModeBase {
private:
Timer *timers[TIMER_COUNT]{};
uint8_t timerCount = 0;
protected: protected:
Display *display; static T *instance;
public: public:
explicit Mode(Display *display) : explicit Mode(Display *display) :
display(display) { ModeBase(display) {
for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { instance = (T *) this;
*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;
} }
}; };

91
src/mode/ModeBase.h Normal file
View File

@ -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

View File

@ -1,3 +1,4 @@
#include "NewYear.h" #include "NewYear.h"
NewYear *NewYear::instance = nullptr; template<>
NewYear *Mode<NewYear>::instance = nullptr;

View File

@ -6,9 +6,7 @@
#include "mode/Mode.h" #include "mode/Mode.h"
#include "Firework.h" #include "Firework.h"
class NewYear : public Mode { class NewYear : public Mode<NewYear> {
static NewYear *instance;
Firework fireworksBegin[MAX_FIREWORKS]; Firework fireworksBegin[MAX_FIREWORKS];
Firework *fireworksEnd = fireworksBegin + MAX_FIREWORKS; Firework *fireworksEnd = fireworksBegin + MAX_FIREWORKS;
@ -23,46 +21,21 @@ class NewYear : public Mode {
} }
void step(Timer *timer, uint32_t counter, uint32_t currentCount) { void step(Timer *timer, uint32_t counter, uint32_t currentCount) {
display->clear();
tm t{}; tm t{};
getLocalTime(&t); getLocalTime(&t);
int year = t.tm_year + 1900; display->clear();
int mon = t.tm_mon + 1; if (t.tm_mon + 1 == 12 && t.tm_mday == 31) {
int day = t.tm_mday; drawCountdown(t);
int hour = t.tm_hour; } else {
int min = t.tm_min; drawYear(counter, t.tm_year + 1900);
int sec = t.tm_sec; drawFirework(timer->interval);
#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++; void drawCountdown(const tm &time) {
hour -= 24; 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;
while (day > 31) { size_t s = (60 - time.tm_sec) % 60;
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; uint8_t x = 0;
if (h >= 10) { if (h >= 10) {
display->print(&x, 1, h / 10, COLOR_WHITE); display->print(&x, 1, h / 10, COLOR_WHITE);
@ -79,10 +52,6 @@ class NewYear : public Mode {
display->print(&x, 1, s / 10, COLOR_WHITE); display->print(&x, 1, s / 10, COLOR_WHITE);
x++; x++;
display->print(&x, 1, s % 10, COLOR_WHITE); display->print(&x, 1, s % 10, COLOR_WHITE);
} else {
drawYear(counter, year);
drawFirework(timer);
}
} }
void drawYear(uint32_t counter, int year) { void drawYear(uint32_t counter, int year) {
@ -96,10 +65,10 @@ class NewYear : public Mode {
display->print(&x, 1, year / 1 % 10, counter % 64 != 3 ? COLOR_WHITE : COLOR_BLACK); 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++) { for (auto *firework = (Firework *) fireworksBegin; firework < fireworksEnd; firework++) {
if (firework->isAlive()) { if (firework->isAlive()) {
firework->step(timer->interval); firework->step(dt);
firework->draw(); firework->draw();
} }
} }
@ -111,7 +80,6 @@ public:
Mode(display) { Mode(display) {
createTimer(500, [](Timer *timer, uint32_t counter, uint32_t currentCount) { instance->launch(timer, counter, currentCount); }); 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); }); createTimer(50, [](Timer *timer, uint32_t counter, uint32_t currentCount) { instance->step(timer, counter, currentCount); });
instance = this;
for (Firework *firework = fireworksBegin; firework < fireworksEnd; firework++) { for (Firework *firework = fireworksBegin; firework < fireworksEnd; firework++) {
firework->init(display); firework->init(display);
} }

View File

@ -1,12 +1,4 @@
#include "Pong.h" #include "Pong.h"
Pong *Pong::instance = nullptr; template<>
Pong *Mode<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;
}

View File

@ -5,7 +5,7 @@
#include "Player.h" #include "Player.h"
#include "display/Vector.h" #include "display/Vector.h"
class Pong : public Mode { class Pong : public Mode<Pong> {
private: private:
@ -13,8 +13,6 @@ private:
SCORE, PLAY, OVER SCORE, PLAY, OVER
}; };
static Pong *instance;
Player player0; Player player0;
Player player1; Player player1;
@ -27,13 +25,16 @@ private:
microseconds_t timeout = 0; microseconds_t timeout = 0;
static void tick(Timer *timer, uint32_t totalCount, uint32_t currentCount) { void resetPlayer() {
instance->_tick(timer, totalCount, currentCount); 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) { switch (status) {
case SCORE: case SCORE:
timeout -= currentCount * timer->interval; timeout -= currentCount * timer->interval;
@ -133,7 +134,7 @@ public:
position(display->width / 2.0, display->height / 2.0), position(display->width / 2.0, display->height / 2.0),
velocity(random(360), exp10(1)) { velocity(random(360), exp10(1)) {
instance = this; 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); spawnBall(random(2) == 0 ? -1 : +1);
resetPlayer(); resetPlayer();
} }

View File

@ -0,0 +1,4 @@
#include "SpaceInvaders.h"
template<>
SpaceInvaders *Mode<SpaceInvaders>::instance = nullptr;

View File

@ -18,7 +18,7 @@ struct Invader {
uint8_t y; uint8_t y;
}; };
class SpaceInvaders : public Mode { class SpaceInvaders : public Mode<SpaceInvaders> {
private: private:
@ -80,7 +80,7 @@ public:
Serial.println("WINNER!"); Serial.println("WINNER!");
reset(); 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"); Serial.println("GAME OVER");
reset(); reset();
} }

4
src/mode/Test/Border.cpp Normal file
View File

@ -0,0 +1,4 @@
#include "Border.h"
template<>
Border *Mode<Border>::instance = nullptr;

View File

@ -3,7 +3,7 @@
#include "mode/Mode.h" #include "mode/Mode.h"
class Border : public Mode { class Border : public Mode<Border> {
public: public: