// Début de l'entête déclarative =================================
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Réglage des heures,des minute et des secondes .
const int btn_Up_Heure = 2, btn_Dn_Heure = 7,
          btn_Up_Minute = 3, btn_Dn_Minute = 8,
          btn_Up_Seconde = 4, btn_Dn_Seconde = 9,
          btn_StartStop = 5,// Marche/arrêt Chrono
          btn_Reset = 6, // Mise à zéro
          buzzer = 13;  // Assigne la broche 13 au piezo.

// Variables de type booléen. = 0 ou 1, LOW ou HIGH
bool etat_btn_Up_Heure, etat_btn_Dn_Heure,
     etat_btn_Up_Minute, etat_btn_Dn_Minute,
     etat_btn_Up_Seconde, etat_btn_Dn_Seconde,
     etat_btn_StartStop,
     etat_btn_Reset,
     etat_btnPressed,
     flagOn, newTime;
// valeurs du temps de départ
long  heure, minute, seconde, milliseconde, TempsEcoule;
char chrono[20]; // Mémoire tampon de 20 caratères
String etat[] = {"Off", "On "};
// Tableau de type String: affiche l'état du bouton Start/Stop
String btn[] = {"             Start  ",
                "             Stop   ",
                "                    "
               };

// Fin de l'entête déclarative=====================================










// Fonction d'initialisation ======================================
void setup() {
  lcd.init(); // Initialise lcd
  lcd.backlight(); // Rétroéclairage lcd
  
  //Assigne le mode INPUT_PULLUP aux 8 boutons poussoirs.
  for (int pin = 2; pin <= 9; pin++) pinMode(pin, INPUT_PULLUP);
  //Assigne le mode OUTPUT à la broche du buzzer.
  pinMode(buzzer, OUTPUT);

}
// FIN de la Fonction d'initialisation ============================











// Fonction d'exécution ===========================================
void loop() {

  Fn_Display(); // Fonction d'affichage.
  Fn_BoutonsCommandes(); // Scan les 8 boutons poussoirs
  Fn_Set_Timer(); // fonction de réglage du minuteur.
  //si(flagOn == 1) Lance le compte à rebour.
  if (flagOn)compte_a_rebour();
}
// Fin de la Fonction d'exécution =================================
















// Fonction de programmation du minuteur===========================
void Fn_Set_Timer() {
  if (newTime == 0) {//  exécute les instruction suivantes...
    lcdPrintCenter("Entrez l'heure...", 1); // Affiche instruction.
    if (!etat_btn_Up_Heure) {//Si btn_Up_Heure est pressé.
      tick(); heure++; // Incrémente les heures de 1
      if (heure >= 24) heure = 0; else  heure = heure; delay(150);
    } if (!etat_btn_Dn_Heure) {//Si btn_Dn_Heure est pressé.
      tick(); heure--; // Décrémente les heures de 1
      if (heure < 0) heure = 23; else  heure = heure; delay(150);
    } if (!etat_btn_Up_Minute) { //Si btn_Up_Minute est pressé.
      tick(); minute++; // Incrémente les minutes de 1
      if (minute > 59)minute = 0; else minute = minute; delay(100);
    } if (!etat_btn_Dn_Minute) {
      tick(); minute--; // Décrémente les minutes de 1
      if (minute < 0)minute = 59; else minute = minute; delay(100);
    } if (!etat_btn_Up_Seconde) {//Si btn_Up_Seconde est pressé.
      tick(); seconde++; // Incrémente les secondes de 1
      if (seconde > 59) seconde = 0;
      else seconde = seconde; delay(150);
    } if (!etat_btn_Dn_Seconde) {
      tick(); seconde--; // Décrémente les secondes de 1
      if (seconde < 0) seconde = 59;
      else seconde = seconde; delay(100);
    }
  }
  if (heure != 0 | minute != 0 | seconde != 0 )
    lcdPrintCenter(btn[0], 3);// Affiche "Start"
  else lcdPrintCenter(btn[2], 3); // Efface la ligne 3
}
// Fin de la Fonction de programmation du minuteur=================








// Fonction des boutons Start/Stop et Reset========================
void Fn_BoutonsCommandes() {
  // Scan l'état des boutons poussoir.
  etat_btn_Up_Heure = digitalRead(btn_Up_Heure);
  etat_btn_Dn_Heure = digitalRead(btn_Dn_Heure);
  etat_btn_Up_Minute = digitalRead(btn_Up_Minute);
  etat_btn_Dn_Minute = digitalRead(btn_Dn_Minute);
  etat_btn_Up_Seconde = digitalRead(btn_Up_Seconde);
  etat_btn_Dn_Seconde = digitalRead(btn_Dn_Seconde);
  etat_btn_StartStop = digitalRead(btn_StartStop);
  etat_btn_Reset = digitalRead(btn_Reset);
  // Le bouton Start/Stop contrôle la marche et l'arrêt du minuteur.
  if (etat_btn_StartStop == LOW && etat_btnPressed == LOW) {
    newTime = 1; // indique que le minuteur est programmé.
    etat_btnPressed = HIGH; // bouton start a été pressé
    flagOn = !flagOn; // Inversion du flag
    beep(); // émet un beep à chaque pression.
    while (etat_btn_StartStop) // fonction anti-rebond
      etat_btn_StartStop = digitalRead(btn_StartStop);
  }
  if (!etat_btn_Reset && !etat_btnPressed && newTime) {// Reset
    etat_btnPressed = LOW; flagOn = LOW; beep();
    heure = 0; minute = 0; seconde = 0; newTime = 0; lcd.clear();
    while (!etat_btn_Reset)etat_btn_Reset = digitalRead(btn_Reset);
  }
  if (etat_btn_StartStop == 1 && etat_btnPressed == 1) {
    etat_btnPressed = !etat_btnPressed; //Inverse etat_btnPressed
    lcdPrintCenter(btn[flagOn], 3); // Affiche l'état de Start/Stop.
  }
}// Fin Fonction des boutons Start/Stop et Reset===================









// Fonction du compte à rebour.==================================
void compte_a_rebour() {
  if (seconde == 0) {
    if (minute != 0)  seconde = 59;
    if (minute <= 0) minute = 0; else minute--;
    if (minute == 0) {
      if (heure != 0)  minute = 59;
      if (heure <= 0) heure = 0; else  heure--;
      if (heure == 0) {
        if (minute == 0)
          if (seconde == 0) {
            flagOn = !flagOn;
            lcd.clear(); // Vide l'afficheur
            beep(); // émet un beep
            lcdPrintCenter("Fin du decompte", 1); //fin du décompte.
            Alarm(); // Lance l'alarme.
          }
      }
    }
    // Décompte de 1 seconde et émet in tick toutes les secondes.
  } else  seconde--; tick();
  delay(1000); // intervale de 1 seconde
}
// Fin Fonction du compte à rebour.===============================











// Fonctions du buzzer ==========================================
// fonction beep pour Émettre une tonalité de x kHz pendant x ms
void beep() {// Émet une tonalité de 2,5kHz pendant 100 ms
  tone(buzzer, 2500, 100);
}
// Émet une très brève tonalité de 5kHz pendant 4 ms
void tick() {
  tone(buzzer, 5000, 4);   // Émet un son de 5 kHz pendant 1 ms
}
// Fonction d'Alarme
void Alarm() {  
  // Répète les 2 tonalitéd 10 fois chaque avant de se taire
  for (int repeat = 0; repeat <= 2; ++repeat) {
    // Émet une tonalité de 800Hz pendant 300 ms,
    // suivi d'une interruption de 200ms
    tone(buzzer, 800, 300); delay(200);
    // Émet une tonalité de 500Hz pendant 300 ms,
    // suivi d'une interruption de 200ms
    tone(buzzer, 500, 300); delay(200);
    // Fait clignoter le rétroéclairage de l'afficheur lcd
    // par interval de 100ms.
    for (int flash = 0; flash <= 2; ++flash) {
      // Désactive le rétroéclairage de lcd3
      lcd.noBacklight();
    }
    delay(100); // Vitesse du clignotement
    lcd.backlight(); // Rétabli le rétroéclairage de l'afficheur.
  }
  lcdPrintCenter("Press Reset button", 3); // Affiche instruction
}
//Fin des Fonctions du buzzer =====================================













// fonction  pour centrer le texte à afficher sur lcd.============
void lcdPrintCenter(String text, int ligne) {
  int len = text.length();// longeur de la variable text
  // positionne le curseur au centre de la ligne choisie et
  // soustrait la longeur du text à afficher
  lcd.setCursor((20 - len) / 2, ligne);
  lcd.print(text);    // affiche le text centré
}

// Fin fonction pour centrer le texte à afficher===========
















// Fonctions d'affichage en tempr réel===========================
void Fn_Display() {
  if (flagOn)lcdPrintCenter("*Compte a rebour*", 1);
  if (flagOn)lcdPrintCenter("Minuteur " + etat[flagOn], 0);
  else lcdPrintCenter("Minuteur " + etat[flagOn], 0);
  //Formate l'affichage.
  sprintf(chrono, "%02ld:%02ld:%02ld", heure, minute, seconde );
  lcdPrintCenter(chrono, 2);  // Affiche le temps écoulé.
}
// Fin des Fonctions d'affichage =================================