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