/*
* SLAVE per catena gioco (5 nodi identici)
*
* Funzione generale: Ogni slave rappresenta due fasi/enigmi fisici consecutivi in una catena sequenziale.
* - Ascolta il segnale di avvio dal master (per Slave1) o dallo slave precedente (per gli altri).
* - Se riceve HIGH stabile, avvia la sequenza: preparazione (ACTIVE), fase 1, fase 2.
* - Al completamento positivo di fase 2, attiva il successivo slave con HIGH su END_SIGNAL.
* - In stato END, replica continuamente lo stato del segnale in ingresso sull'uscita per propagare eventuali stop.
* - Se riceve LOW stabile durante le fasi attive, interrompe tutto e va in END senza attivare il successivo.
*
* Collegamenti hardware:
* - PIN_MASTER_SIGNAL (2): INPUT dal master/slave precedente (HIGH = avvia).
* - PIN_END_SIGNAL (A0): OUTPUT verso slave successivo (HIGH = avvia successivo).
* - PIN_ACTIVE_LED (13): OUTPUT per LED indicatore di attività (HIGH = attivo).
*
* Nota: Il debounce è a 300 ms per robustezza contro rumori/rimbalzi su segnali digitali.
* Le funzioni phase1/phase2 sono placeholder da riempire con logica reale (es. sensori, timer variabili).
* ACTIVE è uno stato transitorio: esegue azioni di preparazione una sola volta e passa immediatamente a PHASE1.
*/
// Definizione costanti: pin e debounce
constexpr uint8_t PIN_MASTER_SIGNAL = 2; // Input: segnale di comando dal master o slave precedente (HIGH = avvia/stop inverso)
constexpr uint8_t PIN_END_SIGNAL = A0; // Output: segnale verso slave successivo (HIGH = attivato dopo completamento positivo)
constexpr uint8_t PIN_ACTIVE_LED = 13; // Output: LED indicatore di attività slave (HIGH = slave in esecuzione)
constexpr uint32_t DEBOUNCE_MS = 300; // Tempo debounce in ms: ignora cambiamenti brevi per evitare falsi avvii/stop
// Enumerazione stati: definisce i possibili stati della macchina a stati dello slave
enum class SlaveState : uint8_t { // Uso enum class per scope sicuro e tipizzazione forte
IDLE, // In attesa di avvio (segnale HIGH stabile)
ACTIVE, // Transitorio: preparazione immediata all'avvio (eseguita una volta sola)
PHASE1, // Prima fase fisica/enigma (da implementare)
PHASE2, // Seconda fase fisica/enigma (da implementare)
END // Fine: completamento o stop, con replica segnale per propagazione
};
// Struttura Slave: contiene lo stato corrente e il timestamp di inizio fase
struct Slave {
SlaveState state = SlaveState::IDLE; // Stato iniziale: IDLE
uint32_t phaseStart = 0; // Timestamp millis() di inizio fase corrente
} slave; // Istanza globale: slave
// Funzione phase1: controlla se la fase 1 è completata
// - Confronta tempo trascorso con un placeholder (5 secondi)
// - Da riempire con logica reale (es. sensori, input utente, timer dinamici)
// - Ritorna false se non completata, true se sì (transizione a PHASE2)
bool phase1(uint32_t now) {
if (now - slave.phaseStart < 5000) { //5 sec placeholder
// ToDo: fase 1
return false; // Non completato
}
return true; // Completato
}
// Funzione phase2: controlla se la fase 2 è completata
// - Simile a phase1, placeholder 5 secondi
// - Da riempire con logica reale
// - Ritorna true per transizione a END e attivazione successivo
bool phase2(uint32_t now) {
if (now - slave.phaseStart < 5000) { //5 sec placeholder
// ToDo: fase 2
return false; // Non completato
}
return true; // Completato
}
// Setup: inizializzazione hardware
// - Configura pin: input per segnale master, output per end signal e LED
// - Imposta stati iniziali LOW per output (stato definito e sicuro)
void setup() {
pinMode(PIN_MASTER_SIGNAL, INPUT);
pinMode(PIN_END_SIGNAL, OUTPUT);
pinMode(PIN_ACTIVE_LED, OUTPUT);
digitalWrite(PIN_ACTIVE_LED, LOW);
digitalWrite(PIN_END_SIGNAL, LOW);
}
// Loop principale: eseguito continuamente
// - Legge tempo corrente (millis()) e segnale input
// - Gestisce debounce per avvio e stop
// - Esegue la macchina a stati
void loop() {
uint32_t now = millis(); // Tempo corrente in ms dal reset (non overflow-safe per run >49 giorni, ma ok per gioco breve)
static bool prevIdle = false; // Stato precedente segnale per debounce avvio (false = LOW iniziale)
static uint32_t edgeTimeIdle = 0; // Timestamp ultimo cambio per avvio
static bool prevStop = true; // Stato precedente per stop (true = HIGH iniziale)
static uint32_t edgeTimeStop = 0; // Timestamp ultimo cambio per stop
bool sig = digitalRead(PIN_MASTER_SIGNAL); // Lettura segnale input: HIGH o LOW
// Gestione avvio da IDLE: rileva HIGH stabile
// - Se cambio segnale, aggiorna prevIdle e timestamp
// - Se HIGH per >= DEBOUNCE_MS, avvia ACTIVE e accende LED
if (slave.state == SlaveState::IDLE) {
if (sig != prevIdle) {
prevIdle = sig;
edgeTimeIdle = now;
}
if (sig && (now - edgeTimeIdle >= DEBOUNCE_MS)) {
slave.state = SlaveState::ACTIVE;
slave.phaseStart = now;
digitalWrite(PIN_ACTIVE_LED, HIGH);
}
}
// Gestione stop anticipato: rileva LOW stabile in stati non-END
// - Se cambio segnale, aggiorna prevStop
// - Se LOW per >= DEBOUNCE_MS, forza END e spegne LED (senza attivare successivo)
else if (slave.state != SlaveState::END) {
if (sig != prevStop) {
prevStop = sig;
if (!sig) {
edgeTimeStop = now;
}
}
if (!sig && (now - edgeTimeStop >= DEBOUNCE_MS)) {
slave.state = SlaveState::END;
digitalWrite(PIN_ACTIVE_LED, LOW);
}
}
// Macchina a stati: switch su stato corrente
// - Esegue azioni specifiche per ogni stato
// - Transizioni basate su completamento o tempo
switch (slave.state) {
case SlaveState::IDLE:
// ToDo: in attesa della partenza
// - Nessuna azione: solo attesa HIGH stabile
break;
case SlaveState::ACTIVE:
// ToDo: preparazione
// - Azioni eseguite UNA SOLA VOLTA all'avvio stabile
// - Esempi: reset sensori, avvio suoni, posizionamento iniziale
// - Transizione immediata a PHASE1 (stato transitorio)
slave.state = SlaveState::PHASE1;
slave.phaseStart = now;
break;
case SlaveState::PHASE1:
// Controlla completamento fase 1
// - Se true, transizione a PHASE2 con reset timestamp
if (phase1(now)) {
slave.state = SlaveState::PHASE2;
slave.phaseStart = now;
}
break;
case SlaveState::PHASE2:
// Controlla completamento fase 2
// - Se true, transizione a END, spegne LED, attiva successivo con HIGH
if (phase2(now)) {
slave.state = SlaveState::END;
digitalWrite(PIN_ACTIVE_LED, LOW);
digitalWrite(PIN_END_SIGNAL, HIGH);
}
break;
case SlaveState::END:
// Fine positiva o stop: replica segnale input su output
// - Se input HIGH, mantiene HIGH output (successivo attivo)
// - Se input LOW, mette LOW output (propaga stop a successivo)
bool master_is_high = digitalRead(PIN_MASTER_SIGNAL);
digitalWrite(PIN_END_SIGNAL, master_is_high ? HIGH : LOW);
break;
}
}MASTER_SIGNAL