#include <SPI.h>
#include "Semafori.h"
#include "sr595.h"

const byte PIN_CS   =  4;   

// TLCU Traffic Light Control Unit
struct TLCU {
    uint8_t *reg;     // puntarore a registro condiviso
    uint16_t *times;   // array di 3 tempi associato a questo registro
};

// tempi specificati in millesimi di secondo
uint16_t lss0_2Times[] = { 5000,   750,    250 }; 
uint16_t lss1_3Times[] = { 3000,   750,    250 };
//                         Verde, Giallo, Rosso
// Nota sui tempi:
// il verde di durata meggiore viene solitamente assegnato 
// alla strada più trafficata

uint8_t lss0_2 = Color::RED;   // registro per lss0 e lss2 (Nord e Sud)
uint8_t lss1_3 = Color::RED;   // registro per lss1 e lss3 (Est e Ovest)
uint32_t greenStartTime;       // dove salvare millis()

#define TLCU_MAX 2             // Quantità di registri
TLCU tlcu[TLCU_MAX] = {
    { &lss0_2, lss0_2Times },
    { &lss1_3, lss1_3Times }
};
// tlcuIdx è indice di tlcu, inizializzato a 1 per puntare a lss1_3 
// che inizia con il verde (vedi funzione allRed())
uint8_t tlcuIdx = 1;  
// sr16 è istanza di classe SR59516 per controllare due shift register 595
SR59516 sr16(PIN_CS);
// Istanze di Lanterne Semaforiche Stradali
LSS lss0(sr16, 5, 6, 7);      // Nord (ore 12)
LSS lss1(sr16, 10, 11, 12);   // Est (ore 3)
LSS lss2(sr16, 2, 3, 4);      // Sud (ore 6)     
LSS lss3(sr16, 13, 14, 15);   // Ovest (ore 9)


void setup() {
 
    Serial.begin(115200);
    
    pinMode(PIN_CS, OUTPUT);

    digitalWrite(PIN_CS, HIGH);
    SPI.begin();
    // ad ogni lanterna è possibile assegnare un ID 0÷255 
    lss0.setId(0);
    lss1.setId(1);
    lss2.setId(2);
    lss3.setId(3);
    // assegna i 2 registri condivisi alle 4 lanterne.
    lss0.setRegister(&lss0_2);   
    lss2.setRegister(&lss0_2);
    lss1.setRegister(&lss1_3);
    lss3.setRegister(&lss1_3);
    
}

bool f_allred = true;   
// Accende tutti rossi per 2 secondi poi lss1_3 su verde
void allRed() {
    
    static uint8_t startTime = millis();
    if (f_allred && millis() - startTime > 2000) {
        lss1_3 = Color::GREEN;
        greenStartTime = millis();
        f_allred = false;
    }
}

// Esegue le temporizzazioni
void run() {
     
    Color color = *tlcu[tlcuIdx].reg;
    if (millis() - greenStartTime >= tlcu[tlcuIdx].times[color]) {
        
        if (*tlcu[tlcuIdx].reg == Color::RED) {
            tlcuIdx++;
            tlcuIdx = tlcuIdx % TLCU_MAX;
        }

        (*tlcu[tlcuIdx].reg)++;
        *tlcu[tlcuIdx].reg = *tlcu[tlcuIdx].reg % 3;
        greenStartTime = millis();
    }
}

void loop() { 
    // occorre chiamare il metodo show per ogni istanza di lanterna 
    lss0.show();
    lss1.show();
    lss2.show();
    lss3.show();
    // Mantiene accessi tutti rossi per 2 secondi, poi lss1_3 commuta sul verde 
    allRed();  
    if (f_allred) 
        return;

    run();
    
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
74HC595
sr1:Q1
sr1:Q2
sr1:Q3
sr1:Q4
sr1:Q5
sr1:Q6
sr1:Q7
sr1:GND
sr1:Q7S
sr1:MR
sr1:SHCP
sr1:STCP
sr1:OE
sr1:DS
sr1:Q0
sr1:VCC
led3:A
led3:C
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C
led8:A
led8:C
74HC595
sr2:Q1
sr2:Q2
sr2:Q3
sr2:Q4
sr2:Q5
sr2:Q6
sr2:Q7
sr2:GND
sr2:Q7S
sr2:MR
sr2:SHCP
sr2:STCP
sr2:OE
sr2:DS
sr2:Q0
sr2:VCC
led11:A
led11:C
led12:A
led12:C
led13:A
led13:C
led14:A
led14:C
led15:A
led15:C
led16:A
led16:C
lss0 id=0
lss1 id=1
lss3 id=3
lss2 id=2
10
11
12
2
3
4
13
14
15
5
6
7
pedonale