MatrixDisplay2025/src/mode/ModeTimer.h
2025-08-26 19:14:42 +02:00

260 lines
6.1 KiB
C++

#ifndef MODE_TIMER_H
#define MODE_TIMER_H
#include <Preferences.h>
#include "beep.h"
#include "Mode.h"
#include "Rest.h"
#include "Timer.h"
#define DEC_MIL ( 100 )
#define SEC_MIL ( 1000 )
#define MIN_MIL ( 60 * SEC_MIL )
#define HOU_MIL ( 60 * MIN_MIL )
#define DAY_MIL ( 24 * HOU_MIL )
#define ENABLE_DECIS false
enum Stage {
FIRST_HALF, SECOND_HALF, LAST_MINUTE, FINALE
};
inline uint32_t getTimerConfig(const char *name, const uint32_t fallback) {
Preferences preferences;
preferences.begin("Timer", true);
const auto configMillis = preferences.getULong(name, fallback);
preferences.end();
return configMillis;
}
inline void setTimerConfig(const char *name, const uint32_t configMillis) {
Preferences preferences;
preferences.begin("Timer", false);
preferences.putULong(name, configMillis);
preferences.end();
Serial.printf("CONFIG SET: %s.%s = %d\n", "Timer", name, configMillis);
}
inline uint32_t getTimerConfigCountdown() {
return getTimerConfig("countdown", 6 * 60 * 1000);
}
inline uint32_t getTimerConfigYellow() {
return getTimerConfig("yellow", 3 * 60 * 1000);
}
inline uint32_t getTimerConfigOrange() {
return getTimerConfig("orange", 1 * 60 * 1000);
}
inline uint32_t getTimerConfigRed() {
return getTimerConfig("red", 10 * 1000);
}
class ModeTimer final : public Mode {
Timer countdown;
Timer flash;
Timer pause;
Timer beep;
uint32_t yellow = 3 * 60 * 1000;
uint32_t orange = 1 * 60 * 1000;
uint32_t red = 10 * 1000;
bool dirty = true;
bool dirtyPrint = true;
Rest rest{0};
Rest last{0};
public:
explicit ModeTimer()
: Mode("Timer"),
countdown("countdown", [this]() {
flash.start();
dirty = true;
dirtyPrint = true;
}),
flash("flash", [this]() {
dirty = true;
dirtyPrint = true;
}),
pause("pause", [this]() {
dirty = true;
dirtyPrint = true;
}),
beep("beep", [this]() { beepSet(beep.isEven()); }) {
//
}
void init() override {
Serial.printf("Mode INIT: %s\n", name);
beepSet(false);
countdown.stop();
flash.stop();
pause.stop();
beep.stop();
const auto configMillis = getTimerConfigCountdown();
yellow = getTimerConfigYellow();
orange = getTimerConfigOrange();
red = getTimerConfigRed();
countdown.countConfig(configMillis, 1);
flash.countConfig(100, 19);
beep.countConfig(200, 1);
pause.foreverConfig(500);
dirty = true;
dirtyPrint = true;
}
void step(const uint64_t deltaMillis) override {
flash.step(deltaMillis);
pause.step(deltaMillis);
beep.step(deltaMillis);
if (!pause.isRunning()) {
countdown.step(deltaMillis);
}
}
void buttonOK() override {
if (flash.isRunning()) {
return;
}
if (!countdown.isRunning()) {
init();
doBeep(1);
countdown.start();
} else {
pause.toggle();
}
dirty = true;
dirtyPrint = true;
}
void buttonESC() override {
init();
}
void draw(Display &display) override {
if (countdown.getRestMillis() >= DAY_MIL) {
rest = Rest(intCeilDiv(countdown.getRestMillis(), HOU_MIL) * HOU_MIL);
} else if (countdown.getRestMillis() >= MIN_MIL) {
rest = Rest(intCeilDiv(countdown.getRestMillis(), SEC_MIL) * SEC_MIL);
} else {
#if ENABLE_DECIS
rest = Rest(intCeilDiv(countdown.getRestMillis(), DEC_MIL) * DEC_MIL);
#else
rest = Rest(intCeilDiv(countdown.getRestMillis(), SEC_MIL) * SEC_MIL);
#endif
}
display.clear();
if (flash.isRunning()) {
const auto state = flash.isEven();
if (state) {
display.rect(0, 0, 32, 8, WHITE);
}
beepSet(true);
} else {
if (countdown.isRunning()) {
if (pause.isRunning() && pause.isEven()) {
display.print(15, 0, ALIGN_CENTER, FONT7, BLUE, "PAUSE");
} else {
drawTime(display);
}
} else {
beepSet(false);
display.print(15, 0, ALIGN_CENTER, FONT7, RED, "-- : --");
}
}
if (dirty) {
dirty = false;
display.show();
if (dirtyPrint) {
dirtyPrint = false;
rest.log();
display.log();
}
}
last = rest;
}
private:
void doBeep(const uint32_t count) {
beepSet(true);
beep.startCount(count * 2 - 1);
}
void drawTime(Display &display) {
Color color = RED;
Stage stage = FINALE;
if (rest.millisTotal > yellow) {
color = WHITE;
stage = FIRST_HALF;
} else if (rest.millisTotal > orange) {
color = YELLOW;
stage = SECOND_HALF;
} else if (rest.millisTotal > red) {
color = ORANGE;
stage = LAST_MINUTE;
}
static int lastStage = stage;
if (lastStage != stage) {
if (stage == SECOND_HALF) {
doBeep(1);
} else if (stage == LAST_MINUTE) {
doBeep(2);
}
lastStage = stage;
}
if (rest.secondChanged(last)) {
if (stage == FINALE) {
doBeep(1);
}
}
if (rest.daysTotal > 0) {
display.print(16, 0, ALIGN_CENTER, FONT7, color, "%d. %2d", rest.daysPart, rest.hoursPart);
dirty |= rest.hourChanged(last);
dirtyPrint = true;
} else if (rest.hoursTotal > 0) {
display.print(16, 0, ALIGN_CENTER, FONT7, color, "%d:%02d:%02d", rest.hoursPart, rest.minutesPart,
rest.secondsPart);
dirty |= rest.secondChanged(last);
dirtyPrint = true;
} else if (rest.minutesTotal > 0) {
display.print(16, 0, ALIGN_CENTER, FONT7, color, "%d:%02d", rest.minutesPart, rest.secondsPart);
dirty |= rest.secondChanged(last);
dirtyPrint = true;
} else {
#if ENABLE_DECIS
display.print(16, 0, ALIGN_CENTER, FONT7, color, "%d.%d", rest.secondsPart, rest.decisPart);
#else
if (rest.secondsTotal > 9) {
display.print(16, 0, ALIGN_CENTER, FONT7, color, "%d", rest.secondsPart, rest.secondsPart);
} else {
display.print(16, 0, ALIGN_CENTER, FONT7, color, "%d %d %d", rest.secondsPart, rest.secondsPart, rest.secondsPart);
}
#endif
dirty |= rest.deciChanged(last);
dirtyPrint |= rest.secondChanged(last);
}
}
};
#endif