This commit is contained in:
Patrick Haßel 2021-12-31 15:23:39 +01:00
parent 72e5946a0e
commit 2351c42db2
14 changed files with 362 additions and 58 deletions

View File

@ -30,4 +30,4 @@ add_custom_target(
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
) )
add_executable(Z_DUMMY_TARGET ${SRC_LIST} src/mode/Test/Border.h src/mode/Clock/Clock.h src/mode/SpaceInvaders/SpaceInvaders.h src/mode/Timer.h src/mode/Pong/Pong.cpp src/BASICS.cpp src/display/Display.cpp) add_executable(Z_DUMMY_TARGET ${SRC_LIST} src/mode/Test/Border.h src/mode/Clock/Clock.h src/mode/SpaceInvaders/SpaceInvaders.h src/mode/Timer.h src/mode/Pong/Pong.cpp src/BASICS.cpp src/display/Display.cpp src/mode/NewYear/NewYear.h src/mode/NewYear/Firework.h src/mode/NewYear/NewYear.cpp)

View File

@ -13,9 +13,9 @@ 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
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
;upload_speed = 921600 upload_speed = 921600
monitor_port = /dev/ttyUSB0 monitor_port = /dev/ttyUSB0
monitor_speed = 115200 monitor_speed = 115200

View File

@ -1,20 +1,10 @@
#include "BASICS.h" #include "BASICS.h"
double step(double valueCurrent, double valueMin, double valueMax, microseconds_t timeTotal, microseconds_t timeDelta) { double doStep(double valueCurrent, double valueMin, double valueMax, long long millisecondsTotal, microseconds_t microsecondsDelta) {
double valueRange = valueMax - valueMin; double valueRange = valueMax - valueMin;
double timeRatio = (double) timeDelta / (double) timeTotal; double timeRatio = (double) microsecondsDelta / ((double) millisecondsTotal * 1000.0);
double valueStep = valueRange * timeRatio; double valueStep = valueRange * timeRatio;
double valueNew = max(valueMin, min(valueMax, valueCurrent + valueStep)); double valueNew = max(valueMin, min(valueMax, valueCurrent + valueStep));
// Serial.printf("valueCurrent: %13.3f\n", valueCurrent);
// Serial.printf("valueMin: %13.3f\n", valueMin);
// Serial.printf("valueMax: %13.3f\n", valueMax);
// Serial.printf("valueRange: %13.3f\n", valueRange);
// Serial.printf("timeTotal: %13.3f\n", (double) timeTotal);
// Serial.printf("timeDelta: %13.3f\n", (double) timeDelta);
// Serial.printf("timeRatio: %13.3f\n", timeRatio);
// Serial.printf("valueStep: %13.3f\n", valueStep);
// Serial.printf("valueNew: %13.3f\n", valueNew);
// Serial.println();
return valueNew; return valueNew;
} }

View File

@ -8,7 +8,7 @@
typedef int64_t microseconds_t; typedef int64_t microseconds_t;
double step(double valueCurrent, double valueMin, double valueMax, microseconds_t timeTotal, microseconds_t timeDelta); double doStep(double valueCurrent, double valueMin, double valueMax, microseconds_t millisecondsTotal, microseconds_t microsecondsDelta);
bool randomBool(int uncertainty); bool randomBool(int uncertainty);

View File

@ -3,11 +3,24 @@
#include "Pixel.h" #include "Pixel.h"
#include "Adafruit_NeoPixel.h" #include "Adafruit_NeoPixel.h"
#include "Vector.h"
#define SYMBOL_COUNT 13 #define SYMBOL_COUNT 13
#define DISPLAY_CHAR_WIDTH 3 #define DISPLAY_CHAR_WIDTH 3
#define DISPLAY_CHAR_HEIGHT 5 #define DISPLAY_CHAR_HEIGHT 5
#define FULL 255
#define ____ 0
#define rgb(r, g, b) ((((r << 8) | g) << 8) | b)
#define COLOR_RED (rgb(FULL, ____, ____))
#define COLOR_GREEN (rgb(____, FULL, ____))
#define COLOR_BLUE (rgb(____, ____, FULL))
#define COLOR_YELLOW (rgb(FULL, FULL, ____))
#define COLOR_VIOLET (rgb(FULL, ____, FULL))
#define COLOR_TURQUOISE (rgb(____, FULL, FULL))
#define COLOR_WHITE (rgb(FULL, FULL, FULL))
#define COLOR_BLACK (rgb(____, ____, ____))
extern bool SYMBOLS[SYMBOL_COUNT][DISPLAY_CHAR_WIDTH * DISPLAY_CHAR_HEIGHT]; extern bool SYMBOLS[SYMBOL_COUNT][DISPLAY_CHAR_WIDTH * DISPLAY_CHAR_HEIGHT];
class Display { class Display {
@ -51,6 +64,10 @@ public:
print(xPos, yPos, index, 255, 255, 255); print(xPos, yPos, index, 255, 255, 255);
} }
void print(uint8_t *xPos, uint8_t yPos, uint8_t index, uint32_t color) {
print(xPos, yPos, index, (uint8_t) (color >> 16), (uint8_t) (color >> 8), (uint8_t) color);
}
void print(uint8_t *xPos, uint8_t yPos, uint8_t index, uint8_t r, uint8_t g, uint8_t b) { void print(uint8_t *xPos, uint8_t yPos, uint8_t index, uint8_t r, uint8_t g, uint8_t b) {
if (index >= SYMBOL_COUNT) { if (index >= SYMBOL_COUNT) {
Serial.printf("Cannot print symbol #%u.\n", index); Serial.printf("Cannot print symbol #%u.\n", index);
@ -77,6 +94,14 @@ public:
setPixelColor(x, y, (((r << 8) | g) << 8) | b); setPixelColor(x, y, (((r << 8) | g) << 8) | b);
} }
void set(Vector *pos, uint32_t color) {
setPixelColor((uint8_t) round(pos->x), (uint8_t) round(pos->y), color);
}
void set(Vector *pos, uint8_t r, uint8_t g, uint8_t b) {
setPixelColor((uint8_t) round(pos->x), (uint8_t) round(pos->y), (((r << 8) | g) << 8) | b);
}
void setPixelColor(uint8_t x, uint8_t y, uint32_t color) { void setPixelColor(uint8_t x, uint8_t y, uint32_t color) {
if (x >= width || y >= height) { if (x >= width || y >= height) {
return; return;

View File

@ -11,6 +11,11 @@ public:
double y; double y;
Vector() :
x(0.0), y(0.0) {
// nothing
}
Vector(double x, double y) : Vector(double x, double y) :
x(x), y(y) { x(x), y(y) {
// nothing // nothing
@ -22,6 +27,24 @@ public:
y = sin(radians) * length; y = sin(radians) * length;
} }
Vector *set(Vector that) {
this->x = that.x;
this->y = that.y;
return this;
}
Vector *set(double _x, double _y) {
this->x = _x;
this->y = _y;
return this;
}
Vector *add(double _x, double _y) {
this->x += _x;
this->y += _y;
return this;
}
Vector *add(Vector that) { Vector *add(Vector that) {
this->x += that.x; this->x += that.x;
this->y += that.y; this->y += that.y;
@ -45,7 +68,6 @@ public:
} }
return this; return this;
} }
}; };
#endif #endif

View File

@ -1,15 +1,21 @@
#include <WiFi.h> #include <WiFi.h>
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#include "mode/Mode.h" #include "mode/Mode.h"
#include "mode/GameOfLife/GameOfLife.h"
#include "display/Display.h" #include "display/Display.h"
#if PROG_ALL
#include "mode/GameOfLife/GameOfLife.h"
#include "mode/Pong/Pong.h" #include "mode/Pong/Pong.h"
#include "mode/Test/Border.h" #include "mode/Test/Border.h"
#include "mode/Clock/Clock.h" #include "mode/Clock/Clock.h"
#include "mode/SpaceInvaders/SpaceInvaders.h" #include "mode/SpaceInvaders/SpaceInvaders.h"
#endif
#include "mode/NewYear/NewYear.h"
enum ModeId { enum ModeId {
NONE, NONE,
#if PROG_ALL
BORDER, BORDER,
CLOCK, CLOCK,
GAME_OF_LIFE_BLACK_WHITE, GAME_OF_LIFE_BLACK_WHITE,
@ -18,11 +24,13 @@ enum ModeId {
GAME_OF_LIFE_RANDOM_COLOR, GAME_OF_LIFE_RANDOM_COLOR,
PONG, PONG,
SPACE_INVADERS, SPACE_INVADERS,
#endif
NEW_YEAR,
}; };
Display display(32, 8); Display display(32, 8);
ModeId newModeId = PONG; ModeId newModeId = NEW_YEAR;
ModeId currentModeId = NONE; ModeId currentModeId = NONE;
@ -48,6 +56,7 @@ void setup() {
delay(500); delay(500);
Serial.begin(115200); Serial.begin(115200);
Serial.println("\n\n\nStartup!"); Serial.println("\n\n\nStartup!");
WiFi.begin("HappyNet", "1Grausame!Sackratte7"); WiFi.begin("HappyNet", "1Grausame!Sackratte7");
ArduinoOTA.onStart([]() { ArduinoOTA.onStart([]() {
display.clear(); display.clear();
@ -68,8 +77,8 @@ void setup() {
display.clear(); display.clear();
display.loop(); display.loop();
}); });
ArduinoOTA.begin(); ArduinoOTA.begin();
display.setup(); display.setup();
} }
@ -156,29 +165,34 @@ void loadNewMode() {
switch (currentModeId) { switch (currentModeId) {
case NONE: case NONE:
break; break;
case BORDER: #if PROG_ALL
mode = new Border(&display); case BORDER:
break; mode = new Border(&display);
case CLOCK: break;
mode = new Clock(&display); case CLOCK:
break; mode = new Clock(&display);
case GAME_OF_LIFE_BLACK_WHITE: break;
mode = new GameOfLife(&display, BLACK_WHITE); case GAME_OF_LIFE_BLACK_WHITE:
break; mode = new GameOfLife(&display, BLACK_WHITE);
case GAME_OF_LIFE_GRAYSCALE: break;
mode = new GameOfLife(&display, GRAYSCALE); case GAME_OF_LIFE_GRAYSCALE:
break; mode = new GameOfLife(&display, GRAYSCALE);
case GAME_OF_LIFE_COLOR_FADE: break;
mode = new GameOfLife(&display, COLOR_FADE); case GAME_OF_LIFE_COLOR_FADE:
break; mode = new GameOfLife(&display, COLOR_FADE);
case GAME_OF_LIFE_RANDOM_COLOR: break;
mode = new GameOfLife(&display, RANDOM_COLOR); case GAME_OF_LIFE_RANDOM_COLOR:
break; mode = new GameOfLife(&display, RANDOM_COLOR);
case PONG: break;
mode = new Pong(&display); case PONG:
break; mode = new Pong(&display);
case SPACE_INVADERS: break;
mode = new SpaceInvaders(&display); case SPACE_INVADERS:
mode = new SpaceInvaders(&display);
break;
#endif
case NEW_YEAR:
mode = new NewYear(&display);
break; break;
} }
Serial.printf("Mode: %s\n", mode == nullptr ? "None" : mode->getName()); Serial.printf("Mode: %s\n", mode == nullptr ? "None" : mode->getName());

View File

@ -16,15 +16,10 @@ public:
void animate(microseconds_t dt) { void animate(microseconds_t dt) {
// TODO "doStep" does not work as expected // TODO "doStep" does not work as expected
if (alive) { if (alive) {
fade = step(fade, 0.0, 255.0, 200000, +dt); fade = doStep(fade, 0.0, 255.0, 200, +dt);
} else { } else {
fade = step(fade, 0.0, 255.0, 200000, -dt); fade = doStep(fade, 0.0, 255.0, 200, -dt);
} }
// if (alive) {
// fade = min(255.0, fade + (double) dt / 200000.0);
// } else {
// fade = max(0.0, fade - (double) dt / 200000.0);
// }
} }
uint8_t getR() const { uint8_t getR() const {

View File

@ -47,12 +47,11 @@ protected:
virtual void doStep(microseconds_t dt) {}; virtual void doStep(microseconds_t dt) {};
Timer *createTimer(microseconds_t interval, Timer::Callback callback) { Timer *createTimer(long long millisecondsInterval, Timer::Callback callback) {
for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) { for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) {
if (*timer == nullptr) { if (*timer == nullptr) {
*timer = new Timer(interval, callback); *timer = new Timer(millisecondsInterval * 1000, callback);
timerCount++; timerCount++;
Serial.printf("Timer created: %p (having %u now)\n", *timer, timerCount);
return *timer; return *timer;
} }
} }
@ -84,7 +83,6 @@ private:
void _destroyTimer(Timer **timer) { void _destroyTimer(Timer **timer) {
timerCount--; timerCount--;
free(*timer); free(*timer);
Serial.printf("Timer destroyed: %p (having %u now)\n", *timer, timerCount);
*timer = nullptr; *timer = nullptr;
} }

136
src/mode/NewYear/Firework.h Normal file
View File

@ -0,0 +1,136 @@
#ifndef NEW_YEAR_FIREWORK_H
#define NEW_YEAR_FIREWORK_H
#include "BASICS.h"
#include "display/Vector.h"
#include "display/Display.h"
class Firework {
enum State {
INITIAL, RISE, EXPLODE, SPARKLE
};
Display *display{};
uint32_t color{};
State state = RISE;
Vector position;
double destinationHeight = 0;
double explosionRadius = 0;
double sparkleMax = 0;
double explosion{};
double sparkle{};
public:
void init(Display *_display) {
this->display = _display;
reset();
}
void reset() {
position.set((double) random(display->width), display->height);
color = random(16777216);
state = INITIAL;
destinationHeight = display->height / 2.0 + (double) random(5) - 2;
explosionRadius = (double) random(3) + 1;
sparkleMax = 100;
explosion = 0.0;
sparkle = 0.0;
}
void launch() {
if (state != INITIAL) {
Serial.println("ERROR: Cannot start Firework. Already started.");
return;
}
state = RISE;
}
void step(microseconds_t dt) {
switch (state) {
case INITIAL:
break;
case RISE:
if (position.y <= destinationHeight) {
state = EXPLODE;
}
break;
case EXPLODE:
if (explosion >= explosionRadius) {
state = SPARKLE;
}
break;
case SPARKLE:
if (sparkle >= sparkleMax) {
reset();
}
break;
}
switch (state) {
case INITIAL:
break;
case RISE:
position.y = doStep(position.y, 0.0, display->height, 1000, -dt);
break;
case EXPLODE:
explosion = doStep(explosion, 0.0, explosionRadius, 500, +dt);
break;
case SPARKLE:
sparkle = doStep(sparkle, 0.0, sparkleMax, 1000, +dt);
break;
}
}
void draw() {
Vector p;
switch (state) {
case INITIAL:
break;
case RISE:
display->set(&position, COLOR_YELLOW);
break;
case EXPLODE:
drawParticle(p, +0.0, +1.0);
drawParticle(p, +0.7, +0.7);
drawParticle(p, +1.0, +0.0);
drawParticle(p, +0.7, -0.7);
drawParticle(p, +0.0, -1.0);
drawParticle(p, -0.7, -0.7);
drawParticle(p, -1.0, +0.0);
drawParticle(p, -0.7, +0.7);
break;
case SPARKLE:
if (randomBool(2)) drawParticle(p, +0.0, +1.0);
if (randomBool(2)) drawParticle(p, +0.7, +0.7);
if (randomBool(2)) drawParticle(p, +1.0, +0.0);
if (randomBool(2)) drawParticle(p, +0.7, -0.7);
if (randomBool(2)) drawParticle(p, +0.0, -1.0);
if (randomBool(2)) drawParticle(p, -0.7, -0.7);
if (randomBool(2)) drawParticle(p, -1.0, +0.0);
if (randomBool(2)) drawParticle(p, -0.7, +0.7);
break;
}
}
void drawParticle(Vector &p, double x, double y) {
display->set(p.set(position)->add(x * explosion, y * explosion), color);
}
bool isAlive() {
return state != INITIAL;
}
};
#endif

View File

@ -0,0 +1,3 @@
#include "NewYear.h"
NewYear *NewYear::instance = nullptr;

120
src/mode/NewYear/NewYear.h Normal file
View File

@ -0,0 +1,120 @@
#ifndef NEWYEAR_H
#define NEWYEAR_H
#define MAX_FIREWORKS 10
#include "mode/Mode.h"
#include "Firework.h"
class NewYear : public Mode {
static NewYear *instance;
Firework fireworksBegin[MAX_FIREWORKS];
Firework *fireworksEnd = fireworksBegin + MAX_FIREWORKS;
void launch(Timer *timer, uint32_t counter, uint32_t currentCount) {
for (Firework *firework = fireworksBegin; firework < fireworksEnd; firework++) {
if (!firework->isAlive()) {
firework->launch();
return;
}
}
}
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);
} else {
for (Firework *firework = fireworksBegin; firework < fireworksEnd; firework++) {
if (firework->isAlive()) {
firework->step(timer->interval);
firework->draw();
}
}
uint8_t x = 8;
display->print(&x, 1, year / 1000 % 10, counter % 64 != 0 ? COLOR_WHITE : COLOR_BLACK);
x++;
display->print(&x, 1, year / 100 % 10, counter % 64 != 1 ? COLOR_WHITE : COLOR_BLACK);
x++;
display->print(&x, 1, year / 10 % 10, counter % 64 != 2 ? COLOR_WHITE : COLOR_BLACK);
x++;
display->print(&x, 1, year / 1 % 10, counter % 64 != 3 ? COLOR_WHITE : COLOR_BLACK);
}
}
public:
explicit NewYear(Display *display) :
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);
}
}
~NewYear() override = default;
const char *getName() override {
return "NewYear";
}
};
#endif

View File

@ -133,7 +133,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(100000, &tick); createTimer(100, &tick);
spawnBall(random(2) == 0 ? -1 : +1); spawnBall(random(2) == 0 ? -1 : +1);
resetPlayer(); resetPlayer();
} }

View File

@ -31,8 +31,9 @@ public:
accu += dt; accu += dt;
if (accu >= interval) { if (accu >= interval) {
uint32_t currentCount = accu / interval; uint32_t currentCount = accu / interval;
totalCount += currentCount;
accu = accu % interval; accu = accu % interval;
callback(this, totalCount++, currentCount); callback(this, totalCount, currentCount);
} }
} }