refactored main loop, added ready countdown to unpause
This commit is contained in:
@@ -58,10 +58,10 @@ bool buttonBLUETEAMtapout = false;
|
||||
unsigned long PITopenTimestamp = 0;
|
||||
bool PITreleased = false;
|
||||
|
||||
const long PITopenTime = 500; // activate solenoid for 500ms
|
||||
const int countdownTIME = 180; // countdown timer length in seconds, actual countdown for the fight
|
||||
const int countdownToFightTIME = 3; // countdown timer length in seconds, "ready" countdown
|
||||
const int PITreleaseTime = 90; // automatic pit release time in seconds until end of countdown
|
||||
const long PITopenTime = 500; // default: 500 activate solenoid for 500ms
|
||||
const int countdownTIME = 30; // default: 180 countdown timer length in seconds, actual countdown for the fight
|
||||
const int countdownToFightTIME = 3; // default: 3 countdown timer length in seconds, "ready" countdown
|
||||
const int PITreleaseTime = 15; // default: 90 automatic pit release time in seconds until end of countdown
|
||||
bool countdownPAUSED = false;
|
||||
CountDown FightCountDown(CountDown::SECONDS);
|
||||
CountDown ReadyCountDown(CountDown::SECONDS);
|
||||
@@ -79,6 +79,7 @@ int BLINK_INTERVAL = 200;
|
||||
bool ARENA_READY = false;
|
||||
bool REDTEAM_READY = false;
|
||||
bool BLUETEAM_READY = false;
|
||||
bool resumeFight = false;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// ESP-NOW config
|
||||
@@ -189,6 +190,14 @@ void sendTimeDisplay(int MINUTES, int SECONDS, int RED, int GREEN, int BLUE, int
|
||||
}
|
||||
}
|
||||
|
||||
// Global markers for tap out states (non‐blocking sequences)
|
||||
bool redTapOutActive = false;
|
||||
unsigned long redTapOutStartTime = 0;
|
||||
int redTapOutStage = 0;
|
||||
|
||||
bool blueTapOutActive = false;
|
||||
unsigned long blueTapOutStartTime = 0;
|
||||
int blueTapOutStage = 0;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
@@ -280,81 +289,77 @@ void setup() {
|
||||
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// poll all the switch/button inputs
|
||||
pollInput();
|
||||
// deactivate solenoids if needed
|
||||
checkPIT();
|
||||
// Arena Light
|
||||
arenaLIGHT();
|
||||
// update status LEDs
|
||||
statusLEDs();
|
||||
// update Teambutton LEDs
|
||||
updateTEAMLEDs();
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
// start button logic
|
||||
// Handler for the START button logic.
|
||||
void handleStartButton() {
|
||||
if (buttonSTARTvar) {
|
||||
buttonSTARTvar = false;
|
||||
// start logic
|
||||
// Fresh start: no countdown is running, and the fight hasn't been paused.
|
||||
if (!FightCountDown.isRunning() && !rumbleTIME.isRunning() && countdownPAUSED == false) {
|
||||
if (switchRUMBLE.on()) {
|
||||
buttonREDTEAMvar = false;
|
||||
buttonBLUETEAMvar = false;
|
||||
//rumbleTIME.start();
|
||||
ARENA_READY = true;
|
||||
ReadyCountDown.start(countdownToFightTIME);
|
||||
} else if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
||||
}
|
||||
else if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
||||
buttonREDTEAMvar = false;
|
||||
buttonBLUETEAMvar = false;
|
||||
//FightCountDown.start(countdownTIME);
|
||||
ARENA_READY = true;
|
||||
ReadyCountDown.start(countdownToFightTIME);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// resume logic
|
||||
// Resume (unpause) branch: instead of calling FightCountDown.resume() immediately,
|
||||
// we want to display ReadyCountDown first.
|
||||
if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
||||
buttonREDTEAMvar = false;
|
||||
buttonBLUETEAMvar = false;
|
||||
resumeFight = true; // Mark that we want to resume later.
|
||||
countdownPAUSED = false;
|
||||
FightCountDown.resume();
|
||||
} else if (switchRUMBLE.on()) {
|
||||
ARENA_READY = true;
|
||||
ReadyCountDown.start(countdownToFightTIME);
|
||||
}
|
||||
else if (switchRUMBLE.on()) {
|
||||
buttonREDTEAMvar = false;
|
||||
buttonBLUETEAMvar = false;
|
||||
resumeFight = true;
|
||||
countdownPAUSED = false;
|
||||
rumbleTIME.start();
|
||||
ARENA_READY = true;
|
||||
ReadyCountDown.start(countdownToFightTIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
// forced start of countdown
|
||||
}
|
||||
|
||||
// Handler for the forced start button logic.
|
||||
void handleForcedStartButton() {
|
||||
if (buttonSTARTforced) {
|
||||
buttonSTARTforced = false;
|
||||
if (!FightCountDown.isRunning() && !rumbleTIME.isRunning() && countdownPAUSED == false) {
|
||||
buttonREDTEAMvar = false;
|
||||
buttonBLUETEAMvar = false;
|
||||
if (!switchRUMBLE.on()) {
|
||||
//FightCountDown.start(countdownTIME);
|
||||
ARENA_READY = true;
|
||||
REDTEAM_LED(true);
|
||||
BLUETEAM_LED(true);
|
||||
ReadyCountDown.start(countdownToFightTIME);
|
||||
} else if (switchRUMBLE.on()) {
|
||||
//rumbleTIME.start();
|
||||
ARENA_READY = true;
|
||||
ReadyCountDown.start(countdownToFightTIME);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// forced resume logic
|
||||
buttonREDTEAMvar = false;
|
||||
buttonBLUETEAMvar = false;
|
||||
resumeFight = true;
|
||||
countdownPAUSED = false;
|
||||
if (!switchRUMBLE.on()) {
|
||||
FightCountDown.resume();
|
||||
} else if (switchRUMBLE.on()) {
|
||||
rumbleTIME.start();
|
||||
ARENA_READY = true;
|
||||
REDTEAM_LED(true);
|
||||
BLUETEAM_LED(true);
|
||||
ReadyCountDown.start(countdownToFightTIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
// pause button logic
|
||||
}
|
||||
|
||||
// Handler for the pause button logic.
|
||||
void handlePauseButton() {
|
||||
if (buttonPAUSEvar) {
|
||||
buttonPAUSEvar = false;
|
||||
if (FightCountDown.isRunning()) {
|
||||
@@ -366,90 +371,181 @@ void loop() {
|
||||
rumbleTIME.stop();
|
||||
}
|
||||
}
|
||||
// pit button logic
|
||||
}
|
||||
|
||||
// Handler for the pit button logic.
|
||||
void handlePitButton() {
|
||||
if (buttonPITvar) {
|
||||
buttonPITvar = false;
|
||||
buttonPIThold = false;
|
||||
openPITmanually();
|
||||
}
|
||||
// automatic pit release
|
||||
if (FightCountDown.remaining() <= PITreleaseTime && FightCountDown.remaining() != 0 && !switchRUMBLE.on() && switchPIT.on() && buttonPIThold == false) {
|
||||
openPIT();
|
||||
}
|
||||
if (rumbleTIME.elapsed() >= PITreleaseTime && switchRUMBLE.on() && switchPIT.on() && buttonPIThold == false) {
|
||||
openPIT();
|
||||
}
|
||||
}
|
||||
|
||||
// tap out logic
|
||||
if (buttonREDTEAMtapout && !switchRUMBLE.on()) {
|
||||
// check for automatic pit release.
|
||||
void handleAutoPitRelease() {
|
||||
// Only release the pit if it hasn't already been released.
|
||||
if (!PITreleased) {
|
||||
if (FightCountDown.remaining() <= PITreleaseTime && FightCountDown.remaining() != 0 &&
|
||||
!switchRUMBLE.on() && switchPIT.on() && buttonPIThold == false) {
|
||||
openPIT();
|
||||
}
|
||||
else if (rumbleTIME.elapsed() >= PITreleaseTime && switchRUMBLE.on() &&
|
||||
switchPIT.on() && buttonPIThold == false) {
|
||||
openPIT();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for transitioning from ReadyCountDown to the fight (or rumble) countdown.
|
||||
void handleCountdownTransition() {
|
||||
if (ReadyCountDown.remaining() == 0 && ARENA_READY) {
|
||||
ARENA_READY = false;
|
||||
REDTEAM_LED(false);
|
||||
BLUETEAM_LED(false);
|
||||
if (!switchRUMBLE.on()) {
|
||||
if (resumeFight) {
|
||||
FightCountDown.resume(); // Resume the paused fight countdown.
|
||||
resumeFight = false;
|
||||
}
|
||||
else {
|
||||
FightCountDown.start(countdownTIME); // Fresh start.
|
||||
}
|
||||
}
|
||||
else if (switchRUMBLE.on()) {
|
||||
// For the rumble branch, you may decide if a resume is relevant.
|
||||
// Here we simply start the rumble timer as before.
|
||||
rumbleTIME.start();
|
||||
resumeFight = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The display update logic now considers all conditions in order.
|
||||
void updateDisplay() {
|
||||
if (ReadyCountDown.isRunning()) {
|
||||
sendTimeDisplay((ReadyCountDown.remaining()/60 % 60), (ReadyCountDown.remaining()%60), 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||
} else if (switchRUMBLE.on()) {
|
||||
sendTimeDisplay((rumbleTIME.elapsed()/60 % 60), (rumbleTIME.elapsed()%60), 0, 255, 255, CLOCK_LED_BRIGHTNESS);
|
||||
} else if (!FightCountDown.isRunning() && !countdownPAUSED) {
|
||||
// Choose green if both team buttons are active; otherwise, choose magenta.
|
||||
if (buttonREDTEAMvar && buttonBLUETEAMvar) {
|
||||
sendTimeDisplay((countdownTIME/60 % 60), (countdownTIME%60), 0, 255, 0, CLOCK_LED_BRIGHTNESS);
|
||||
} else {
|
||||
sendTimeDisplay((countdownTIME/60 % 60), (countdownTIME%60), 255, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
} else {
|
||||
// choose yellow if countdown is paused and both teams aren't ready
|
||||
if (countdownPAUSED && (!buttonREDTEAMvar || !buttonBLUETEAMvar)) {
|
||||
sendTimeDisplay((FightCountDown.remaining()/60 % 60), (FightCountDown.remaining()%60), 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||
} else {
|
||||
sendTimeDisplay((FightCountDown.remaining()/60 % 60), (FightCountDown.remaining()%60), 0, 255, 0, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Redesigned endless cycling for Red Team tap-out.
|
||||
void handleRedTapOut() {
|
||||
// When the red tap-out is first triggered.
|
||||
if (!redTapOutActive && buttonREDTEAMtapout && !switchRUMBLE.on() && !blueTapOutActive) {
|
||||
buttonREDTEAMtapout = false;
|
||||
countdownPAUSED = true;
|
||||
FightCountDown.stop();
|
||||
REDTEAM_LED(true);
|
||||
sendTimeDisplay(99, 0, 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||
delay(1500);
|
||||
sendTimeDisplay(0, 99, 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||
delay(1500);
|
||||
sendTimeDisplay((FightCountDown.remaining()/60%60), (FightCountDown.remaining()%60), 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||
delay(7000);
|
||||
redTapOutActive = true;
|
||||
redTapOutStartTime = millis();
|
||||
}
|
||||
if (buttonBLUETEAMtapout && !switchRUMBLE.on()) {
|
||||
|
||||
// If tap-out is active, continuously update the display in a cycle.
|
||||
if (redTapOutActive) {
|
||||
// Define a full cycle period of 10'000 ms.
|
||||
const unsigned long cycleDuration = 10000;
|
||||
// Compute how far into the current cycle we are.
|
||||
unsigned long cycleTime = (millis() - redTapOutStartTime) % cycleDuration;
|
||||
|
||||
if (cycleTime < 1500) {
|
||||
// Stage 1 (0 - 1500ms): Display first tap-out message.
|
||||
sendTimeDisplay(99, 0, 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
else if (cycleTime < 3000) {
|
||||
// Stage 2 (1500 - 3000ms): Display second tap-out message.
|
||||
sendTimeDisplay(0, 99, 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
else {
|
||||
// Stage 3 (3000 - 10'000ms): Show the remaining fight countdown.
|
||||
sendTimeDisplay((FightCountDown.remaining() / 60 % 60), (FightCountDown.remaining() % 60), 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Redesigned endless cycling for Blue Team tap-out.
|
||||
void handleBlueTapOut() {
|
||||
// When the blue tap-out is first triggered.
|
||||
if (!blueTapOutActive && buttonBLUETEAMtapout && !switchRUMBLE.on() && !redTapOutActive) {
|
||||
buttonBLUETEAMtapout = false;
|
||||
countdownPAUSED = true;
|
||||
FightCountDown.stop();
|
||||
BLUETEAM_LED(true);
|
||||
sendTimeDisplay(99, 0, 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||
delay(1500);
|
||||
sendTimeDisplay(0, 99, 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||
delay(1500);
|
||||
sendTimeDisplay((FightCountDown.remaining()/60%60), (FightCountDown.remaining()%60), 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||
delay(1500);
|
||||
blueTapOutActive = true;
|
||||
blueTapOutStartTime = millis();
|
||||
}
|
||||
|
||||
// reset button logic
|
||||
// If tap-out is active, continuously update the display in a cycle.
|
||||
if (blueTapOutActive) {
|
||||
// Define a full cycle period of 10'000 ms.
|
||||
const unsigned long cycleDuration = 10000;
|
||||
// Compute the cycle progress.
|
||||
unsigned long cycleTime = (millis() - blueTapOutStartTime) % cycleDuration;
|
||||
|
||||
if (cycleTime < 1500) {
|
||||
// Stage 1 (0 - 1500ms): Display first tap-out message.
|
||||
sendTimeDisplay(99, 0, 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
else if (cycleTime < 3000) {
|
||||
// Stage 2 (1500 - 3000ms): Display second tap-out message.
|
||||
sendTimeDisplay(0, 99, 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
else {
|
||||
// Stage 3 (3000 - 10'000ms): Show the remaining fight countdown.
|
||||
sendTimeDisplay((FightCountDown.remaining() / 60 % 60), (FightCountDown.remaining() % 60), 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
void loop() {
|
||||
// Poll and update low-level I/O and LEDs.
|
||||
pollInput();
|
||||
checkPIT();
|
||||
arenaLIGHT();
|
||||
statusLEDs();
|
||||
updateTEAMLEDs();
|
||||
|
||||
// Process button events.
|
||||
handleStartButton();
|
||||
handleForcedStartButton();
|
||||
handlePauseButton();
|
||||
handlePitButton();
|
||||
handleAutoPitRelease();
|
||||
|
||||
// Process non-blocking tap-out sequences.
|
||||
handleRedTapOut();
|
||||
handleBlueTapOut();
|
||||
|
||||
// Handle reset
|
||||
if (buttonRESETvar) {
|
||||
buttonRESETvar = false;
|
||||
PITreleased = false;
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
// Ready Countdown to Fight Countdown transition
|
||||
if (ReadyCountDown.remaining() == 0 && ARENA_READY) {
|
||||
ARENA_READY = false;
|
||||
REDTEAM_LED(false);
|
||||
BLUETEAM_LED(false);
|
||||
if (!switchRUMBLE.on()) {
|
||||
FightCountDown.start(countdownTIME);
|
||||
} else if (switchRUMBLE.on()) {
|
||||
rumbleTIME.start();
|
||||
}
|
||||
}
|
||||
// Transition from ReadyCountDown to the appropriate fight countdown.
|
||||
handleCountdownTransition();
|
||||
|
||||
// If either team has tapped out, skip updating the display.
|
||||
if (buttonREDTEAMtapout || buttonBLUETEAMtapout) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Display the Ready CountDown timer if it is running.
|
||||
if (ReadyCountDown.isRunning()) {
|
||||
sendTimeDisplay((ReadyCountDown.remaining()/60%60), (ReadyCountDown.remaining()%60), 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||
return;
|
||||
}
|
||||
|
||||
// When the RUMBLE switch is active, always show the rumble timer.
|
||||
if (switchRUMBLE.on()) {
|
||||
sendTimeDisplay((rumbleTIME.elapsed()/60%60), (rumbleTIME.elapsed()%60), 0, 255, 255, CLOCK_LED_BRIGHTNESS);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the fight countdown isn't running and isn't paused, determine which countdown color to use.
|
||||
if (!FightCountDown.isRunning() && !countdownPAUSED) {
|
||||
// Choose green if both buttons are active; otherwise, choose magenta.
|
||||
if (buttonREDTEAMvar && buttonBLUETEAMvar) {
|
||||
sendTimeDisplay((countdownTIME/60%60), (countdownTIME%60), 0, 255, 0, CLOCK_LED_BRIGHTNESS);
|
||||
} else {
|
||||
sendTimeDisplay((countdownTIME/60%60), (countdownTIME%60), 255, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, show the fight countdown timer.
|
||||
sendTimeDisplay((FightCountDown.remaining()/60%60), (FightCountDown.remaining()%60), 0, 255, 0, CLOCK_LED_BRIGHTNESS);
|
||||
// When no team is in a tap‐out sequence, update the display.
|
||||
if (!redTapOutActive && !blueTapOutActive) {
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user