/* Programme relatif au Poste de travail pour tester un réseau en anneaux par Bluetooth HC-05 avec trois
   unités. Deux sont des Postes de Travail avec pour chacun des tâches spécifiques. Toutefois, les six
   premiers Travaux sont communs à toutes les "unités de fabrication".
   Le démonstrateur est prévu pour une carte NANO élargie avec afficheur OLED de 32 x 128 PIXELs.
   La LED d'Arduino clignote tant qu'un premier jeton concernant le poste n'a pas été réceptionné.
   Par défaut aucune LED n'est allumée, OLED est actif et l'encadrement est affiché.
   >>>>>>> Ce démonstrateur concerne le poste de travail n°1 d'adresse 1 utilisant le circuit de
           de développement UNIVERSEL qui ne dispose que de la LED triple et la Rouge de 3mm de diamètre.
           Naturellement il faudra enlever le Strap et réunir la LED sur D9 par exemple qui est disponible
           le pilotage se faisant en logique négative

     ********************** À modifier sur chaque nouveau poste de travail *********************
     *    • Mettre à jour #define Nb_Actions_MAX 'J'.                                          *
     *    • La procédure Recevoir_un_JETON()() doit être adaptée sur if (JETON[0] == 'N').     *
     *    • Adapter la procédure Traite_le_TRAVAIL().                                          *
     *    • Adapter les textes dans la procédure Ecran_Dialogue().                             *
     *******************************************************************************************

BRANCHEMENTS à effectuer :
--------------------------
   En entrée : Esclave 1 : GND -> GND  VCC -> +5V ou +3,3V   TXD -> (RX) D0  (TX) D1 -> RXD avec R1/R2
   En sortie : Maître 2  : GND -> GND  VCC -> +5V ou +3,3V   TXD -> D2            D3 -> RXD avec R1/R2
   ATTENTION : A4 et A5 sont réservés pour la gestion de l'écran OLED.
   D6 est relié à la LED tricolore Rouge.
   D7 est relié à la LED tricolore Verte.
   D8 est relié à la LED tricolore Bleue.
   D9 est branché sur la LED rouge de 3mm de diamètre. (Strap enlevé")
   
NOTE : Comme sur le module "UNIVERSEL" il n'y a pas de liaison avec les sorties, STATE (Autre que le
       pilotage des LEDs vertes.) il n'est pas possible de tester l'accouplement entre
       les modules. Ce n'est pas impératif, car pour tester le fonctionnement du réseau le Maître se
       contente de transmettre un JETON adressé "à personne" et attend en retour un JETON orphelin. Quand
       il le reçoit c'est que le réseau fonctionne. Pour en vérifier l'activité, toutes les minutes
       il réitère le test avec JETON "anonyme".
   
Compilateur v1.7.9.              PGM               RAM dynamique
Developpement               14678 Octets (47%)    1343 Octets (65%)
Utilisation                 14492 Octets (47%)    1343 Octets (65%) */

//------------------------ Constantes du programme --------------------------
#define Version "21/09/25." // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Developpement false // Utilise le moniteur pour envoyer les JETONS. (HC-05 en entrée enlevé @@@@@@@@@
#define Lgr_TEXTE 5 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Nb_Actions_MAX 'J' // Nombre maximum d'actions possibles sur ce poste @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#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 RX 0 // Va sur TXD du module Bluetooth d'Entrée mais pas exploité.
#define TX 1 // Va sur RXD du module Bluetooth d'Entrée avec pont de résistances.
#define TXD 2 // Va sur TXD du module Bluetooth de Sortie mais n'est pas exploité.
#define RXD 3 // Va sur RXD du module Bluetooth de Sortie avec pont de résistances.
#define LED_triple_ROUGE 6
#define LED_triple_VERTE 7
#define LED_triple_BLEUE 8
#define LED_rouge_3mm 9
#define LED_Arduino 13
//------------------- Définition des broches abanoliques --------------------
// Néant.

//---------------------- 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_en_SORTIE(TXD,RXD);
#include <U8g2lib.h>   // L'afficheur est sur A4 et A5 pour SDA et SCL.
#include <SPI.h>
#include <Wire.h>
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0);

//------------------------- Variables du programme --------------------------
boolean Clignote_si_JETON_non_acquis, Encadrement, Ne_TX_pas_le_JETON, Noir;
char CAR_USB, Erreur, SAVJ0, SAVJ1, SAVJ2;
byte Index;
char JETON[Lgr_TEXTE];
unsigned long Clignotement = 0;
//========================= Procédures de servitude ============================
void Inverser_LED_Arduino() {digitalWrite(LED_Arduino,!digitalRead(LED_Arduino));}

void Vider_les_deux_tampons() {
  while(Serial.available()) Serial.read(); // Vider le tampon de RX.
  while(Module_HC05_en_SORTIE.available()) Module_HC05_en_SORTIE.read();} // Vider le tampon de RXS.

void Affiche_ATTENTE_sur_OLED() {
  u8g2.clearBuffer(); // Efface la mémoire interne.
  u8g2.drawFrame(2,0,126,32);
  u8g2.setFont(u8g2_font_shylock_nbp_tf); // Choisir la police de caractère affichée.
  u8g2.drawStr(10,14,"Version"); u8g2.drawStr(64,14,Version);u8g2.drawStr(10,28,"Attend  un JETON.");
  u8g2.sendBuffer();} // Transférer le texte sur l'afficheur.

void Analyseur_syntaxique() {// Vérifie le texte présent dans JETON[].
  Erreur = '0';
  if (Index != 3) Erreur = '1';
  if ((JETON[2] < 'A') || (JETON [2]> Nb_Actions_MAX)) Erreur = '2';
  if (JETON[1] != ':') Erreur = '3';}

void Saisie_JETON_sur_USB() {// Donc arrivant du Moniteur ou du Bluetooth Esclave n°1.
  Index = 0;
  while (!Serial.available()) { // Attente d'une saisie sur le Moniteur.
        //================== Chronométrage pour JETON non trouvé ==================
        if (Clignote_si_JETON_non_acquis) {
           if (millis() - Clignotement > 75) {Clignotement = millis(); Inverser_LED_Arduino();}}}
        //-------------------------------------------------------------------------
  while (Serial.available()) {CAR_USB = Serial.read();
         if ((Index < Lgr_TEXTE) && (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.

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

void Transmet_le_JETON_en_sortie() {
  for (byte I = 0; I < Index; I++) Module_HC05_en_SORTIE.print(JETON[I]);
       Module_HC05_en_SORTIE.write(CR); Module_HC05_en_SORTIE.write(LF);
       Ne_TX_pas_le_JETON = false; // Pour afficher le JETON sur OLED au lieu de "///".
  if (Developpement) {Serial.print(F("JETON en sortie : ")); Liste_le_contenu_de_JETON();}}

void Ecran_Dialogue() {
  u8g2.clearBuffer(); // Efface la mémoire interne.
    if (!Noir) {
       if (Encadrement) u8g2.drawFrame(2,0,126,32);
       u8g2.setFont(u8g2_font_shylock_nbp_tf); // Choisir la police de caractère affichée.
       u8g2.drawStr(18,14,"JETON  TX1 = "); u8g2.setCursor(98,14); u8g2.print(SAVJ0);
       u8g2.print(SAVJ1); u8g2.print(SAVJ2); u8g2.drawStr(18,28,"JETON RX2 = "); u8g2.setCursor(98,28);
       if (Ne_TX_pas_le_JETON) {u8g2.print('/');  u8g2.print('/');  u8g2.print('/');} 
       else {u8g2.print(JETON[0]);  u8g2.print(JETON[1]);  u8g2.print(JETON[2]);}}
  u8g2.sendBuffer();} // Transférer le texte sur l'afficheur.

void Recevoir_un_JETON() {
  Saisie_JETON_sur_USB();
  if (Developpement) {Serial.println(); Serial.print(F("JETON re")); Serial.print(char(231));
     Serial.print(F("u : ")); Liste_le_contenu_de_JETON();}
  SAVJ0 = JETON[0]; SAVJ1 = JETON[1]; SAVJ2 = JETON[2]; // Mémorise le message précédent.
  if (JETON[0] == '1') {Analyseur_syntaxique();
     if (Erreur > '0') {JETON[1] = Erreur; JETON[2] = 'E'; Transmet_le_JETON_en_sortie(); Ecran_Dialogue();}
     else {digitalWrite(LED_Arduino, LOW); Traite_le_TRAVAIL(); Ne_TX_pas_le_JETON = true;
           Ecran_Dialogue();}}
  else {Transmet_le_JETON_en_sortie(); Ecran_Dialogue();}}

//================= Procédures spécifiques au poste de travail =================
void Eteindre_toutes_les_LEDs() {
  digitalWrite(LED_triple_ROUGE, LOW); digitalWrite(LED_triple_VERTE, LOW);
  digitalWrite(LED_triple_BLEUE, LOW); digitalWrite(LED_rouge_3mm, HIGH); digitalWrite(LED_Arduino, LOW);}

void Allume_une_LED(byte Num_LED) {
  Eteindre_toutes_les_LEDs();
  switch(Num_LED) {
    case 1 : {digitalWrite(LED_triple_ROUGE, HIGH); break;}
    case 2 : {digitalWrite(LED_triple_VERTE, HIGH); break;}
    case 3 : {digitalWrite(LED_triple_BLEUE, HIGH); break;}
    case 4 : {digitalWrite(LED_rouge_3mm, LOW); break;}
    case 13 : digitalWrite(LED_Arduino, HIGH);}}

void Traite_le_TRAVAIL() {
  switch (JETON[2]) {
     case 'A' : {Noir = true; break;}
     case 'B' : {Noir = false; break;}
     case 'C' : {Allume_une_LED(13); break;}
     case 'D' : {Eteindre_toutes_les_LEDs(); break;}
     case 'E' : {Encadrement = true; break;}
     case 'F' : {Encadrement = false; break;}
     case 'G' : {Allume_une_LED(4); break;}
     case 'H' : {Allume_une_LED(3); break;}
     case 'I' : {Allume_une_LED(2); break;}
     case 'J' : Allume_une_LED(1);}}

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

void setup() {
  Serial.begin(9600); Serial.println(); Serial.print(F(" POSTE de travail num 1 : Version du "));
  Serial.println(Version); Serial.println(); Serial.println(F(" Attend un premier JETON."));
  Serial.println();
  pinMode(LED_Arduino, OUTPUT); pinMode(LED_triple_ROUGE, OUTPUT); pinMode(LED_triple_VERTE, OUTPUT);
  pinMode(LED_triple_BLEUE, OUTPUT); pinMode(LED_rouge_3mm, OUTPUT); Eteindre_toutes_les_LEDs();
  //------------- Initialisation de la voie série complémentaire -------------
  pinMode(RXD,OUTPUT); pinMode(TXD,INPUT); Module_HC05_en_SORTIE.begin(9600);
  //----------- Affichage OLED avant synchronisation des Bluetooth -----------
  u8g2.begin(); // Initialisation de l'afficheur local OLED.
  Encadrement = true; Noir = false; Clignote_si_JETON_non_acquis = true; Affiche_ATTENTE_sur_OLED();
  //-------------- Attente confirmation des dialogues Bluetooth --------------
  Vider_les_deux_tampons(); Recevoir_un_JETON(); Clignote_si_JETON_non_acquis = false;
  digitalWrite(LED_Arduino, LOW);}

void loop() {Recevoir_un_JETON();} // Le recevoir et le traiter ou faire suivre.

// Le module Arduino élargi avec afficheur OLED installé présente un défaut. En effet, les deux
// colonnes de PIXELs situées à gauche ne s'allument pas. Pour pouvoir conduire le développement
// le module est utilisé en "mode dégradé" c'est à dire que la définition est considérée comme
// étant de 32 x 126 et tous les affichages sont cadrés dans ce format. Ainsi le programme
// présente correctement les données et les afficheurs corrects ne seront pas influencés. Donc ne pas
// s'étonner des cadrages "décalés" de deux colonnes à droite.

