/* esercizio_03_riflessi
 * test del display sullo shield arduino.
 * accende per 250mS ogni segmento ed il punto
 *
 * Connessioni dello shield e
 *
 * Digital 2 - In   Tasto S3
 * Digital 4 [3] - Out  Segmento e
 * Digital 3 [4]4 - In   Tasto S2
 * Digital 5 - Out  Segmento d
 * Digital 6 - Out  Segmento c
 * Digital 7 - Out  dp - Punto Decimale
 * Digital 8 - In   Tasto S1
 * Digital 9 - Out  Segmento b
 * Digital 10 - Out Segmento a
 * Digital 11 - Out Segmento f
 * Digital 12 - Out Segmento g
 * Analog 0 - Fotoresistenza - Luce
 * Analog 1 - NTC - Temperatura
 *     --a--
 *    |     |
 *    f     b
 *    |     |
 *     --g--
 *    |     |
 *    e     c
 *    |     |
 *     --d--  dp
 */

#define NUMPROVE  10

#define LEDPIN  13

#define  APIN   10
#define  BPIN   9
#define  CPIN   6
#define  DPIN   5
#define  EPIN   4 /* 3 */
#define  FPIN   11
#define  GPIN   12
#define  DPPIN  7
#define  S1PIN  8
#define  S2PIN  3 /* 4 */
#define  S3PIN  2
#define  LUCE   1
#define  TEMP   0

#define  NUMSEGS  8

/* Array dei numeri di piedino, per ogni segmento del display */
char segments [] = {
  APIN,
  BPIN,
  CPIN,
  DPIN,
  EPIN,
  FPIN,
  GPIN,
  DPPIN  
};

/* Matrice di decodifica da esadecimale allo stato dei segmenti */
boolean cifre [16][7] = {
// a     b      c      d      e      f      g
  {true,  true,  true,  true,  true,  true,  false },  // 0
  {false, true,  true,  false, false, false, false },  // 1
  {true,  true,  false, true,  true,  false, true },   // 2
  {true,  true,  true,  true,  false, false, true },   // 3
  {false, true,  true,  false, false, true,  true },   // 4
  {true,  false, true,  true,  false, true,  true },   // 5
  {true,  false, true,  true,  true,  true,  true },   // 6
  {true,  true,  true,  false, false, false, false },  // 7
  {true,  true,  true,  true,  true,  true,  true },   // 8
  {true,  true,  true,  true,  false,  true,  true },  // 9
  {true,  true,  true,  false, true,  true,  true },   // A
  {false, false, true,  true,  true,  true,  true },   // B
  {true,  false, false, true,  true,  true,  false },  // C  
  {false, true,  true,  true,  true,  false,  true },  // D
  {true,  false, false, true,  true,  true,  true },   // E  
  {true,  false, false, false, true,  true,  true },   // F 
};

void setup () {
  int i;

  for (i = 0; i < NUMSEGS; i++) {
    pinMode(segments [i], OUTPUT);      // Imposta il piedino del segmento a in uscita
    digitalWrite(segments [i], HIGH);   // Spegne il LED
  }
  Serial.begin (9600);                  // Imposta la velocita' della seriale
  randomSeed(analogRead(5));           // Inizializza il generatore di numeri seriali
}


/* Funzione che visualizza un numero sul display
 * Parametri:
 * n -> il numero da visualizzare (limitato a 0-15)
 * Ritorna:
 * niente
 */
void digit (int n) {
  int i;
  n = n % 16;  // limita ad una cifra
  for (i = 0; i < 7; i++) {
    digitalWrite(segments [i], (cifre[n][i]) ? LOW : HIGH);   // Accende il LED
  }
} 

void resetDisp () {
  int i;

  for (i = 0; i < NUMSEGS; i++) {
    digitalWrite(segments [i], HIGH);   // Spegne il LED
  }
}

void loop () {
  int i = 0;
  int side;
  long startTime = micros ();
  long totale = 0;
  long minimo = 10000000;
  long massimo = 0;

  resetDisp ();                  // Spengo il display
  digitalWrite(APIN, LOW);       // Accendo il segmento "a"
  
  while (digitalRead(S2PIN)) {  // Attendo che venga premuto il tasto "START" (S2)
    if (micros () > startTime + 1000000) { // Ogni secondo
      // Cmbio il segmento acceso, tra quelli orizzontali
      startTime = micros ();
      switch (i++ % 3) {
        case 0:
          digitalWrite(APIN, HIGH);
          digitalWrite(GPIN, LOW);
          break;
        case 1:
          digitalWrite(GPIN, HIGH);
          digitalWrite(DPIN, LOW);
          break;
        case 2:
          digitalWrite(DPIN, HIGH);
          digitalWrite(APIN, LOW);
          break;
      }
    }
  }
  
  delay(10);  // Ritardo per attendere la fine dei rimbalzi
  if (!digitalRead(S2PIN)) {  // Il tasto e' ancora premuto
    while (!digitalRead(S2PIN));  // Attende il rilascio
  }

  for (i=0; i < NUMPROVE; i++) {  // Ripeto per "NUMPROVE" volte la prova di riflesso
    int bottone;
    resetDisp ();                 // Spengo il display
    delay (random (1500,2500));   // Attendo un tempo casuale tra 1,5 e 2 secondi
    if (random (2)) {             // seleziono un lato a caso 
      digitalWrite(EPIN, LOW);    // Accendo il lato sinistro (segmenti "e" e "f")
      digitalWrite(FPIN, LOW);
      bottone=S3PIN;              // e seleziono il pulsante sinistro
    } else {  
      digitalWrite(BPIN, LOW);    // Accendo il lato destro (segmenti "b" e "c")
      digitalWrite(CPIN, LOW);
      bottone=S1PIN;              // e seleziono il pulsante destro
    }

    startTime = micros ();        // registro il momento dell'inizio dell'attesa
    
    if (digitalRead(S1PIN) && digitalRead(S3PIN)) {      // Se non c'Ã¨ nessun bottone premuto al momento (falsa partenza)
      while (digitalRead(S1PIN) && digitalRead(S3PIN));  // Attende fino a che non viene premuto S1 o S3
      
      if (!digitalRead(S1PIN) && !digitalRead(S3PIN)) {
        i --;  // Tasti premuti insieme - salto la prova
      } else {
        if (!digitalRead(bottone)) {              // Se il bottone premuto Ã¨ quello giusto
          long riflesso = micros () - startTime;  // calcolo quanto tempo Ã¨ passato
          totale += riflesso;                     // Sommo il tempo attuale a quello delle aptrre prove
          if (riflesso < minimo) {                // guardo se il tempo attuale Ã¨ il nuovo minimo
            minimo = riflesso;                    // se lo Ã¨, aggiorno il minimo
          }
          if  (riflesso > massimo) {              // guardo se il tempo attuale Ã¨ il nuovo massimo
            massimo = riflesso;                   // se lo Ã¨, aggiorno il massimo
          }
        } else {
          i--; // bottone sbagliato - ripeto la prova
        }
      }
      
    } else {
      i--;  // Era giÃ  premuto, quindi ripeto la prova
    }
    while (!digitalRead(S1PIN) || !digitalRead(S3PIN));  // Attende fino a che non viene rilasciato S1 o S3
  }
  /* Stampa il risultato sul terminale */
  Serial.print ("Riflesso minimo = ");
  Serial.print (minimo);
  Serial.print (" massimo = ");
  Serial.print (massimo);
  Serial.print (" media = ");
  Serial.println (totale / NUMPROVE);
  
  /* Stampa il risultato sul display */
  digit (totale / 50000 / NUMPROVE);
  delay (2500);
}



