/* Poste de PILOTAGE pour le réseau en anneau avec Bluetooth HC-05 comportant deux postes de Travail.

  • Stictement identique à P18A mis à part que la génération automatique des JETONS en mode
    INFINI se charge de produire des JETONs aléatoires tant en contenu que pour l'adressage.

 COMPORTEMENT DU PROGRAMME :
 ---------------------------
  • Sur RESET le programme est en génération manuelle des JETONS via le Moniteur de l'IDE.
    Il attend que l'opérateur saisice "555" ou "666" dans la fenêtre du Moniteur.
    Si durant l'attente de cette directive l'opérateur attend, on voit défiler des ACR
    sous la forme "Retour orphelin > Non."
  • Toutes les trente secondes le programme teste si le dialogue est effectif. Si un JETON spécial
    "999" n'est pas retourné par le réseau, un BIP sonore prévient l'opérateur, la LED triple
    s'allume en jaune et un texte spécifique est présenté sur OLED si Noir n'est pas validé.
    Le système reste figé jusqu'à ce que l'opérateur clique sur le B.P. surveillé par A3.
    Si l'opérateur clique sur B.P. A1, rétablit les affichages OLED si les écrans étaien noirs.
    L'action de l'opérateur éteint la LED triple qui est illuminée en "jaune".
  • Si sur RESET le BP sur A3 est actif, le programme passe en génération automatique des JETONS.
    
  Mode manuel de génération des JETONS :
  ======================================
  • Fermer l'inverseur et activer le Moniteur, le programme attend la synchronisation.
    Frapper "555" ou "666" l'écran affiche "Debut du DIALOGUE".
  • Chaque commande manuelle allume la LED en BLEUE durant 0,8S et OLED rend compte du résultat.
  • Si la commande comporte une erreur la LED ROUGE s'allume et OLED spécifie l'origine et la
    nature de l'erreur. C'est la commande suivante qui éteint la LED ROUGE.
  • Si le JETON ne comporte qu'une seule lettre, c'est une directive.
    La directive '?' ou 'H' fait lister les commandes possibles sur OLED.
    Si 'S' est active, la lettre 'S' est affichée dans un petit cadre en haut à droite.
    La sortie de la commande 'N' fait afficher le texte du HELP.

 BRANCHEMENTS à effectuer :
---------------------------
  • Le +5V va sur VCC des deux HC-05.
  • GND va sur GND des deux HC-05.
  • GND va sur EN des deux HC-05.
  • D0 (RX) d'Arduino va sur TXD du HC-05 d'Entrée.
  • D1 (TX) d'Arduino va sur RXD (1k,2k) du HC-05 d'Entrée.
  • D2 d'Arduino va sur TXD du HC-05 de Sortie.
  • D3 d'Arduino va sur RXD (1k,2k) du HC-05 de Sortie.
  • D9 pilote un relais 2xRT 5V si mode manuel (Développement) est envisagé.
    Les contacts repos sont en série avec l'inverseur double qui isole D0 et D1.
  • A1 va sur un bouton poussoir type "Travail" dont le point froid est sur GND.
    A1 permet d'allumer ou d'éteindre les écrans OLED en mode INFINI.
  • A3 va sur un bouton poussoir type "Travail" dont le point froid est sur GND.
    A3 permet en autonome de passer en mode en mode INFINI.
    
  • 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
                       18082 Octets (58%)      985 Octets (48%) */

//------------------------ Constantes du programme --------------------------
#define Version "15/10/2025" // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Taille_PGM "18082 58% 985 48%" // Tailles du PGM @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Lgr_JETON 7 // 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.

//------------------- Définition des broches binaires -----------------------
#define RXD 2 // D2 va sur TX du module Bluetooth de Sortie.
#define TXD 3 // D3 va sur RX du module Bluetooth de Sortie avec pont de résistances.
#define BUZZER 4 // Va sur le bruiteur actif.
#define LED_triple_ROUGE 6
#define LED_triple_VERTE 7
#define LED_triple_BLEUE 8
#define Relais 9 // Relais provisoire utilisé pour le développement.
#define LED_Arduino 13

//------------------- Définition des broches analogiuqes --------------------
#define BP_sur_A1 15 // A1 sert à allumer ou éteindre OLED en mode INFINI.
#define BP_sur_A3 17 // A3 sert à libérer une alerte de perte de réseau.
                             // Sur RESET A3 actif fait passer en mode INFINI.

//---------------------- 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 HC05_de_Sortie(RXD,TXD);

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

//------------------------- Variables du programme --------------------------
boolean Allume, Developpement, INFINI, Led_Arduino, Noir, Silence;
char ACTION, Adresse_Poste, CAR_HC05_de_Sortie, CAR_USB, SAV_Index;
byte Index;
byte Un_sur_5 = 0;
unsigned long Compteur;
char JETON[Lgr_JETON];
char SAV_JETON[Lgr_JETON];
unsigned long Temps_Ecoule_depuis_RESET = 0;
unsigned long Temps_pour_tester_le_dialogue;
unsigned long TIME_OUT;

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

void BIP() {
  if (!Silence) {digitalWrite(BUZZER, HIGH); delay(100); digitalWrite(BUZZER, LOW);}}

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

void Eteindre_la_LED_triple() {
  digitalWrite(LED_triple_ROUGE,LOW); digitalWrite(LED_triple_VERTE,LOW);
  digitalWrite(LED_triple_BLEUE,LOW);}

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


void Affiche_JETON_sur_USB() {for (byte I = 0; I < Index; I++) Serial.print(JETON[I]); Serial.println();}

void Regarde_si_JETON_orphelin_sur_USB() {// Donc arrivant du Moniteur ou du Bluetooth Esclave n°3.
  // Si le tampon USB contient du texte, réceptionne ce dernier dans JETON[].
  boolean Sortir = false;
  Index = 0; TIME_OUT = millis(); // Débute le chronométrage du TIME_OUT.
  //======================= Attente d'un JETON ====================
  while (!Sortir) { // Ci-dessous, ne pas descendre en dessous de la valeur 700.
        if (millis() - TIME_OUT > 700) Sortir = true;
        if (Serial.available()) Sortir = true;}
  //================ Si présent capturer le JETON =================
  while (Serial.available()) {CAR_USB = Serial.read();
         if ((Index < Lgr_JETON) && (CAR_USB != CR) && (CAR_USB != LF)) {
            //---------- Passer les lettre en MAJUSCULES ----------
            if ((CAR_USB >= 'a') && (CAR_USB < char(123))) CAR_USB = CAR_USB & 223;
            // Bien moins couteux en octets que Chaine_Memorisee.toUpperCase().
            //-----------------------------------------------------
            JETON[Index] = CAR_USB; Index++;} delay(5);} // Délai impératif.
  //===============================================================
  if (Developpement) {Serial.print(F(" Retour orphelin > "));
     if (Index == 0) Serial.print(F("Non.")); else Affiche_JETON_sur_USB(); Serial.println();}}

void Attente_de_la_synchronisation() {
  boolean Pair = false;
  if (Developpement) {Serial.println(); Serial.println(F(" Attente de la SYNCHRONISATION."));}
  //--------------- Affichage sur OLED durant 3,5 secondes ---------------
  u8g.firstPage(); do {// Début de la boucle d'affichage de la page écran.
    u8g.drawFrame(17,16,105,34); u8g.drawFrame(19,18,101,30); u8g.setPrintPos(40,30);
    u8g.print("Attente de"); u8g.setPrintPos(25,42); u8g.print("SYNCHRONISATION");}
  while(u8g.nextPage()); delay(3500);
  //------------ Envoyer "555" jusqu'à réception de ce texte /------------
  do {Compteur++; Vider_le_tampon_HC05();  // Changer l'affichage pour visualiser les tentatives :
     if (Pair) HC05_de_Sortie.println("555"); else HC05_de_Sortie.println("666"); Pair = !Pair;
     delay(800); Regarde_si_JETON_orphelin_sur_USB();
     //-------------------------------------------------------------------
     // Transcoder pour simplifier le test de fin de la boucle while.
     if (JETON[0] == '6') JETON[0] = '5'; if (JETON[1] == '6') JETON[1] = '5';
     if (JETON[2] == '6') JETON[2] = '5';}
     while ((JETON[0] != '5') || (JETON[1] != '5') || (JETON[2] != '5'));
     //--------------- Signale le début du dialogue 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()); Temps_pour_tester_le_dialogue = 0;}

void Reception_du_JETON_orphelin() {
  if (Developpement) digitalWrite(Relais,LOW); //Rétablit TX,RX du HC-05 d'entrée.
  digitalWrite(LED_triple_BLEUE, HIGH); delay(150); digitalWrite(LED_triple_BLEUE, LOW);
  JETON[2] = 'e'; // Pour que les JETONS 1:E, 2:E etc ne déclenchent pas un BIP d'erreur.
  Regarde_si_JETON_orphelin_sur_USB(); if (!INFINI) digitalWrite(Relais,HIGH);}
  // Ci-dessus : Isole TX,RX du HC-05 d'entrée même si Developpement = false ce qui évite un test inutile.

void Ecran_OLED_en_exploitation() {// Traite l'affichage d'une erreur éventuelle.
  if (JETON[2] == 'E')  {BIP(); digitalWrite(LED_triple_ROUGE,HIGH);}
  u8g.firstPage(); do {
    if (!Noir) {
       if (Silence) {u8g.drawVLine(115,1,13); u8g.setPrintPos(119,10); u8g.print('S');}
       Aff_cadre_a_quatre_lignes(); u8g.setPrintPos(10,10); u8g.print("Cmptr = "); u8g.print(Compteur);
       u8g.setPrintPos(10,26); u8g.print("JETON  : ");
       for (byte I = 0; I < SAV_Index; I++) u8g.print(SAV_JETON[I]);
       u8g.setPrintPos(10,42); u8g.print("Retour : ");
       if (Index > 0) for (byte I = 0; I < Index; I++) u8g.print(JETON[I]);
       else u8g.print("Non");
       if (JETON[2] == 'E') {u8g.drawVLine(89,31,16); u8g.setPrintPos(83,42);
          u8g.print("  E / "); u8g.print(JETON[0]); u8g.setPrintPos(10,58);
          switch(JETON[1]) {
            case '1' : {u8g.print("Lgr incorrecte."); break;}
            case '2' : {u8g.print("Action invalide."); break;}
            case '3' : u8g.print('S'), u8g.print(char(233)); u8g.print("parateur non ':'");}}
       else {if (INFINI) {u8g.setPrintPos(8,58); u8g.print(">>> Mode INFINI <<<");}}}}
    while(u8g.nextPage());}

void Orange_sur_LED_triple() {
  if (Allume) {digitalWrite(LED_triple_ROUGE, HIGH); digitalWrite(LED_triple_VERTE, HIGH);}
  else Eteindre_la_LED_triple();}

void Tester_le_dialogue() {
  Allume = true;
  Compteur++; HC05_de_Sortie.println("999");
  SAV_Index = 3; SAV_JETON[0] = '9'; SAV_JETON[1] = '9';  SAV_JETON[2] = '9';
  Reception_du_JETON_orphelin();
  if ((JETON[0] != '9') || (JETON[1] != '9') || (JETON[2] != '9')) {
     Avertissement_sur_OLED(); Temps_Ecoule_depuis_RESET = millis();
     //------------------ Attendre un clic sur le BP de A3 -------------------
     while (analogRead(BP_sur_A3) > 511) { // Attendre l'activation.
           //================= Chronométrage pour le clignotement ================
           if (millis() - Temps_Ecoule_depuis_RESET > 75)  {
              Temps_Ecoule_depuis_RESET = millis(); Allume = !Allume; Orange_sur_LED_triple();}
           //=====================================================================
           //-------------------- Tester le BP sur A1 --------------------
           if (analogRead(BP_sur_A1) < 512) { // Active OLED si noir.
              digitalWrite(LED_Arduino,HIGH);
              while (analogRead(BP_sur_A1) < 512); // Attendre le relâcher.
              Noir = false; Ecran_OLED_en_exploitation(); digitalWrite(LED_Arduino,LOW);}}
           //-------------------------------------------------------------
     while (analogRead(BP_sur_A3) < 511);} // Attendre la libération.
  else Ecran_OLED_en_exploitation();
  Eteindre_la_LED_triple(); digitalWrite(LED_Arduino,LOW);}

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());}

void Aff_cadre_a_quatre_lignes() {
  u8g.drawFrame(0,0,128,64); u8g.drawHLine(1,14,126); u8g.drawHLine(1,30,126); u8g.drawHLine(1,47,126);}

void Attendre_une_commande_sur_USB() {
  //----------- Effectuer une SAISIE sur le Moniteur -----------
  Index = 0;
  while (!Serial.available()) { // Attente d'une saisie sur le Moniteur.
        //================= Chronométrage pour le clignotement ================
        if (millis() - Temps_Ecoule_depuis_RESET > 75)  {
           Temps_Ecoule_depuis_RESET = millis(); Inverser_LED_Arduino();}}
        //=====================================================================
  digitalWrite(LED_triple_ROUGE,LOW); // Annule l'alerte rouge si erreur sur JETON précédent.
  while (Serial.available()) {CAR_USB = Serial.read();
        if ((Index < Lgr_JETON) && (CAR_USB != CR) && (CAR_USB != LF)) {
           //---------- Passer les lettre en MAJUSCULES ----------
           if ((CAR_USB >= 'a') && (CAR_USB < char(123))) CAR_USB = CAR_USB & 223;
              // Bien moins couteux en octets que Chaine_Memorisee.toUpperCase().
              //-----------------------------------------------------
              JETON[Index] = CAR_USB; Index++;} delay(5);} // Délai impératif.
  for (byte I = 0; I < Index; I++) SAV_JETON[I] = JETON[I]; SAV_Index = Index;}

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 Aff_caracteristiques_du_demonstrateur() {
  if (!Noir) {
     u8g.firstPage(); do {Aff_cadre_a_quatre_lignes();
        u8g.setPrintPos(15,10); u8g.print("Rev du "); u8g.print(Version);
        u8g.setPrintPos(15,26); u8g.print(Taille_PGM);
        u8g.setPrintPos(15,42); u8g.print("PILE - TAS = "); u8g.print(SRAM_LIBRE());
        u8g.setPrintPos(15,58); u8g.print("Compilateur 1.7.9");}
  while(u8g.nextPage());}}

void Aff_les_commandes() {
  if (!Noir) {
     u8g.firstPage(); do {Aff_cadre_a_quatre_lignes();
        u8g.setPrintPos(10,10); u8g.print("N : Ecran Noir.");
        u8g.setPrintPos(10,26); u8g.print("P : Programme.");
        u8g.setPrintPos(10,42); u8g.print("S : Silence.");
        u8g.setPrintPos(10,58); u8g.print("Z : Compteur = 0.");}
     while(u8g.nextPage());}}

void Traiter_la_Commande() {
  CAR_USB = SAV_JETON[0];
  if (CAR_USB == ',') CAR_USB = 'H'; if (CAR_USB == '?') CAR_USB = 'H';
  switch (CAR_USB) {
    case 'H' : {Aff_les_commandes(); break;}
    case 'N' : {Noir = !Noir; if (Noir) {u8g.firstPage(); do {} while(u8g.nextPage());}
                              else Aff_les_commandes(); break;}
    case 'P' : {Aff_caracteristiques_du_demonstrateur(); break;}
    case 'S' : {Silence = !Silence; break;}
    case 'T' : {Tester_le_dialogue(); break;}
    case 'Z' : Compteur = 0;}}

void Affiche_mode_INFINI_sur_OLED() {
  u8g.firstPage(); do {u8g.drawFrame(0,0,128,64); u8g.drawFrame(3,3,122,58);
     u8g.setPrintPos(33,18); u8g.print("ATTENTION :");
     u8g.setPrintPos(22,34); u8g.print("Passe en mode");
     u8g.setPrintPos(44,51); u8g.print("INFINI.");}
  while(u8g.nextPage());}

void Souligner() {Serial.println(F(" ----------------------------------"));}

void Presenter_le_PGM_sur_USB() {
  Serial.println(); Serial.print(F(" Poste de PILOTAGE-A : Version du ")); Serial.println(Version);
  Souligner(); Serial.println(F(" Version de developpement pour"));
  Serial.println(F(" proposer des JETONs manuellement."));  Souligner();
  Serial.println(F(" * Le relais d'isolation Fig.80 est en place."));
  Serial.println(F(" 1) Inverseur Fig.80 sur PGM.")); Serial.println(F(" 2) Televerser le programme."));
  Serial.println(F(" 3) Inverseur Fig.80 sur UT.")); 
  Serial.println(F(" 4) Activer le Moniteur : Le relais est au travail."));
  Serial.println(F(" 5) Saisir 555 ou 666 : Debut du dialogue."));
  Serial.println(F(" 6) Saisir librement des JETONS.")); Souligner();
  Serial.println(F("  >>>> Commande I : INFINI.")); Souligner();
  Serial.print(F("  >>>> Commande T : Test du r")); Serial.print(char(233)); Serial.println(F("seau.")); 
  Souligner(); Serial.println(F(" Help avec 'H','?' ou ','."));}

void TX_un_JETON(String JETON) {
  HC05_de_Sortie.println(JETON); Compteur++;
  Reception_du_JETON_orphelin(); Ecran_OLED_en_exploitation();
  digitalWrite(LED_triple_ROUGE,LOW); // Annule une erreur précédente en éteignant la LED triple rouge.
  delay(500);}

void Eteindre_les_Ecrans() {TX_un_JETON("1:A"); TX_un_JETON("2:A"); delay(100);}

void Active_les_Ecrans_poste_de_Travail() {TX_un_JETON("1:B"); TX_un_JETON("2:B"); delay(100);}

void Eteindre_les_LEDs_sur_les_postes_de_travail() {TX_un_JETON("1:D"); TX_un_JETON("2:D");}

//================== Procédures du mode automatique : Génération des JETONs aléatoires ==================
void Selectionne_un_poste() {
  byte Poste;
  Poste = random(1,4);
  if (Poste == 3) {
     Un_sur_5++; if (Un_sur_5 == 5) Un_sur_5 = 0;
                 else Poste = random(1,3);}
  Adresse_Poste = char(Poste + 48);} // Transforme le byte en char.

void Selectionne_une_action() {
  byte Chiffre;
  Chiffre = random(1,12);
  if ((Chiffre == 1) || (Chiffre == 2)) Chiffre = random(3,12); // Ne pas agir sur Noir/Écran. 
  ACTION = char(Chiffre + 64);} // Transforme le byte en lettre majuscule.

void Genere_un_JETON_aleatoire() {
  Index = 3; Selectionne_un_poste(); Selectionne_une_action(); // Impérativement dans cet ordre.
  JETON[0] = Adresse_Poste;
  if (Adresse_Poste != '3') {JETON[1] = ':'; JETON[2] = ACTION;}
  else { JETON[1] = 'x'; JETON[2] = 'E';}
  SAV_Index = 3; SAV_JETON[0] = JETON[0]; SAV_JETON[1] = JETON[1];  SAV_JETON[2] = JETON[2];}

void Transmet_un_JETON() {
  for (byte I = 0; I < Index; I++) HC05_de_Sortie.write(JETON[I]);
  HC05_de_Sortie.write(CR); HC05_de_Sortie.write(LF);}

void Reception_sur_reseau() {
  Compteur++; Reception_du_JETON_orphelin(); Ecran_OLED_en_exploitation();}
  
void TX_JETON_et_Aff_orphelin_sur_OLED() {Transmet_un_JETON(); Reception_sur_reseau();}

void Mode_automatique() {// Booléen INFINI : Pour ne plus que le relais d'isolement batte à chaque JETON.
  //---------------------------- Préparations initiales ----------------------------
  if (Developpement) {
     Serial.println(); Serial.println(); Serial.println(F(" Mode INFINI : Sortie par RESET."));}
  INFINI = true; Developpement = false; digitalWrite(LED_Arduino,LOW); Silence = true;
  digitalWrite(Relais,LOW); // Rétablit TX,RX du HC-05 d'entrée de façon statique.
  Temps_pour_tester_le_dialogue = millis(); // Démarre le chronométrage pour vérifier la communication.
  //--------------------- Génère les JETONS en boucle infinie ----------------------
  while (true) {// Boucle de génération de JETONs INFINIE.
     //-------------- Vérification du dialogue toutes les 30 secondes --------------
     if (millis() - Temps_pour_tester_le_dialogue > 30000)  {
        Temps_pour_tester_le_dialogue = millis(); Tester_le_dialogue();}
     //---------------------------- Tester le BP sur A1 ----------------------------
  if (analogRead(BP_sur_A1) < 512) {
     digitalWrite(LED_Arduino,HIGH);
     while (analogRead(BP_sur_A1) < 512); // Attendre le relâcher.
     Noir = !Noir; if (Noir) Eteindre_les_Ecrans();
                   else {Ecran_OLED_en_exploitation(); Active_les_Ecrans_poste_de_Travail();}
     digitalWrite(LED_Arduino,LOW);}
     //------------------------ Transmet un JETON aléatoire ------------------------
     Genere_un_JETON_aleatoire(); TX_JETON_et_Aff_orphelin_sur_OLED();
     if (JETON[2] == 'E') digitalWrite(LED_triple_ROUGE,LOW);}}

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

void setup() {
  pinMode(RXD,INPUT); pinMode(TXD,OUTPUT); pinMode(LED_Arduino,OUTPUT); pinMode(LED_triple_ROUGE,OUTPUT);
  pinMode(LED_triple_VERTE,OUTPUT); pinMode(LED_triple_BLEUE,OUTPUT); Eteindre_la_LED_triple();
  pinMode(Relais,OUTPUT); digitalWrite(Relais,HIGH);
  pinMode(BUZZER,OUTPUT); digitalWrite(BUZZER,LOW);
  pinMode(BP_sur_A1,INPUT); // Broche en entrée et R PULLUP sur le circuit imprimé.
  HC05_de_Sortie.begin(9600);
  u8g.setFont(u8g_font_6x10); // Police de matrices de 6x10 pixels lettres MJA/min comprises.
  while(HC05_de_Sortie.available()) CAR_USB = HC05_de_Sortie.read(); // Vider le tampon.
  Compteur = 0; Developpement = true; INFINI = false; Led_Arduino = true; Noir = false; Silence = false;
  //-----------------------------------------------------------------------------
  Serial.begin(9600); while (Serial.available()) CAR_USB = Serial.read(); // Vider le tampon série.
  Presenter_le_PGM_sur_USB(); Temps_pour_tester_le_dialogue = millis();
  //---------------------------- Tester le BP sur A3 ----------------------------
  if (analogRead(BP_sur_A3) < 512) {
     digitalWrite(LED_Arduino,HIGH); Affiche_mode_INFINI_sur_OLED();
     while (analogRead(BP_sur_A3) < 512); // Attendre le relâcher.
     digitalWrite(LED_Arduino,LOW); Mode_automatique();}
  //-----------------------------------------------------------------------------
  Attente_de_la_synchronisation(); Vider_le_tampon_HC05();
  if (Developpement) {Serial.println(F(" Debut du dialogue.")); 
  Serial.println(F(" Eteindre toutes les LEDs.")); Serial.println(F(" Allumer les Ecrans OLED."));
  Serial.println();} Eteindre_les_LEDs_sur_les_postes_de_travail(); Active_les_Ecrans_poste_de_Travail();}

void loop() { // Attente sur Moniteur ou génération automatique en mode NON Developpement.
  if (Developpement) { Serial.println(); Serial.print(F(" Saisir un JETON > "));
                     Attendre_une_commande_sur_USB(); Affiche_JETON_sur_USB();}
  //=============================================================================
  if (Index > 1) TX_JETON_et_Aff_orphelin_sur_OLED();
  //-----------------------------------------------------------------------------
  else { Traiter_la_Commande(); // // Traite les commandes 'H', 'N', 'P', 'S' et 'T'.
       if (CAR_USB == 'I'){Affiche_mode_INFINI_sur_OLED();  delay(2000); Mode_automatique();}
       if ((CAR_USB == 'S') && (!Noir)) {
           u8g.firstPage(); do {u8g.setPrintPos(25,36); u8g.print("Commande S.");} while(u8g.nextPage());}
       if ((CAR_USB == 'Z') && (!Noir)) {
           u8g.firstPage(); do {u8g.setPrintPos(25,36); u8g.print("Commande Z.");} while(u8g.nextPage());}}}
