Sporttafel/src/countdown.cpp

200 lines
4.2 KiB
C++

#include "countdown.h"
#include <LittleFS.h>
#include "display.h"
enum State {
CONFIG, READY, RUNNING, PAUSED, END
};
State state = CONFIG;
bool countdownConfigDirty = false;
long countdownMillis = 6 * 60 * 1000;
long countdownRest = countdownMillis;
unsigned long last = 0;
void updateTime() {
if (state != RUNNING) {
return;
}
const auto now = max(1UL, millis());
if (last != 0) {
const auto diff = now - last;
countdownRest -= static_cast<long>(diff);
if (countdownRest < 0) {
countdownRest = 0;
}
}
last = now;
}
void drawSequence() {
for (int x = 0; x < 3; ++x) {
for (int i = 0; i < 2; ++i) {
drawAll(WHITE);
delay(100);
drawBlack();
delay(100);
}
drawDashes();
delay(500);
}
}
void setState(const State newState) {
if (state == newState) {
return;
}
state = newState;
const char* name;
switch (state) {
case CONFIG:
countdownRest = countdownMillis;
name = "CONFIG";
break;
case READY:
countdownRest = countdownMillis;
name = "READY";
break;
case RUNNING:
last = millis();
name = "RUNNING";
break;
case PAUSED:
name = "PAUSED";
break;
case END:
drawSequence();
name = "END";
break;
default:
name = "[???]";
break;
}
Serial.printf("Mode: %s\n", name);
}
void countdownUpdate() {
switch (state) {
case CONFIG:
drawMillis(countdownRest, MAGENTA);
break;
case READY:
drawMillis(countdownRest, GREEN);
break;
case RUNNING: {
if (countdownRest > 0) {
const auto color = countdownRest >= 60000 ? WHITE : (countdownRest >= 10000 ? YELLOW : RED);
drawMillis(countdownRest, color);
} else {
setState(END);
setState(READY);
}
break;
}
case PAUSED:
drawMillis(countdownRest, BLUE);
break;
case END:
drawDashes();
break;
}
}
void countdownConfigLoad() {
if (LittleFS.begin(true)) {
Serial.println("Filesystem mounted.");
File file = LittleFS.open("/countdownMillis");
if (file) {
const String content = file.readString();
if (content) {
countdownMillis = content.toInt();
Serial.printf("Read countdownMillis from file: countdownMillis=%lu, file=%s", countdownMillis, file.path());
} else {
Serial.printf("WARN: Cannot parse content of: %s\n", file.path());
}
file.close();
} else {
Serial.printf("WARN: Cannot open file for READ: %s\n", file.path());
}
LittleFS.end();
Serial.println("Filesystem unmounted.");
} else {
Serial.println("ERROR: Failed to mount filesystem.");
}
}
void countdownConfigWrite() {
if (LittleFS.begin(true)) {
Serial.println("Filesystem mounted.");
File file = LittleFS.open("/countdownMillis", "w", true);
if (file) {
file.printf("%lu", countdownMillis);
Serial.printf("Wrote countdownMillis to file: countdownMillis=%lu, file=%s", countdownMillis, file.path());
file.close();
countdownConfigDirty = false;
} else {
Serial.printf("WARN: Cannot open file for WRITE: %s\n", file.path());
}
LittleFS.end();
Serial.println("Filesystem unmounted.");
} else {
Serial.println("ERROR: failed to mount filesystem");
}
}
void countdownSetup() {
countdownConfigLoad();
setState(READY);
}
void countdownLoop() {
updateTime();
countdownUpdate();
}
void buttonShortPressed() {
switch (state) {
case CONFIG: {
const auto seconds = (countdownMillis / 30000) * 30 % (15 * 60) + 30;
countdownMillis = seconds * 1000;
countdownRest = countdownMillis;
countdownConfigDirty = true;
break;
}
case READY:
case END:
setState(CONFIG);
break;
case RUNNING:
case PAUSED:
setState(READY);
break;
}
}
void buttonLongPressed() {
switch (state) {
case CONFIG:
if (countdownConfigDirty) {
countdownConfigWrite();
}
setState(READY);
break;
case RUNNING:
setState(PAUSED);
break;
case READY:
case PAUSED:
setState(RUNNING);
break;
case END:
setState(READY);
break;
}
}