Compare commits
3
Commits
4698dd7d42
...
606219b8bd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
606219b8bd | ||
|
|
d93b283d2c | ||
|
|
c9c4b1c1c5 |
@@ -3,7 +3,6 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
||||||
#include <Preferences.h> // automatically installed for ESP32 boards
|
#include <Preferences.h> // automatically installed for ESP32 boards
|
||||||
#include <FastLED.h> // https://fastled.io/
|
|
||||||
#include <avdweb_Switch.h> // https://github.com/avdwebLibraries/avdweb_Switch
|
#include <avdweb_Switch.h> // https://github.com/avdwebLibraries/avdweb_Switch
|
||||||
#include <CountDown.h> // https://github.com/RobTillaart/CountDown
|
#include <CountDown.h> // https://github.com/RobTillaart/CountDown
|
||||||
#include <StopWatch.h> // https://github.com/RobTillaart/StopWatch_RT
|
#include <StopWatch.h> // https://github.com/RobTillaart/StopWatch_RT
|
||||||
@@ -58,10 +57,10 @@ bool buttonBLUETEAMtapout = false;
|
|||||||
unsigned long PITopenTimestamp = 0;
|
unsigned long PITopenTimestamp = 0;
|
||||||
bool PITreleased = false;
|
bool PITreleased = false;
|
||||||
|
|
||||||
const long PITopenTime = 500; // activate solenoid for 500ms
|
const long PITopenTime = 500; // default: 500 activate solenoid for 500ms
|
||||||
const int countdownTIME = 180; // countdown timer length in seconds, actual countdown for the fight
|
const int countdownTIME = 180; // default: 180 countdown timer length in seconds, actual countdown for the fight
|
||||||
const int countdownToFightTIME = 3; // countdown timer length in seconds, "ready" countdown
|
const int countdownToFightTIME = 3; // default: 3 countdown timer length in seconds, "ready" countdown
|
||||||
const int PITreleaseTime = 90; // automatic pit release time in seconds until end of countdown
|
const int PITreleaseTime = 90; // default: 90 automatic pit release time in seconds until end of countdown
|
||||||
bool countdownPAUSED = false;
|
bool countdownPAUSED = false;
|
||||||
CountDown FightCountDown(CountDown::SECONDS);
|
CountDown FightCountDown(CountDown::SECONDS);
|
||||||
CountDown ReadyCountDown(CountDown::SECONDS);
|
CountDown ReadyCountDown(CountDown::SECONDS);
|
||||||
@@ -79,6 +78,7 @@ int BLINK_INTERVAL = 200;
|
|||||||
bool ARENA_READY = false;
|
bool ARENA_READY = false;
|
||||||
bool REDTEAM_READY = false;
|
bool REDTEAM_READY = false;
|
||||||
bool BLUETEAM_READY = false;
|
bool BLUETEAM_READY = false;
|
||||||
|
bool resumeFight = false;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// ESP-NOW config
|
// ESP-NOW config
|
||||||
@@ -163,13 +163,19 @@ void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// RED team button
|
// RED team button
|
||||||
buttonREDTEAMvar = receiveDATA.buttonREDTEAM;
|
// ignore button input if in rumble mode
|
||||||
buttonREDTEAMtapout = receiveDATA.buttonREDTEAMtapout;
|
if (!switchRUMBLE.on()) {
|
||||||
|
buttonREDTEAMvar = receiveDATA.buttonREDTEAM;
|
||||||
|
buttonREDTEAMtapout = receiveDATA.buttonREDTEAMtapout;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
// BLUE team button
|
// BLUE team button
|
||||||
buttonBLUETEAMvar = receiveDATA.buttonBLUETEAM;
|
// ignore button input if in rumble mode
|
||||||
buttonBLUETEAMtapout = receiveDATA.buttonBLUETEAMtapout;
|
if (!switchRUMBLE.on()) {
|
||||||
|
buttonBLUETEAMvar = receiveDATA.buttonBLUETEAM;
|
||||||
|
buttonBLUETEAMtapout = receiveDATA.buttonBLUETEAMtapout;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,6 +195,23 @@ void sendTimeDisplay(int MINUTES, int SECONDS, int RED, int GREEN, int BLUE, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global Vars for tap out states
|
||||||
|
bool redTapOutActive = false;
|
||||||
|
unsigned long redTapOutStartTime = 0;
|
||||||
|
int redTapOutStage = 0;
|
||||||
|
|
||||||
|
bool blueTapOutActive = false;
|
||||||
|
unsigned long blueTapOutStartTime = 0;
|
||||||
|
int blueTapOutStage = 0;
|
||||||
|
|
||||||
|
// Global Vars for Fight end
|
||||||
|
bool fightStarted = false;
|
||||||
|
bool fightEnded = false;
|
||||||
|
const int END_BLINK_COUNT = 3;
|
||||||
|
const unsigned long END_BLINK_INTERVAL = 500; // in milliseconds
|
||||||
|
int endBlinkTransitions = 0;
|
||||||
|
bool endBlinkState = false;
|
||||||
|
unsigned long lastEndBlinkTime = 0;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -280,81 +303,85 @@ void setup() {
|
|||||||
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
|
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) {
|
if (buttonSTARTvar) {
|
||||||
buttonSTARTvar = false;
|
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 (!FightCountDown.isRunning() && !rumbleTIME.isRunning() && countdownPAUSED == false) {
|
||||||
if (switchRUMBLE.on()) {
|
if (switchRUMBLE.on()) {
|
||||||
buttonREDTEAMvar = false;
|
buttonREDTEAMvar = false;
|
||||||
buttonBLUETEAMvar = false;
|
buttonBLUETEAMvar = false;
|
||||||
//rumbleTIME.start();
|
|
||||||
ARENA_READY = true;
|
ARENA_READY = true;
|
||||||
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
ReadyCountDown.start(countdownToFightTIME);
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
} else if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
}
|
||||||
|
else if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
||||||
buttonREDTEAMvar = false;
|
buttonREDTEAMvar = false;
|
||||||
buttonBLUETEAMvar = false;
|
buttonBLUETEAMvar = false;
|
||||||
//FightCountDown.start(countdownTIME);
|
|
||||||
ARENA_READY = true;
|
ARENA_READY = true;
|
||||||
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
ReadyCountDown.start(countdownToFightTIME);
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// resume logic
|
// Resume (unpause) branch: instead of calling FightCountDown.resume() immediately,
|
||||||
|
// we want to display ReadyCountDown first.
|
||||||
if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
||||||
buttonREDTEAMvar = false;
|
buttonREDTEAMvar = false;
|
||||||
buttonBLUETEAMvar = false;
|
buttonBLUETEAMvar = false;
|
||||||
|
resumeFight = true; // Mark that we want to resume later.
|
||||||
countdownPAUSED = false;
|
countdownPAUSED = false;
|
||||||
FightCountDown.resume();
|
ARENA_READY = true;
|
||||||
} else if (switchRUMBLE.on()) {
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
|
}
|
||||||
|
else if (switchRUMBLE.on()) {
|
||||||
buttonREDTEAMvar = false;
|
buttonREDTEAMvar = false;
|
||||||
buttonBLUETEAMvar = false;
|
buttonBLUETEAMvar = false;
|
||||||
|
resumeFight = true;
|
||||||
countdownPAUSED = false;
|
countdownPAUSED = false;
|
||||||
rumbleTIME.start();
|
ARENA_READY = true;
|
||||||
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// forced start of countdown
|
}
|
||||||
|
|
||||||
|
// Handler for the forced start button logic.
|
||||||
|
void handleForcedStartButton() {
|
||||||
if (buttonSTARTforced) {
|
if (buttonSTARTforced) {
|
||||||
buttonSTARTforced = false;
|
buttonSTARTforced = false;
|
||||||
if (!FightCountDown.isRunning() && !rumbleTIME.isRunning() && countdownPAUSED == false) {
|
if (!FightCountDown.isRunning() && !rumbleTIME.isRunning() && countdownPAUSED == false) {
|
||||||
buttonREDTEAMvar = false;
|
buttonREDTEAMvar = false;
|
||||||
buttonBLUETEAMvar = false;
|
buttonBLUETEAMvar = false;
|
||||||
if (!switchRUMBLE.on()) {
|
ARENA_READY = true;
|
||||||
//FightCountDown.start(countdownTIME);
|
REDTEAM_LED(true);
|
||||||
ARENA_READY = true;
|
BLUETEAM_LED(true);
|
||||||
ReadyCountDown.start(countdownToFightTIME);
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
} else if (switchRUMBLE.on()) {
|
|
||||||
//rumbleTIME.start();
|
|
||||||
ARENA_READY = true;
|
|
||||||
ReadyCountDown.start(countdownToFightTIME);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// forced resume logic
|
|
||||||
buttonREDTEAMvar = false;
|
buttonREDTEAMvar = false;
|
||||||
buttonBLUETEAMvar = false;
|
buttonBLUETEAMvar = false;
|
||||||
|
resumeFight = true;
|
||||||
countdownPAUSED = false;
|
countdownPAUSED = false;
|
||||||
if (!switchRUMBLE.on()) {
|
ARENA_READY = true;
|
||||||
FightCountDown.resume();
|
REDTEAM_LED(true);
|
||||||
} else if (switchRUMBLE.on()) {
|
BLUETEAM_LED(true);
|
||||||
rumbleTIME.start();
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// pause button logic
|
}
|
||||||
|
|
||||||
|
// Handler for the pause button logic.
|
||||||
|
void handlePauseButton() {
|
||||||
if (buttonPAUSEvar) {
|
if (buttonPAUSEvar) {
|
||||||
buttonPAUSEvar = false;
|
buttonPAUSEvar = false;
|
||||||
if (FightCountDown.isRunning()) {
|
if (FightCountDown.isRunning()) {
|
||||||
@@ -366,90 +393,230 @@ void loop() {
|
|||||||
rumbleTIME.stop();
|
rumbleTIME.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// pit button logic
|
}
|
||||||
|
|
||||||
|
// Handler for the pit button logic.
|
||||||
|
void handlePitButton() {
|
||||||
if (buttonPITvar) {
|
if (buttonPITvar) {
|
||||||
buttonPITvar = false;
|
buttonPITvar = false;
|
||||||
buttonPIThold = false;
|
buttonPIThold = false;
|
||||||
openPITmanually();
|
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
|
// check for automatic pit release.
|
||||||
if (buttonREDTEAMtapout && !switchRUMBLE.on()) {
|
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.
|
||||||
|
fightStarted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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()) {
|
||||||
|
// Display Ready Countdown in Yellow
|
||||||
|
sendTimeDisplay((ReadyCountDown.remaining()/60 % 60), (ReadyCountDown.remaining()%60), 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
|
} else if (switchRUMBLE.on()) {
|
||||||
|
// Display the Rumble Timer
|
||||||
|
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 {
|
||||||
|
// Display the countdown in green
|
||||||
|
sendTimeDisplay((FightCountDown.remaining()/60 % 60), (FightCountDown.remaining()%60), 0, 255, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
countdownPAUSED = true;
|
||||||
FightCountDown.stop();
|
FightCountDown.stop();
|
||||||
REDTEAM_LED(true);
|
REDTEAM_LED(true);
|
||||||
sendTimeDisplay(99, 0, 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
redTapOutActive = true;
|
||||||
delay(1500);
|
redTapOutStartTime = millis();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
if (buttonBLUETEAMtapout && !switchRUMBLE.on()) {
|
|
||||||
|
// If tap-out is active, continuously update the display in a cycle.
|
||||||
|
if (redTapOutActive) {
|
||||||
|
// Define a full cycle period of 8'000 ms.
|
||||||
|
const unsigned long cycleDuration = 8000;
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
countdownPAUSED = true;
|
||||||
FightCountDown.stop();
|
FightCountDown.stop();
|
||||||
BLUETEAM_LED(true);
|
BLUETEAM_LED(true);
|
||||||
sendTimeDisplay(99, 0, 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
blueTapOutActive = true;
|
||||||
delay(1500);
|
blueTapOutStartTime = millis();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset button logic
|
// If tap-out is active, continuously update the display in a cycle.
|
||||||
|
if (blueTapOutActive) {
|
||||||
|
// Define a full cycle period of 8'000 ms.
|
||||||
|
const unsigned long cycleDuration = 8000;
|
||||||
|
// 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 handleFightEnd() {
|
||||||
|
// When the countdown hits 0 and the fight had started, mark it as ended.
|
||||||
|
if ((FightCountDown.remaining() == 0) && fightStarted) {
|
||||||
|
fightEnded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only do blinking if the fight has ended.
|
||||||
|
if (!fightEnded) {
|
||||||
|
return; // Skip the rest until fightEnded becomes true.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each full blink cycle includes an "on" and "off" state.
|
||||||
|
// Therefore, we count transitions: total transitions = END_BLINK_COUNT * 2.
|
||||||
|
const int totalTransitions = END_BLINK_COUNT * 2 + 1;
|
||||||
|
|
||||||
|
// If we haven't completed our full blink sequence, manage timing:
|
||||||
|
if (endBlinkTransitions < totalTransitions) {
|
||||||
|
unsigned long currentMillis = millis();
|
||||||
|
if (currentMillis - lastEndBlinkTime >= END_BLINK_INTERVAL) {
|
||||||
|
endBlinkState = !endBlinkState; // Toggle between on and off states.
|
||||||
|
endBlinkTransitions++; // Count this toggle.
|
||||||
|
lastEndBlinkTime = currentMillis; // Reset the timer.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depending on the blink state, update the display.
|
||||||
|
// When endBlinkState is true, use the normal brightness.
|
||||||
|
// When false, replace CLOCK_LED_BRIGHTNESS with 0 to blank the display.
|
||||||
|
if (endBlinkState) {
|
||||||
|
sendTimeDisplay(0, 0, 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
|
} else {
|
||||||
|
sendTimeDisplay(0, 0, 255, 165, 0, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// After completing the blink sequence, ensure that the display remains on.
|
||||||
|
sendTimeDisplay(0, 0, 255, 165, 0, 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 tap-out sequences.
|
||||||
|
if (!switchRUMBLE.on()) {
|
||||||
|
handleRedTapOut();
|
||||||
|
handleBlueTapOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle reset
|
||||||
if (buttonRESETvar) {
|
if (buttonRESETvar) {
|
||||||
buttonRESETvar = false;
|
buttonRESETvar = false;
|
||||||
PITreleased = false;
|
PITreleased = false;
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ready Countdown to Fight Countdown transition
|
// Transition from ReadyCountDown to the appropriate fight countdown.
|
||||||
if (ReadyCountDown.remaining() == 0 && ARENA_READY) {
|
handleCountdownTransition();
|
||||||
ARENA_READY = false;
|
|
||||||
REDTEAM_LED(false);
|
|
||||||
BLUETEAM_LED(false);
|
|
||||||
if (!switchRUMBLE.on()) {
|
|
||||||
FightCountDown.start(countdownTIME);
|
|
||||||
} else if (switchRUMBLE.on()) {
|
|
||||||
rumbleTIME.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If either team has tapped out, skip updating the display.
|
// End display
|
||||||
if (buttonREDTEAMtapout || buttonBLUETEAMtapout) {
|
handleFightEnd();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display the Ready CountDown timer if it is running.
|
// When no team is in a tap‐out sequence and fight hasn't ended, update the display.
|
||||||
if (ReadyCountDown.isRunning()) {
|
if (!redTapOutActive && !blueTapOutActive && !fightEnded) {
|
||||||
sendTimeDisplay((ReadyCountDown.remaining()/60%60), (ReadyCountDown.remaining()%60), 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
updateDisplay();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ const int COLONArray [] = {224,225,226,227,228,229,230,231};
|
|||||||
|
|
||||||
// tap out
|
// tap out
|
||||||
const int LitArrayTap [] = {0,1,2,3,4,5,6,7,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151};
|
const int LitArrayTap [] = {0,1,2,3,4,5,6,7,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151};
|
||||||
const int LitArrayOut [] = {0,1,2,3,4,5,6,7,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159};
|
//const int LitArrayOut [] = {0,1,2,3,4,5,6,7,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159};
|
||||||
|
const int LitArrayOut [] = {56,57,58,59,60,61,62,63,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215};
|
||||||
|
|
||||||
|
|
||||||
// set digits of the timer/clock, use: setDIGIT(<digit ID>, <Number>, <red channel intensity 0-255>, <green channel intensity 0-255>, <blue channel intensity 0-255>)
|
// set digits of the timer/clock, use: setDIGIT(<digit ID>, <Number>, <red channel intensity 0-255>, <green channel intensity 0-255>, <blue channel intensity 0-255>)
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#define ACTUATED_PULSE 1000 // Actuated position
|
#define ACTUATED_PULSE 1000 // Actuated position
|
||||||
|
|
||||||
// Define the reset time in milliseconds
|
// Define the reset time in milliseconds
|
||||||
#define RESET_TIME_MS 500
|
#define RESET_TIME_MS 1000
|
||||||
|
|
||||||
// Create two Servo objects for the two servos
|
// Create two Servo objects for the two servos
|
||||||
Servo servo1;
|
Servo servo1;
|
||||||
|
|||||||
Reference in New Issue
Block a user