From 4a04565878b3c1444059d6366981d41fe2ae81a7 Mon Sep 17 00:00:00 2001 From: Carsten Graf Date: Wed, 6 Aug 2025 00:46:05 +0200 Subject: [PATCH] BUG: Comp-mode erstes stoppen zeigt falsche zeit an! Individ mode geht. --- data/index.html | 46 ++++++++--- src/gamemodes.h | 210 ++++++++++++++++++++++++++++++++++++------------ src/master.cpp | 11 ++- src/master.h | 6 +- 4 files changed, 204 insertions(+), 69 deletions(-) diff --git a/data/index.html b/data/index.html index a0cf1f6..412c94f 100644 --- a/data/index.html +++ b/data/index.html @@ -368,12 +368,23 @@ s1.textContent = "Standby: Bitte beide Buttons 1x betätigen"; } else { s1.className = `status ${status1}`; - s1.textContent = - status1 === "ready" - ? "Bereit" - : status1 === "running" - ? "Läuft..." - : "Beendet"; + + switch (status1) { + case "ready": + s1.textContent = "Bereit"; + break; + case "running": + s1.textContent = "Läuft..."; + break; + case "finished": + s1.textContent = "Beendet"; + break; + case "armed": + s1.textContent = "Armiert"; // Neuer Status für armiert + break; + default: + s1.textContent = "Unbekannter Status"; + } } document.getElementById("time2").textContent = formatTime(display2); @@ -383,12 +394,23 @@ s2.textContent = "Standby: Bitte beide 1x betätigen"; } else { s2.className = `status ${status2}`; - s2.textContent = - status2 === "ready" - ? "Bereit" - : status2 === "running" - ? "Läuft..." - : "Beendet"; + + switch (status2) { + case "ready": + s2.textContent = "Bereit"; + break; + case "running": + s2.textContent = "Läuft..."; + break; + case "finished": + s2.textContent = "Beendet"; + break; + case "armed": + s2.textContent = "Armiert"; // Neuer Status für armiert + break; + default: + s2.textContent = "Unbekannter Status"; + } } document.getElementById("best1").textContent = diff --git a/src/gamemodes.h b/src/gamemodes.h index 7e2a62c..72af23b 100644 --- a/src/gamemodes.h +++ b/src/gamemodes.h @@ -20,7 +20,7 @@ void handleStart2(uint64_t timestamp); void handleStop2(uint64_t timestamp); void triggerAction(const char *action, int press, int lane, - uint64_t _timestamp = 0) { + uint64_t _timestamp) { if (gamemode == 0) { Serial.println("Individual Mode aktiv"); IndividualMode(action, press, lane, _timestamp); @@ -50,7 +50,7 @@ void IndividualMode(const char *action, int press, int lane, timerData.endTime1 = (timestamp > 0) ? timestamp : millis(); timerData.finishedSince1 = millis(); // Set finished time timerData.isRunning1 = false; - unsigned long currentTime = timerData.endTime1 - timerData.startTime1; + uint64_t currentTime = timerData.endTime1 - timerData.startTime1; if (timerData.bestTime1 == 0 || currentTime < timerData.bestTime1) { timerData.bestTime1 = currentTime; @@ -77,7 +77,7 @@ void IndividualMode(const char *action, int press, int lane, timerData.endTime2 = (timestamp > 0) ? timestamp : millis(); timerData.finishedSince2 = millis(); // Set finished time timerData.isRunning2 = false; - unsigned long currentTime = timerData.endTime2 - timerData.startTime2; + uint64_t currentTime = timerData.endTime2 - timerData.startTime2; if (timerData.bestTime2 == 0 || currentTime < timerData.bestTime2) { timerData.bestTime2 = currentTime; @@ -98,74 +98,178 @@ void CompetitionMode(const char *action, int press, int lane, uint64_t timestamp) { Serial.printf("Competition Mode Action: %s on Lane %d at %llu\n", action, lane, timestamp); - // Implement competition mode logic here + + int armedAtTime1; + int armedAtTime2; + int armTimeout = 10000; // Zeit in Millisekunden, die die Bahn armiert bleibt + + if (action == "start" && press == 2 && lane == 1) { + if (!timerData.isRunning1 && timerData.isReady1) { + timerData.isReady1 = false; + timerData.isArmed1 = true; // Set Bahn 1 as armed + publishLaneStatus(1, "armed"); + Serial.println("Bahn 1 armiert"); + armedAtTime1 = millis(); // Set armed time for Bahn 1 + } + } + if (action == "start" && press == 2 && lane == 2) { + if (!timerData.isRunning2 && timerData.isReady2) { + timerData.isReady2 = false; + timerData.isArmed2 = true; // Set Bahn 2 as armed + publishLaneStatus(2, "armed"); + Serial.println("Bahn 2 armiert"); + armedAtTime2 = millis(); // Set armed time for Bahn 2 + } + } + + if (armedAtTime1 > armedAtTime1 + armTimeout) { + timerData.isArmed1 = false; // Reset Bahn 1 if armed time exceeded + timerData.isReady1 = true; // Set Bahn 1 back to ready + Serial.println("Bahn 1 automatisch zurückgesetzt (armiert)"); + publishLaneStatus(1, "ready"); + } + + if (armedAtTime2 > armedAtTime2 + armTimeout) { + timerData.isArmed2 = false; // Reset Bahn 2 if armed time exceeded + timerData.isReady2 = true; // Set Bahn 2 back to ready + Serial.println("Bahn 2 automatisch zurückgesetzt (armiert)"); + publishLaneStatus(2, "ready"); + } + + if (timerData.isArmed1 && timerData.isArmed2) { + timerData.isReady1 = false; + uint64_t startNow = getCurrentTimestampMs(); + timerData.startTime1 = startNow; + timerData.localStartTime1 = millis(); // Set local start time + timerData.isRunning1 = true; + timerData.endTime1 = 0; // Reset end time for Bahn 1 + timerData.isArmed1 = false; // Reset Bahn 1 armed status + publishLaneStatus(1, "running"); + Serial.println("Bahn 1 gestartet"); + + timerData.isReady2 = false; + timerData.startTime2 = startNow; + timerData.localStartTime2 = millis(); // Set local start time + timerData.isRunning2 = true; + timerData.endTime2 = 0; // Reset end time for Bahn 2 + timerData.isArmed2 = false; // Reset Bahn 2 armed status + publishLaneStatus(2, "running"); + Serial.println("Bahn 2 gestartet"); + } + + if ((action == "stop" && press == 1 && lane == 1)) { + if (timerData.isRunning1) { + timerData.endTime1 = (timestamp > 0) ? timestamp : millis(); + timerData.finishedSince1 = millis(); // Set finished time + timerData.isRunning1 = false; + uint64_t currentTime1 = timerData.endTime1 - timerData.startTime1; + + if (timerData.bestTime1 == 0 || currentTime1 < timerData.bestTime1) { + timerData.bestTime1 = currentTime1; + saveBestTimes(); + } + publishLaneStatus(1, "stopped"); + Serial.println( + "Bahn 1 gestoppt - Zeit: " + String(currentTime1 / 1000.0) + "s"); + } + } + if (action == "stop" && press == 1 && lane == 2) { + if (timerData.isRunning2) { + timerData.endTime2 = (timestamp > 0) ? timestamp : millis(); + timerData.finishedSince2 = millis(); // Set finished time + timerData.isRunning2 = false; + uint64_t currentTime2 = timerData.endTime2 - timerData.startTime2; + + if (timerData.bestTime2 == 0 || currentTime2 < timerData.bestTime2) { + timerData.bestTime2 = currentTime2; + saveBestTimes(); + } + publishLaneStatus(2, "stopped"); + Serial.println( + "Bahn 2 gestoppt - Zeit: " + String(currentTime2 / 1000.0) + "s"); + } + } } void checkAutoReset() { unsigned long currentTime = millis(); - if (timerData.isRunning1 && - (currentTime - timerData.localStartTime1 > maxTimeBeforeReset)) { - timerData.isRunning1 = false; - timerData.startTime1 = 0; - publishLaneStatus(1, "ready"); - Serial.println("Bahn 1 automatisch zurückgesetzt"); - } + if (gamemode == 0) { // Individual Mode: Bahnen unabhängig zurücksetzen + if (!timerData.isRunning1 && timerData.endTime1 > 0 && + timerData.finishedSince1 > 0) { + if (currentTime - timerData.finishedSince1 > maxTimeDisplay) { + timerData.startTime1 = 0; + timerData.endTime1 = 0; + timerData.finishedSince1 = 0; + timerData.isReady1 = true; + JsonDocument messageDoc; + messageDoc["firstname"] = ""; + messageDoc["lastname"] = ""; + messageDoc["lane"] = "start1"; + String message; + serializeJson(messageDoc, message); + pushUpdateToFrontend(message); + publishLaneStatus(1, "ready"); + Serial.println("Bahn 1 automatisch auf 'Bereit' zurückgesetzt"); + } + } + if (!timerData.isRunning2 && timerData.endTime2 > 0 && + timerData.finishedSince2 > 0) { + if (currentTime - timerData.finishedSince2 > maxTimeDisplay) { + timerData.startTime2 = 0; + timerData.endTime2 = 0; + timerData.finishedSince2 = 0; + timerData.isReady2 = true; + JsonDocument messageDoc; + messageDoc["firstname"] = ""; + messageDoc["lastname"] = ""; + messageDoc["lane"] = "start2"; + String message; + serializeJson(messageDoc, message); + pushUpdateToFrontend(message); + publishLaneStatus(2, "ready"); + Serial.println("Bahn 2 automatisch auf 'Bereit' zurückgesetzt"); + } + } + } else if (gamemode == + 1) { // Competition Mode: Beide Bahnen gemeinsam zurücksetzen + bool bothStopped = !timerData.isRunning1 && !timerData.isRunning2 && + timerData.endTime1 > 0 && timerData.endTime2 > 0 && + timerData.finishedSince1 > 0 && + timerData.finishedSince2 > 0; - if (timerData.isRunning2 && - (currentTime - timerData.localStartTime2 > maxTimeBeforeReset)) { - timerData.isRunning2 = false; - timerData.startTime2 = 0; - publishLaneStatus(2, "ready"); - Serial.println("Bahn 2 automatisch zurückgesetzt"); - } + unsigned long latestFinish = + timerData.finishedSince1 > timerData.finishedSince2 + ? timerData.finishedSince1 + : timerData.finishedSince2; - // Automatischer Reset nach 10 Sekunden "Beendet" - if (!timerData.isRunning1 && timerData.endTime1 > 0 && - timerData.finishedSince1 > 0) { - if (millis() - timerData.finishedSince1 > maxTimeDisplay) { + if (bothStopped && (currentTime - latestFinish > maxTimeDisplay)) { + // Bahn 1 zurücksetzen timerData.startTime1 = 0; timerData.endTime1 = 0; timerData.finishedSince1 = 0; - timerData.isReady1 = true; // Zurücksetzen auf "Bereit" - - JsonDocument messageDoc; - messageDoc["firstname"] = ""; - messageDoc["lastname"] = ""; - messageDoc["lane"] = "start1"; // Add lane information - - String message; - serializeJson(messageDoc, message); - - // Push the message to the frontend - pushUpdateToFrontend(message); + timerData.isReady1 = true; publishLaneStatus(1, "ready"); - Serial.println("Bahn 1 automatisch auf 'Bereit' zurückgesetzt"); - } - } - if (!timerData.isRunning2 && timerData.endTime2 > 0 && - timerData.finishedSince2 > 0) { - if (currentTime - timerData.finishedSince2 > maxTimeDisplay) { + // Bahn 2 zurücksetzen timerData.startTime2 = 0; timerData.endTime2 = 0; timerData.finishedSince2 = 0; - timerData.isReady2 = true; // Zurücksetzen auf "Bereit" - - JsonDocument messageDoc; - messageDoc["firstname"] = ""; - messageDoc["lastname"] = ""; - messageDoc["lane"] = "start2"; // Add lane information - - String message; - serializeJson(messageDoc, message); - - // Push the message to the frontend - pushUpdateToFrontend(message); + timerData.isReady2 = true; publishLaneStatus(2, "ready"); - Serial.println("Bahn 2 automatisch auf 'Bereit' zurückgesetzt"); + + // Optional: Frontend-Update für beide Bahnen + for (int lane = 1; lane <= 2; ++lane) { + JsonDocument messageDoc; + messageDoc["firstname"] = ""; + messageDoc["lastname"] = ""; + messageDoc["lane"] = lane == 1 ? "start1" : "start2"; + String message; + serializeJson(messageDoc, message); + pushUpdateToFrontend(message); + } } } } \ No newline at end of file diff --git a/src/master.cpp b/src/master.cpp index bf472a9..bc784f7 100644 --- a/src/master.cpp +++ b/src/master.cpp @@ -16,16 +16,15 @@ #include #include #include +#include #include #include #include #include #include -#include const char *firmwareversion = "1.0.0"; // Version der Firmware - void saveButtonConfig() { preferences.begin("buttons", false); preferences.putBytes("config", &buttonConfigs, sizeof(buttonConfigs)); @@ -59,6 +58,7 @@ void saveSettings() { preferences.begin("settings", false); preferences.putULong("maxTime", maxTimeBeforeReset); preferences.putULong("maxTimeDisplay", maxTimeDisplay); + preferences.putUInt("gamemode", gamemode); preferences.end(); } @@ -66,6 +66,7 @@ void loadSettings() { preferences.begin("settings", true); maxTimeBeforeReset = preferences.getULong("maxTime", 300000); maxTimeDisplay = preferences.getULong("maxTimeDisplay", 20000); + gamemode = preferences.getUInt("gamemode", 0); preferences.end(); } @@ -117,6 +118,9 @@ String getTimerDataJSON() { } else if (timerData.endTime1 > 0) { doc["time1"] = (timerData.endTime1 - timerData.startTime1) / 1000.0; doc["status1"] = "finished"; + } else if (timerData.isArmed1) { + doc["time1"] = 0; + doc["status1"] = "armed"; // Status für Bahn 1, wenn sie armiert ist } else { doc["time1"] = 0; doc["status1"] = "ready"; @@ -129,6 +133,9 @@ String getTimerDataJSON() { } else if (timerData.endTime2 > 0) { doc["time2"] = (timerData.endTime2 - timerData.startTime2) / 1000.0; doc["status2"] = "finished"; + } else if (timerData.isArmed2) { + doc["time2"] = 0; + doc["status2"] = "armed"; // Status für Bahn 2, wenn sie armiert ist } else { doc["time2"] = 0; doc["status2"] = "ready"; diff --git a/src/master.h b/src/master.h index ac05d97..27fce53 100644 --- a/src/master.h +++ b/src/master.h @@ -25,8 +25,10 @@ struct TimerData { unsigned long bestTime2 = 0; bool isRunning1 = false; bool isRunning2 = false; - bool isReady1 = true; // Status für Bahn 1 - bool isReady2 = true; // Status für Bahn 2 + bool isReady1 = true; // Status für Bahn 1 + bool isReady2 = true; // Status für Bahn 2 + bool isArmed1 = false; // Status für Bahn 1 (armiert/nicht armiert) + bool isArmed2 = false; // Status für Bahn 2 (armiert/nicht armiert) }; // Button Konfiguration