#ifndef MODE_TIMER_H #define MODE_TIMER_H #include #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