/* Programme MAITRE pour piloter la boucle Bluetooth HC-05 en anneau à trois unités.
   Directement issu de P14_MAITRE.ino est globalement identique avec comme petite différence,
   si sur RESET le B.P. placé sur D4 n'est pas cliqué, le système passe en mode INFINI. Ainsi, sur
   coupure secteur et redémarrage la boucle de dialogue se rétablit automatiquement.
   Par ailleurs avec l'agencement avec trois interlocuteurs, la synchronisation impose sur l'unité
   Maître à utiliser une séquence avec "TIME OUT". Le déclenchement du mode INFINI passe automatiquement
   les écrans à NOIR après un délai de quelques secondes.

UTILISATION DU PROGRAMME :
--------------------------
   Si le B.P. est maintenu cliqué au moment du RESET, le système fonctionnera en mode "Manuel".
   Les commandes sont alors imposées dans la ligne de saisie du Moniteur.
   Il les affiche dans la fenêtre contextuelle du Moniteur puis les transmet sur la ligne Bluetooth.
   Il passe alors en réception sur cette ligne.
   Recevant l'accusé de réception il le montre dans la fenêtre du Moniteur. Il présente également toutes
   les données de l'échange effectué sur l'écran OLED. Puis le cycle recommence.
   La seule façon de sortir du mode "Dialogue INFINI" consiste à effectuer un RESET sur le module Maitre
   par exemple en cliquant sur la puce d'ouverture du Moniteur et maintenir le B.P. sur D4 cliqué.
   Lorsque le programme est en attente d'un texte arrivant du Moniteur la LED Arduino clignote rapidement
   pour témoigner de l'attente d'une saisie.
   La consigne 'l' ou 'L' Liste sur le Moniteur les commandes possibles.
   Comme on dispose de place à "revendre" pour le programme, la commande 'F' est un amusement graphique
   qui utilise en particulier le tracé d'ellipse pleine.
   • Si on frappe les commandes en minuscules elles sont converties en majuscules.
   • La commande 'I' fait passer le programme en mode "Boucle INFINIE". C'est alors le logiciel
     qui va à nouveau enchaîner automatiquement les commandes.
   • Si sur RESET lors de la synchronisation du dialogue le B.P. branché sur D4 n'est pas activé,
     le système passe en mode "Boucle INFINIE". On peut ainsi déclencher ce processus sans
     avoir besoin d'un ordinateur, avec redémarrage automatique sur coupure secteur.
   • Durant le mode "Boucle INFINIE", le BP branché sur D5 se comporte comme une bascule de
     type OUI/NON pour avoir un Écran noir ou un affichage normal. Agit sur les trois unités. 

 BRANCHEMENTS à effectuer :
--------------------------
  • Le +5V va sur VCC du HC-05.
  • GND va sur GND  du HC-05.
  • GND va sur EN  du HC-05.
  • GND est relié entre les trois unités.
  • D2 d'Arduino va sur TX du HC-05.
  • D3 d'Arduino va sur RX (1k,2k) du HC-05.
  • D4 va sur un bouton poussoir type "Travail" dont le point froid est sur GND.
  • D5 va sur un bouton poussoir type "Travail" dont le point froid est sur GND.
  • D10 d'Arduino va sur STATE du HC-05.
  • A4 va sur SDA de l'afficheur OLED de 1,34 de diagonale.
  • A5 va sur SLC de l'afficheur OLED.
 
Compilateur v1.7.9.            PGM                RAM dynamique
                          18556 Octets (57%)    1150 Octets (56%)  */

//------------------------ Constantes du programme --------------------------
#define Version "06/09/2025" // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Taille_PGM 18556 // Taille du programme Maitre @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define RAM_Dynamique 1150 // Taille de la RAM dynamique @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Pour_cent_PGM 57 // Pourcentage du programme. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Pour_cent_DYN 56 // Pourcentage des données. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Lgr_TEXTE 22 // Longueur maximale d'un ACR Esclave @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define CR 13 // Code du Retour Chariot qui vaut 13 codé en ASCII sous forme décimale.
#define LF 10 // Code du passage à la ligne qui vaut 10 codé en ASCII sous forme décimale.
int Delai_voulu = 75; // Demi période du clignottement en mS.

//------------------- Définition des broches binaires -----------------------
#define RX 2 // D2 va sur TX du module Bluetooth.
#define TX 3 // D3 va sur RX du module Bluetooth avec pont de résistances.
#define Mode_Infini 4 // D4 va sur le bouton poussoir pour imposer le mode INFINI sur RESET.
#define Eteindre_OLED 5 // D5 sert à allumer ou éteindre OLED en mode INFINI.
#define Accouplement 10 // DO va sur la sortie STATE du module Bluetooth.
#define LED_Arduino 13

//---------------------- Déclarations pour le matériel ----------------------
// Cette section est placée après la déclaration des broches binaires qui doivent
// être définies lors de l'instruction SoftwareSerial mySerial(RX,TX);
#include <SoftwareSerial.h>
SoftwareSerial Module_HC05(RX,TX);

#include "U8glib.h"
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); // Usage de la ligne I2C (Two Wire Interface)

//------------------------- Variables du programme --------------------------
boolean Cadre, Encadrement, INFINI, Led_Arduino, Noir, Noir_sur_RESET, Silence, TIME_OUT;
byte Compteur_Time_Out, Index, Index_Debut;
char CAR_module_HC05, Commande_Infinie, CAR_Moniteur, SAV_Commande;
char TEXTE[Lgr_TEXTE];
unsigned long Compteur;
unsigned long Temps_Ecoule_depuis_RESET = 0;
unsigned long Chronometre_TIME_OUT;

//========================= Procédures de servitude ============================

void Inverser_LED_Arduino() {digitalWrite(LED_Arduino,!digitalRead(LED_Arduino));}

void Vider_le_tampon_HC05() {while (Module_HC05.available()) Module_HC05.read();}

int SRAM_LIBRE() { // Fonction qui retourne la taille de SRAM disponible.
    extern int __heap_start, *__brkval; // Déclaration des deux pointeurs dédiés.
    byte BIDON; // Dernière variable allouée, donc occupe le "haut" du TAS.
    if (__brkval == 0) {return (int) &BIDON -(int) &__heap_start;}
    else {return (int) &BIDON -(int) __brkval;}}

void Attente_ACR_sur_le_Module_HC_05() {
  TIME_OUT = false; Chronometre_TIME_OUT = millis();
  while ((!Module_HC05.available()) && (!TIME_OUT)) { // Attente du début de l'ACR.
        //================= Chronométrage pour le délai écoulé ================
          if (millis() - Chronometre_TIME_OUT > 1500)  {TIME_OUT = true;
          Serial.println(); Serial.print(F(" Time OUT d")); Serial.print(char(233));
          Serial.print(F("pass")); Serial.print(char(233));}}
        //=====================================================================
  if (TIME_OUT) {TEXTE[0] = ':'; TEXTE[1] = ' '; TEXTE[2] = 'E'; TEXTE[3] = 'R';}
  else {Index = 0; // Si !TIME-OUT saisir l'ACR venant de l'Esclave.
        while (Module_HC05.available()) {CAR_module_HC05 = Module_HC05.read();
               if ((Index < Lgr_TEXTE) && (CAR_module_HC05 != CR) && (CAR_module_HC05 != LF))
                  {TEXTE[Index] = CAR_module_HC05; Index++;}
               delay(10);}}} // Délai impératif.

void Decale_le_TEXTE_a_gauche() {for (byte I = 0; I < Lgr_TEXTE - 1; I++) TEXTE[I] =  TEXTE[I + 1];}

void Attente_de_la_synchronisation() {
  //------------------------- Affichage sur OLED -------------------------
  u8g.firstPage(); do {// Début de la boucle d'affichage de la page écran.
    u8g.setPrintPos(40,25); u8g.print("Attente de");
    u8g.setPrintPos(25,37); u8g.print("SYNCHRONISATION");}
  while(u8g.nextPage()); delay(1000); // laisser aux modules le temps de se connecter.
  //----------------------------------------------------------------------
  do {Vider_le_tampon_HC05(); Serial.println(); Serial.print(F(" Transmet 'SY' >>> "));
      Module_HC05.println("SYnchro"); Attente_ACR_sur_le_Module_HC_05(); Compteur_Time_Out++;
      //------------------------------------------------------------------
      Serial.print(F(" Analyse de [")); Serial.print(TEXTE[0]); Serial.print(TEXTE[1]);
      Serial.print(TEXTE[2]); Serial.print(TEXTE[3]); Serial.print(TEXTE[4]); Serial.print(TEXTE[5]);
      Serial.print(TEXTE[6]); Serial.print(TEXTE[7]); Serial.print(']');
      //------------------ Filter l'entête "nnnn : OK !" -----------------
      while (TEXTE[0] != ':') Decale_le_TEXTE_a_gauche();
      //------------------ Affichage de l'ACR sur OLED -------------------
      u8g.firstPage(); do {// Début de la boucle d'affichage de la page écran.
         u8g.setPrintPos(40,25); u8g.print("Filtre ACR :"); u8g.setPrintPos(40,37); u8g.print(TEXTE[0]);
         u8g.print(TEXTE[1]); u8g.print(TEXTE[2]); u8g.print(TEXTE[3]); u8g.print("   ");
         u8g.print(Compteur_Time_Out);}
      while(u8g.nextPage());}
  while ((TEXTE[2] != 'O') || (TEXTE[3] != 'K'));
  //----------------------------------------------------------------------
  Serial.println(); Serial.print(F(" DEBUT du DIALOGUE :")); Serial.println();
  //------------------------- Affichage sur OLED -------------------------
  u8g.firstPage(); do {// Début de la boucle d'affichage de la page écran.
    u8g.setPrintPos(40,25); u8g.print("Debut du");
    u8g.setPrintPos(40,37); u8g.print("DIALOGUE");}
  while(u8g.nextPage());}

void Souligner(byte Nb) {
  Serial.print(' '); for (byte I = 0; I < Nb; I++) Serial.print('-'); Serial.println();}

void Aff_OUI_NON(boolean OUI) {
  Serial.print(' '); if (OUI) Serial.println("OUI"); else Serial.println("NON");}

void OLED_OUI_NON(boolean OUI) {
  u8g.print(' '); if (OUI) u8g.print("OUI"); else u8g.print("NON"); u8g.print('.');}
  
void Liste_les_Options() {
  Serial.println(); Serial.println(" Etats des options :"); Souligner(19);
  Serial.print(F(" Encadrement =")); Aff_OUI_NON(Cadre);
  Serial.print(F(" LED_Arduino =")); Aff_OUI_NON(Led_Arduino);  
  Serial.print(F("  Ecran noir =")); Aff_OUI_NON(Noir);
  Serial.print(F("     Silence =")); Aff_OUI_NON(Silence);}

void Lister_les_Commandes() {
   Serial.println(); Serial.println(" Rappel des commandes :"); Souligner(22);
   Serial.println(F(" 6 ou - : Compteur - 1."));
   Serial.println(F(" = ou + : Compteur + 1."));
   Serial.println(F(" a ou A : Alarme. (BIP)"));
   Serial.println(F(" b ou B : Bonjour."));
   Serial.println(F(" c ou C : Compilateur 1.7.9."));
   Serial.println(F(" d ou D : Discretion.")); // Force le Silence.
   Serial.println(F(" e ou E : Encadrement OUI/NON."));
   Serial.println(F(" f ou F : Fenetre.")); // Simple affichage graphique.
   Serial.println(F(" h ou H : Liste les commandes. (Ou , ou ?)"));
   Serial.println(F(" i ou I : Dialogue INFINI."));
   Serial.println(F(" j ou J : Jalon.")); // Affichage du nombre d'échanges.
   Serial.println(F(" k ou K : Taille du PGM."));
   Serial.println(F(" l ou L : LED Arduino OUI/NON."));
   Serial.println(F(" m ou M : Pile - Tas sur les deux Arduinos.")); 
   Serial.println(F(" n ou N : Ecran noir OUI/NON."));
   Serial.println(F(" o ou O : Liste les Options."));
   Serial.println(F(" p ou P : Pourcentages.")); // Affichage du nombre d'échanges.
   Serial.println(F(" q ou Q : Quitter.")); // Simple texte "Au revoir !"
   Serial.println(F(" r ou R : RESET des OPTIONS."));
   Serial.println(F(" s ou S : Silence OUI/NON."));
   Serial.println(F(" t ou T : TEST dialogue.")); // Simple texte.
   Serial.println(F(" u ou U : RAM Dynamique utilisee."));
   Serial.println(F(" v ou V : Version logicielle."));
   Serial.println(F(" x ou X : Vider le tampon UART du HC-05."));
   Serial.println(F(" z ou Z : Remise a zero du compteur d'echanges.")); Serial.println();}

void Traiter_la_Commande() {
  Serial.println(); Serial.print(" TEXTE = [");
  for (byte I = 0; I < Index; I++) Serial.print(TEXTE[I]);
  Serial.print(']'); Serial.print(" Lgr TEXTE = "); Serial.println(Index);
  CAR_Moniteur = TEXTE[0];
  switch (CAR_Moniteur) {
    case '-' : {Serial.print(F(" Compteur - 1.")); Compteur--; break;}
    case '+' : {Serial.print(F(" Compteur + 1.")); Compteur++; break;}
    case 'A' : {Serial.println(F(" BIP d'Alarme.")); break;}
    case 'B' : {Serial.println(F(" BONJOUR !")); break;}
    case 'C' : {Serial.println(F(" Compilateur 1.7.9. ")); break;}
    case 'D' : {Serial.println(F(" Plus de BIPs sonores. ")); break;}
    case 'E' : {Serial.print(F(" Encadrement")); Aff_OUI_NON(Cadre); break;}
    case 'F' : {Serial.println(F(" FENETRE.")); break;}
    case 'H' : {Lister_les_Commandes(); break;}
    case 'I' : {Serial.println(F(" Mode automatique INFINI"));
                INFINI = true; Commande_Infinie = 'B'; break;}
    case 'J' : {Serial.print(F(" Jalons = ")); Serial.println(Compteur + 1); break;} 
    case 'K' : {Serial.print(F(" Taille PGM = ")); Serial.println(Taille_PGM); break;}
    case 'L' : {Serial.print(F(" LED Arduino")); Aff_OUI_NON(Led_Arduino); break;}
    case 'M' : {Serial.print(F(" Pile - Tas sur le Maitre = ")); Serial.println(SRAM_LIBRE()); break;}
    case 'N' : {Serial.print(F(" Ecran Noir")); Aff_OUI_NON(Noir); break;}
    case 'O' : {Liste_les_Options(); break;}
    case 'P' : {Serial.print(F("PGM ")); Serial.print(Pour_cent_PGM); Serial.print(F("% M Dyn "));
                Serial.print(Pour_cent_PGM); Serial.println(F("%.")); break;} 
    case 'Q' : {Serial.println(F(" Au revoir !")); break;}  
    case 'R' : {Serial.println(); Serial.println(F(" Options sur l'esclave :")); Souligner(23);
                Serial.println(F(" Compteur = 0,")); Serial.println(F(" Pas de LED Arduino,"));
                Serial.println(F(" Encadrement,")); Serial.println(F(" Ecran actif,"));
                Serial.println(F(" Pas de BIP.")); Serial.println(); break;}
    case 'S' : {Serial.print(F(" Silence")); Aff_OUI_NON(Silence); break;}
    case 'T' : {Serial.println(F(" TEST dialogue.")); break;}
    case 'U' : {Serial.print(F(" RAM Dynamique = ")); Serial.println(RAM_Dynamique); break;}
    case 'V' : {Serial.print(F(" Version PGM : ")); Serial.println(Version); break;}
    case 'X' : {Serial.print(F(" Vide le tampon du HC-05.")); Serial.println();
                if (!INFINI) Vider_le_tampon_HC05(); break;}
    case 'Z' : Serial.print(F(" RAZ Compteur."));}}

void Memorisation_des_options() {
  CAR_Moniteur = TEXTE[0];
  if (Index == 1) switch (CAR_Moniteur) {
                     case 'D' : {Silence = true; break;}
                     case 'E' : {Cadre = !Cadre; break;}
                     case 'L' : {Led_Arduino = !Led_Arduino; break;}
                     case 'N' : {Noir = !Noir; break;}
                     case 'R' : {Cadre = true; Silence = true; Noir = false; Led_Arduino = false;
                                 Compteur = 0; break;}
                     case 'S' : {Silence = !Silence; break;}
                     case 'Z' : Compteur = 0;}}

void Saisir_une_commande() {
  // Les caractères 'A' et 'S' en mode Infini sont éliminés pour ne pas déclencher de BIPs.
  // Le caractère 'I' en mode Infini est éliminé pour ne pas recycler en 'B'.
  // Le caractère 'N' en mode Infini est éliminé pour ne pas éteindre l'écran.
  // Les caractères 'R' et 'Z'en mode Infini sont éliminés pour ne pas remettre le compteur à zéro.
  if (INFINI) {Index = 1; 
              if (Commande_Infinie == 'I') Commande_Infinie = 'J';
              if (Commande_Infinie == 'N') Commande_Infinie = 'O';
              if (Commande_Infinie == 'R') Commande_Infinie = 'T';
              if ((Noir_sur_RESET) && (Commande_Infinie == 'Y')) {
                 Noir_sur_RESET = false; Commande_Infinie = 'N'; TEXTE[0] = 'N';} 
              if (Commande_Infinie == 'Z') Commande_Infinie = 'B';
              TEXTE[0] = Commande_Infinie; Commande_Infinie++; delay(300);}
  else {//----------- Effectuer une SAISIE sur le Moniteur -----------
       Index = 0;
       while (!Serial.available()) { // Attente d'une saisie sur le Moniteur.
             //================= Chronométrage pour le délai écoulé ================
             if (millis() - Temps_Ecoule_depuis_RESET > Delai_voulu)  {
             Temps_Ecoule_depuis_RESET = millis(); Inverser_LED_Arduino();}}
             //=====================================================================
       while (Serial.available()) {CAR_Moniteur = Serial.read();
              if ((Index < Lgr_TEXTE) && (CAR_Moniteur != CR) && (CAR_Moniteur != LF)) {
                 //---------- Passer les lettre en MAJUSCULES ----------
                 if ((CAR_Moniteur >= 'a') && (CAR_Moniteur < char(123))) CAR_Moniteur = CAR_Moniteur & 223;
                 // Bien moins couteux en octets que Chaine_Memorisee.toUpperCase().
                 //---------- Substitue des signes en MAJUSCULES ----------
                 if (CAR_Moniteur == '6') CAR_Moniteur = '-'; if (CAR_Moniteur == '=') CAR_Moniteur = '+';
                 if ((CAR_Moniteur == '?') || (CAR_Moniteur == ',')) CAR_Moniteur = 'H';
                 //-----------------------------------------------------
                 TEXTE[Index] = CAR_Moniteur; Index++;} delay(5);}}} // Délai impératif.

void Affiche_le_commentaire() {
  switch (SAV_Commande) {
    case 'A' : {u8g.print("BIP d'Alarme."); break;}
    case 'B' : {u8g.print("BONJOUR !"); break;}
    case 'C' : {u8g.print("Compilateur 1.7.9. "); break;}
    case 'D' : {u8g.print("Pas de BIP sonores. "); break;}
    case 'E' : {u8g.print("Encadrement"); OLED_OUI_NON(Cadre); break;}
    case 'F' : {u8g.print("FENETRE."); break;}
    case 'H' : {u8g.print("Lister Commandes."); break;}
    case 'I' : {u8g.print("Mode INFINI"); break;}
    case 'J' : {u8g.print("Jalons = "); u8g.print(Compteur); u8g.print('.'); break;} 
    case 'K' : {u8g.print("Taille PGM = "); u8g.print(Taille_PGM); u8g.print('.'); break;}
    case 'L' : {u8g.print("LED Arduino"); OLED_OUI_NON(Led_Arduino); break;}
    case 'M' : {u8g.print("Pile - Tas = "); u8g.print(SRAM_LIBRE()); u8g.print('.'); break;}
    case 'N' : {u8g.print("Ecran Noir"); OLED_OUI_NON(Noir); break;}
    case 'O' : {u8g.print("Options Esclave."); break;}
    case 'P' : {u8g.print("PGM "); u8g.print(Pour_cent_PGM); u8g.print("% M Dyn ");
                u8g.print(Pour_cent_PGM); u8g.print("%.");break;} 
    case 'Q' : {u8g.print("Au revoir !"); break;}  
    case 'R' : {u8g.print("RESET des Options."); break;}
    case 'S' : {u8g.print("Silence"); OLED_OUI_NON(Silence); break;}
    case 'T' : {u8g.print("TEST dialogue."); break;}
    case 'U' : {u8g.print("M Dynamique = "); u8g.print(RAM_Dynamique); u8g.print('.');break;}
    case 'V' : {u8g.print("Rev. : "); u8g.print(Version);  u8g.print('.'); break;}
    // Case X est inutile car non affiché la commande restant locale.
    case 'Z' : u8g.print("RAZ Compteur.");}}

void Affiche_Ecran_OLED() {
  Index_Debut = 0; while(TEXTE[Index_Debut] != ':') Index_Debut++; // Prépare l'affichage de l'ACR.
  u8g.firstPage(); do {
     u8g.drawFrame(0,0,128,62); u8g.drawHLine(1,14,126); u8g.drawHLine(1,28,126);
     u8g.drawHLine(1,42,126); u8g.drawFrame(2,44,124,16);
     u8g.setPrintPos(10,10); u8g.print("Nb Cycles : "); u8g.print(Compteur);
     u8g.setPrintPos(10,24); u8g.print("Commande : "); u8g.print(SAV_Commande);
     u8g.setPrintPos(10,38); u8g.print("ACR ");
     for (byte I = Index_Debut; I < Index; I++) u8g.print(TEXTE[I]);
     u8g.setPrintPos(10,55); Affiche_le_commentaire();}
     while(u8g.nextPage());}

void Aff_Fenetre() {
  u8g.firstPage(); do {
    u8g.drawFrame(0,0,48,64); u8g.drawVLine(24,1,62); u8g.drawHLine(1,21,46); u8g.drawHLine(1,43,46);
    u8g.drawFrame(2,2,21,18); u8g.drawFrame(2,23,21,19); u8g.drawFrame(2,45,21,17);
    u8g.drawFrame(26,2,20,17); u8g.drawFrame(26,23,20,18); u8g.drawFrame(26,45,20,17);
    u8g.drawFrame(52,0,48,64); u8g.drawVLine(76,1,62); u8g.drawHLine(53,21,46); u8g.drawHLine(53,43,46);
    u8g.drawFrame(54,2,21,18); u8g.drawFrame(54,23,21,19); u8g.drawFrame(54,45,21,17);
    u8g.drawFrame(78,2,20,18); u8g.drawFrame(78,23,20,19); u8g.drawFrame(78,45,20,17);
    u8g.drawFilledEllipse(50,32,6,3); u8g.drawFrame(101,0,27,64); u8g.setPrintPos(106,10); 
    u8g.print("Dou"); u8g.setPrintPos(106,22); u8g.print("ble"); u8g.setPrintPos(108,34);
    u8g.print("vi"); u8g.setPrintPos(106,46); u8g.print("tra"); u8g.setPrintPos(106,58); u8g.print("ge.");}
  while(u8g.nextPage());}

void Affiche_Accouplement() {
  Serial.println(); Serial.print(F(" Attente appairage des HC-05.")); Serial.println();
  u8g.firstPage(); do {// Début de la boucle d'affichage de la page écran.
    u8g.setPrintPos(20,25); u8g.print("Att.  APPAIRAGE");
    u8g.setPrintPos(20,37); u8g.print("des BLUETOOTHs.");}
  while(u8g.nextPage());}

void Avertissement_sur_OLED() {
  u8g.firstPage(); do {
    if (!Noir) {u8g.drawFrame(21,13,95,34); u8g.drawFrame(17,10,103,40);
       u8g.setPrintPos(39,26); u8g.print("PROBLEME de "); u8g.drawLine(70,17,71,18);
       u8g.setPrintPos(29,40); u8g.print("COMMUNICATION.");}}
     while(u8g.nextPage());}

//=========================== Corps du programme ===============================

void setup() {
  pinMode(RX,INPUT); pinMode(TX,OUTPUT); pinMode(LED_Arduino, OUTPUT); pinMode(Accouplement,INPUT);
  pinMode(Mode_Infini,INPUT_PULLUP); // Broche en entrée et validation de la résistance de Pullup.
  pinMode(Eteindre_OLED,INPUT_PULLUP); // Broche en entrée et validation de la résistance de Pullup.
  Module_HC05.begin(9600);
  u8g.setFont(u8g_font_6x10); // Police de matrices de 6x10 pixels lettres MJA/min comprises.
  while(Module_HC05.available()) CAR_Moniteur = Module_HC05.read(); // Vider le tampon de RX.
  Cadre = true; INFINI = false; Compteur_Time_Out = 0; Led_Arduino = false; Noir = false;
  Silence = true; Compteur = 1;
  //----------------- Prise en compte du bouton poussoir sur D4 -----------------
  Noir_sur_RESET = false;
  if (digitalRead(Mode_Infini)) INFINI = true; Noir_sur_RESET = true; 
  //---------------------- Présenter le programme sur USB -----------------------
  Serial.begin(9600); while (Serial.available()) CAR_Moniteur = Serial.read(); // Vider le tampon série.
  Serial.println(); Serial.print(F(" MAITRE-H : Version du ")); Serial.println(Version);
  //--------------------- Attendre l'accouplement des HC-05 ---------------------
  Affiche_Accouplement(); while(!digitalRead(Accouplement)); // Attente de l'accouplement.
  //-----------------------------------------------------------------------------
  Serial.println(); Serial.println(F(" Attente de la SYNCHRONISATION.")); Vider_le_tampon_HC05();
  Attente_de_la_synchronisation(); Vider_le_tampon_HC05();
  if (digitalRead(Mode_Infini)) {INFINI = true; Module_HC05.print('I'); Attente_ACR_sur_le_Module_HC_05();
      delay(200); Vider_le_tampon_HC05(); Commande_Infinie = 'B';}}

void loop() {
  if (INFINI && !digitalRead(Eteindre_OLED)) {// Alterner Ecran Noir sur l'Esclave.
     while (!digitalRead(Eteindre_OLED)) Commande_Infinie = '#';}
  //======================== Traitement de la ligne Bluetooth. =======================
  Saisir_une_commande(); // Saisie Moniteur ou génération automatique en mode INFINI.
  //--------------------- Mémorisation des options ---------------------
  Memorisation_des_options();
  //--------------------------------------------------------------------
  if (Index == 1) Traiter_la_Commande(); SAV_Commande = TEXTE[0];
  //------------------------ Traite le BP NOIR -------------------------
  if (TEXTE[0] == '#')  {TEXTE[0] = 'N'; Commande_Infinie = 'B'; Noir = !Noir; SAV_Commande = TEXTE[0];}
  //------------------- Transmission sur TX du texte -------------------
  if ((TEXTE[0] != 'X') && (TEXTE[0] != '-') && (TEXTE[0] != '+')) {// Ne pas envoyer ces 3 commandes.
     Compteur++;
     for (byte I = 0; I < Index; I++) Module_HC05.print(TEXTE[I]);
         Module_HC05.write(CR); Module_HC05.write(LF);
     //---------------- Réception de l'ACR du Bleutooth ----------------
     Attente_ACR_sur_le_Module_HC_05();
     if (TIME_OUT) {Serial.print(F(" Probl")); Serial.print(char(232));
        Serial.println(F("me de communication.")); Avertissement_sur_OLED();}
     else {Serial.print(F(" ACR num "));
          //------------ Affichage de l'ACR sur le Moniteur ------------
           for (byte I = 0; I < Index; I++) Serial.print(TEXTE[I]); Serial.println();
          //-------------- Affichage page Ecran sur OLED ---------------
          if ((Noir) && (SAV_Commande == 'N')) {u8g.firstPage(); do {} while(u8g.nextPage());}
          if (!Noir) {if (SAV_Commande == 'F') Aff_Fenetre(); else Affiche_Ecran_OLED();}
          if (SAV_Commande == 'Z') Compteur = 0;}}}
 
 
