/************************************************************************************************************************************************************
* Affichage sur LCD I2C 128x64 ----  Plusieurs Page General : Rotatif Bouton (+) Bouton (-) de scrolling          -------------------------           Version UNO R4
*                                    Menu selection Rotatif --> Lancement Fonction
************************************************************************************************************************************************************
* Menu (encadré) Avec selection rotative de 5 Choix max sur plusieurs pages
* 3 Boutons : OK (entree et selection de la fonction) Bouton (+) Bouton (-) de scrolling
* --> Remplir TextAffich pour les element afficher du menu (calcul automatique du nombre de pages)
* Execution de la fonction demande par retour du numero de la fonction choisis
* 
* Fonction execution de la Fonction
* fonctionSelect = ScanMenu();                                                                         // Lancement de la fonction Menu 2 pages avec 3 boutons 
* if ( fonctionSelect != 0 ) ConfigureLCD(fonctionSelect);                                             // Configure avec menu LCD si fonctionSelect different de 0
* Version Boutons interruption
* 
************************************************************************************************************************************************************
*     LCD TFT - I2C - 128x64 - GM12864-59N VER2.0 -----  ST7567S 
************************************************************************************************************************************************************
* Fonction : Affichage d'un Menu de sélection de 5 choix Max // 2 pages
* Bouton Select                            PORT D8
* Scroll rotatif du menu sens bas (+)      PORT D2
* Scroll rotatif du menu sens haut (-)     PORT D3
************************************************************************************************************************************************************
* Entrée : 
* Digital Button sur PORT Digital 
* http://www.seeedstudio.com/wiki/Grove_-_Button 
* 
* Sortie : Ecran LCD : I2C LCD_GM12864_64x128
* LCD TFT - I2C - 128x64 - GM12864-59N VER2.0 -----  ST7567S 
************************************************************************************************************************************************************
* Librairie : U8g2lib.h (Version U8g2-2.35.30)    https://www.arduinolibraries.info/libraries/u8g2?utm_source=chatgpt.com
************************************************************************************************************************************************************/
// Déclaration / Librairie
// Initialisation de l'écran LCD I2C GM12864 59n VER2.0 -----  ST7567S - 64*128
#include <U8g2lib.h>
#include <Wire.h>
U8G2_ST7567_ENH_DG128064I_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);           // OK !! -- Mode _F_ → Full Frame Buffer -- 128 × 64 / 8 = 1024 octets  -- _SW_I2C : Software I²C (bit-banging)
//U8G2_ST7567_ENH_DG128064I_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);                   // plus performant I2C materiel == bug
//U8G2_ST7567_JLX12864_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); // contrast
//U8G2_ST7567_ENH_DG128064_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);  // bug decalage


// Declaration Fonction Interruption
boolean Detect_SelectOK();                                                           // Bouton OK
boolean BoutonScanScrollPlus();
boolean BoutonScanScrollMoins();
// Declaration Fonction 
void AffichageLCD_Principal();                                                       // Affichage Principal
unsigned char ScanMenu();                                                            // Fonction : Entree Bouton ok (+) (-) sortie menu selectionner comptScroll 
void ConfigureLCD(unsigned char fonctionSelect);                                     // Fonction : Entree comptScroll --> Sortie Execute menu selectionne                                 


// Prototypes des ISR (important si définies plus bas)
void ISR_Detect_SelectOK();
void ISR_BoutonScanScrollMoins();
void ISR_BoutonScanScrollPlus();

void EffaceCaract(uint8_t ligne, uint8_t decalPixel, uint8_t nbrCaract);                              // EffaceCaract(ligne (1 a7) , nbr de decalage de caract en commancant a droite , nombre de caractera a effacer )
void EffaceLigne(uint8_t ligne);
void DrawIP(uint8_t xo, uint8_t yo, const char* text, uint8_t IP[4], uint8_t selected);
void CoeurPointLigneLCD(unsigned char  ligne);

                                                                         // Lancement de la fonction Menu 2 pages avec 3 boutons 

/*************************************************************************/

// Constante pour Interruption
#define  buttonPinOK D8                                                             // crée un identifiant pour la broche utilisée sur le Connecteur Digital D5 -- Interruption
volatile boolean etatSelectOK = 0;                                                  // Variable d'interruption (volatil) pour l'état actuel du bouton poussoir pour la séléction du Menu et la sortie du Menu
volatile boolean ISR_Etat_BoutonMoins = 0;
volatile boolean ISR_Etat_BoutonPlus = 0;

unsigned long dernierTemps = 0;                                                     // pour le debounce
const unsigned long delaiDebounce = 250;                                            // ms
                                                         
// Constante pour Bouton + / - Interruption
#define  buttonPinScrollPlus  D2                                                    // crée un identifiant pour la broche utilisée avec le bouton poussoir
#define  buttonPinScrollMoins D3                                                    // crée un identifiant pour la broche utilisée avec le bouton poussoir
unsigned char comptScroll = 1 ;                                                     // SORTIE FONCTION MENU pour incrementer le menu (Menu commence a 1 jusqua xx
unsigned char last_comptScroll = 1 ; 

// Variable Affichage Principale
#define  max_page_affichagePrincipale 3
unsigned char page_en_cours_affichagePrincipale = 1;

// Variable Menu LCD ( Boucle principale loop)
char fonctionSelect = 0;                                                                 // Variable de sortie contenant le numero du menu du LCD choisis 
int decalPixel = 0;                                                                     // Nombre de decalage du texte affiche sortie fonction decalPixel=u8g2.drawStr(

// Varialble coeur --> Affichage de point defilant sur le LCD
char comptCoeurLCD_Point = 0;                                                            // Coeur LCD --> Affiche des points 


// Varialble Affichage LCD fonctionnement normal (toutes les 1s
boolean etatServeurWEB = 0;                                                              // Variable connexion au serveur WEB -- Mise a jour par le serveur WEB
//boolean validMessConnexionWEB = 0;                                                       // Pour LCD
unsigned long previousMillisWEB = 0;                                                     // TimeOut Serveur WEB : variable pour un break dans la boucle du serveur WEB
boolean flagServeurWEB_Actif = 0;                                                        // variable aquittement affichage connexion serveur WEB en cours
char comptAffichageLCD = 0;                                                              // 
unsigned long previousMillisAffichageLCD = 0;                                            // previousMillisAffichageLCD
boolean validMessConnexionFTP = 0;                                                       // variable aquittement affichage connexion serveur FTP en cours
char bufferIP[16];                                                                       // "255.255.255.255" + \0
unsigned long previousMillisConnexionInternet = 0;                                       //




// Variable pour la fonction Menu -- Avec affichage d'un cadre : ligne 20 caractere : xx colone Menu  -- xx pages
// +--------------------+
// |-  Menu Selection  -|  Ligne 1
// |                    |        2
// | Select Fonction 1  |        3   -->  LigneDebutMenu
// | Select Fonction 2  |        4
// | Select Fonction 3  |        5
// | Select Fonction 4  |        6
// | Select Fonction 5  |        7   -->  LigneFinMenu
// +--------------------+
//#include <TimerOne.h>                                                              // Librairie Interne Time pour Interruption Arduino UNO
const char LigneDebutMenu = 2;                                                       // ENTREE ---> Ligne ou commence le Menu 
const char LigneFinMenu = 6;                                                         // ENTREE ---> Ligne ou termine le Menu 
const char nbrMaxLigneParPage = LigneFinMenu - LigneDebutMenu + 1 ;                  // Nombre max de choix dans le menu de 1 a 5 -- Le menu commence a la ligne 2 jusqu'a 6 de l'ecran    


// ENTREE ---> Remplir la variable Textaffich avec les elements du menu
// Attention : le nombre de Fonction doit corresponde au nombre de fonction par page --> Exemple : LigneDebutMenu et LigneFinMenu = 5 fonctions / page donc pour trois pages : TextAffich aura 15 Fonctions
// Texte a afficher                    |1                       |24|                        |  |                        |  |                        |  |                        |  
const char *TextAffich[] = { "NOZERO", " WEB        : ON / OFF  ", " FTP        : ON / OFF  ", " Datalogger : ON / OFF  ", " Login WEB  : ON / OFF  ", " Login Telnet / Serial  ",
                                 " Configure IP           ", " Configure Netmask      ", " Configure Gateway      ", " Ping .........         ", " Exit                   ", "xxxNOxxx" };
// Calcul de la talle des element que constitue TexAffich (faire -2 pour le debut et la fin)
#define countofTxt(TextAffich) (sizeof(TextAffich)/sizeof(TextAffich[0]))

//const int nbrDePage = 0;                                                           // Nombre de page
const int nbrDePage = ( countofTxt(TextAffich) - 2 ) / nbrMaxLigneParPage;           // Calcul automatique du nombre de page en fonction de la taille de Textaffich
// Exemple ici TextAffich = 11 -2 = 10 donne 2 pages
// Variable Fonction Menu

// Varialble coeur --> Affichage de point defilant sur le LCD
char comptCoeurLCD = 0;                                                              // Coeur LCD --> Affiche des points 
unsigned long previousMillisCoeurLCD = 0;                                            // Coeur LCD --> Affiche des points

/*********************************************************************************************************************/
//**************  Initialisation (Setup)           *******************************************************************/
/*********************************************************************************************************************/
void Setup_Initialisation_LCD_GM12864()
{
 // Declaration Initialisation Interruption
  pinMode(buttonPinOK         , INPUT_PULLUP);                                       // met la broche en entrée 
  pinMode(buttonPinScrollPlus , INPUT_PULLUP);                                       // met la broche en entrée 
  pinMode(buttonPinScrollMoins, INPUT_PULLUP);                                       // met la broche en entrée 

  attachInterrupt(digitalPinToInterrupt(buttonPinOK)          , ISR_Detect_SelectOK       , RISING); 
  attachInterrupt(digitalPinToInterrupt(buttonPinScrollMoins) , ISR_BoutonScanScrollMoins , RISING); 
  attachInterrupt(digitalPinToInterrupt(buttonPinScrollPlus)  , ISR_BoutonScanScrollPlus  , RISING); 

// Initialisation Libraire Ecran LCD
  Wire.begin();
  u8g2.setI2CAddress(0x3F * 2);                                                       //u8g2.setI2CAddress(0x3F);
   u8g2.setBusClock(1000000);
 // u8g2.setBusClock(800000);   //ok                                                 //  u8g2.setBusClock(400000);      // ok  // u8g2.setBusClock(200000);   // u8g2.setBusClock(100000);
  u8g2.begin();

  //u8g2.clearBuffer();
  
  //u8g2.enableUTF8Print();                                                           // enable UTF8 support for the Arduino print() function
  u8g2.setFont(u8g2_font_profont10_tf);                                               // 7 linge de 24 caractere Max avec cadre largeur 5 x hauteur 8
//u8g2.setFont(u8g2_font_lucasfont_alternate_tf);                                     //  --- hauteur 8pix - ligne 20 caracters ok
//u8g2.setFont(u8g2_font_6x10_tr);
//u8g2.setFontDirection(0);
  u8g2.setFontMode(1);                                                                // 1 text blanc Transparent   -- 0 text noir
  u8g2.setContrast(conf.lcdRetro);

  u8g2.drawBitmap(0, 0, 16, 64, iotos_logo);
  u8g2.sendBuffer();
  delay(4000);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AffichageLCD_Principal() {
// Execute Fonction Scan Menu -> LCD_GM12864_64x128.h
  fonctionSelect = ScanMenu();                                                                           // Lancement de la fonction Menu 2 pages avec 3 boutons 
  if ( fonctionSelect != 0 ) ConfigureLCD(fonctionSelect);                                               // Configure avec menu LCD si fonctionSelect different de 0

// Choix Affichage de la page Principale
  if ( ISR_Etat_BoutonMoins  == 1)  { comptScroll--;   ISR_Etat_BoutonMoins = 0; }                     // 
  if ( ISR_Etat_BoutonPlus   == 1)  { comptScroll++;   ISR_Etat_BoutonPlus  = 0; }                     // Lecture des boutons (+) et (-) --> validAffichage = 1 et comptScroll++ ou --
  if (comptScroll == 0) comptScroll = max_page_affichagePrincipale;
  if (comptScroll == max_page_affichagePrincipale + 1 ) comptScroll = 1;                               // Page principale : comptScroll = 1

  if ( ( millis() - previousMillisAffichageLCD ) >= 1000 )                                             // Ne fait l'affichage que toute les 0,5s
  {
      if (comptScroll != last_comptScroll ) u8g2.clearBuffer();                                        // Efface l'ecran que si la page a change
      last_comptScroll = comptScroll;
      
      u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                                                         //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                                     
      switch (comptScroll)
            {
            case 1 : {
              // Affichage Page principale LCD  
              //u8g2.drawStr(3, 2+8 * 0 ,"-   -    -    -    -   -");                              // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
              u8g2.drawStr(3, 2+8 * 1 ,"  ----  Prise IP  ----  ");

              
              //Serial.println("Affichage Page principale LCD");  //Serial.println();
              // 3eme ligne
              decalPixel = u8g2.drawStr(3, 2+8 * 3 ," IP  : ");                                             // decalPixel va donne 7*5 = 35
              IPAddress ip = Ethernet.localIP();
              sprintf(bufferIP, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
              //EffaceCaract(3, decalPixel, 16);                                                            // void efface(ligne, decalPixel, nbrCaract);
              u8g2.drawStr(3 + decalPixel, 2 + 8 * 3, bufferIP);
            
            // 4eme ligne			  
              decalPixel = u8g2.drawStr(3, 2+8 * 4 ," LED : ");
              EffaceCaract(4, decalPixel, 3 );                                                              // void efface(ligne, decalPixel, nbrCaract);
              conf.led == 0 ?           u8g2.drawStr(3+decalPixel , 2+8 * 4 , "OFF") : u8g2.drawStr(3+decalPixel , 2+8 * 4 , "ON ");
              
              // 5eme ligne
              decalPixel = u8g2.drawStr(3, 2+8 * 5 ," WEB : "); 
              EffaceCaract(5, decalPixel, 3 );                                                              // void efface(ligne, decalPixel, nbrCaract);
              conf.SrvWEBswitch == 0 ?  u8g2.drawStr(3+decalPixel , 2+8 * 5 , "OFF") : u8g2.drawStr(3+decalPixel , 2+8 * 5 , "ON ");

              // 5eme ligne
              decalPixel = u8g2.drawStr(3 + 64, 2+8 * 5 ," FTP : ");              // Moitier ecran 5em ligne
              decalPixel = decalPixel + 64 ;             
              EffaceCaract(5, decalPixel , 3 );                                                              // void efface(ligne, decalPixel, nbrCarac);
              conf.SrvFTPswitch == 0 ?  u8g2.drawStr(3+decalPixel , 2+8 * 5 , "OFF") : u8g2.drawStr(3+decalPixel , 2+8 * 5 , "ON ");

              if ( etatServeurWEB == 1)                                                                             // Detection connexion serveur WEB 
                {                                                                                                    // attention declaration variable validMessConnexionWEB dans serveurWEB.h
                  //EffaceCaract(6, 1, 20);
                  EffaceLigne(6);
                  //u8g2.drawStr(3, 2+8 * 0 ,"-   -    -    -    -   -");                                          // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
                  u8g2.drawStr(3+0 , 2+8*6, " Connexion WEB en cours");
                  //u8g2.sendBuffer();
                  //etatServeurWEB = 0;
                  flagServeurWEB_Actif = 1;   // Pour effacement
                }

              if ( flagServeurWEB_Actif && (millis() - previousMillisWEB >= 5*1000 )  )                            // Utilisation du timeout pour fin de connexion
                {
                  EffaceLigne(6);
                  //u8g2.setDrawColor(0);
                  //u8g2.drawBox(3 , 2+8*6 -8 , 25*5 -2 , 8);
                  //u8g2.setDrawColor(1);
                  //Serial.print(F("."));
                  flagServeurWEB_Actif = 0;
                }
              
              // Coeur : point qui defile sur la ligne 6
              u8g2.drawStr(3+6*comptCoeurLCD_Point , 2+8*7 , "...");
              comptCoeurLCD_Point++;
              comptCoeurLCD_Point++;
              comptCoeurLCD_Point++;
              if (comptCoeurLCD_Point >= 24 ) 
                    {  
                      u8g2.setDrawColor(0);                                                                // Efface la ligne
                      u8g2.drawBox(3 , 2+8*7 -8 , 25*5 -2 , 8);                                            // u8g2.drawBox( x0 , yo , w , h );     - box pleine  u8g2.drawBox(3+decalPixel, 2+8*3-8, 3*6, 8); // largeur=3 caractères*6 px, hauteur=8 px
                      u8g2.setDrawColor(1);                   
                      comptCoeurLCD_Point = 0;                 
                    }

            } break;  // Fin case 1

            case 2 : {
              //u8g2.drawStr(3, 2+8 * 0 ,"-   -    -    -    -   -");                              // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
              u8g2.drawStr(3, 2+8 * 1 ," ----  Connexion  ----  "); 
              // Message sur la ligne    && !etatActuelConnexionSerial && !clientTelnet && premiereConnexionTelnet && !etatServeurWEB && !flagServeurWEB_Actif
              // etatFTP = 2 pas connecte -- 3 4 5 109 en cours connexion -- 5 connecte -- 77 copie en cours Detection connexion FTP             
              //Serial.print("etatFTP  ");  Serial.println(etatFTP, DEC);                //Serial.print("validMessConnexionFTP  ");  Serial.println(validMessConnexionFTP);
              
             if ( (validMessConnexionFTP == 0)  && ( etatFTP > 2) )                                                // etatFTP = 2 pas connecte -- 3 4 5 109 en cours connexion -- 5 connecte -- 77 copie en cours Detection connexion FTP
                {                  
                    EffaceLigne(3);        
                    //u8g2.drawStr(3, 2+8 * 10,"-   -    -    -    -   -");                                        // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
                    u8g2.drawStr(3+0 , 2+8*3, "Connexion FTP en cours");
                    validMessConnexionFTP = 1; 
                }
             if ( ( validMessConnexionFTP == 1 ) && ( etatFTP == 2 ) )                                                      // Detection deconnexion FTP
                {
                    Serial.print("etatFTP  ");  Serial.println(etatFTP);
                    validMessConnexionFTP = 0;                                                                    // Detect la fin de connexion FTP
                    EffaceLigne(3);
                    comptCoeurLCD_Point = 0;                   
                }
             if ( (flagServeurWEB_Actif == 0) && ( etatServeurWEB == 1 ) )                                                                             // Detection connexion serveur WEB 
                {                                                                                                 // attention declaration variable validMessConnexionWEB dans serveurWEB.h
                  EffaceLigne(4);
                  //u8g2.drawStr(3, 2+8 * 0 ,"-   -    -    -    -   -");                                          // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
                  u8g2.drawStr(3+0 , 2+8*4, "Connexion WEB en cours");
                  etatServeurWEB = 0;
                  flagServeurWEB_Actif = 1;   // Pour effacement
                }

             if ( ( flagServeurWEB_Actif == 1 )&& (millis() - previousMillisWEB >= 5*1000 )  )                            // Utilisation du timeout pour fin de connexion
                {
                  EffaceLigne(4);
                  flagServeurWEB_Actif = 0;  
                }   
   
            if (connexionTelnet == 1 )
                {
                  EffaceLigne(5);
                  //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                        // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
                  u8g2.drawStr(3+0 , 2+8*5, "Connexion Telnet en cours");
                }
		  	   	if (  ( millis() - timeoutDeconnexionTelnet ) >= 30 *1000 )
                {
                  EffaceLigne(5);
                  connexionTelnet = 0;
                }     
            if (Serial)
                {
                  EffaceLigne(6);
                //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                        // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
                  u8g2.drawStr(3+0 , 2+8*6, "Connexion Serial en cours");

                }           
             if (!Serial)
                {
                  EffaceLigne(6);                                                                 // void efface(ligne, decalCaract, nbrCaract);
                }      
             EffaceLigne(7);
            (dns.getHostByName("www.google.com",timeServer) == 1) ? u8g2.drawStr(3+0 , 2+8*7, "Connexion Internet ok :)") : u8g2.drawStr(3+0 , 2+8*7, "Connexion Internet Down ") ;
          }break;


          case 3 : {                   
            //u8g2.drawStr(3, 2+8 * 0 ,"-   -    -    -    -   -");                              // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
            u8g2.drawStr(3, 2+8 * 1 ,"  ----  Info IP  ----   ");
            //Serial.println(F("   - Info IP"));
            char buffer[16];   // "255.255.255.255" + \0
            decalPixel = u8g2.drawStr(3, 2+8 * 3 ," IP   : ");
            IPAddress ip = Ethernet.localIP();
            sprintf(buffer, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
            u8g2.drawStr(3 + decalPixel, 2 + 8 * 3, buffer);

            decalPixel = u8g2.drawStr(3, 2+8 * 4 ," MSR  : ");
            IPAddress subnet =  Ethernet.subnetMask();
            sprintf(buffer, "%u.%u.%u.%u", subnet[0], subnet[1], subnet[2], subnet[3]);
            u8g2.drawStr(3 + decalPixel, 2 + 8 * 4, buffer);

            decalPixel = u8g2.drawStr(3, 2+8 * 5 ," Pass : ");
            IPAddress gateway = Ethernet.gatewayIP();
            sprintf(buffer, "%u.%u.%u.%u", gateway[0], gateway[1], gateway[2], gateway[3]);
            u8g2.drawStr(3 + decalPixel, 2 + 8 * 5, buffer);
            
            //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -"); 
            u8g2.drawStr(3 , 2 + 8 * 6, " DNS google : 1.1.1.1");
            EffaceLigne(7);
            (dns.getHostByName("www.google.com",timeServer) == 1) ? u8g2.drawStr(3+0 , 2+8*7, "Connexion Internet ok :)") : u8g2.drawStr(3+0 , 2+8*7, "Connexion Internet Down ") ;
  
 
          }break;  // Fin case 2      

      } // Fin Switch

      // ICI Page en plus
                      

       u8g2.sendBuffer(); 
       //etatFTP = 2;                                                                                    // Met etatFTP a 2 au cas ou il est en off        
       previousMillisAffichageLCD = millis();
  } // Fin IF 

//  CoeurPointLigneLCD(7);                                                                               // Affiche des points (Coeur) sur la ligne x en boucle (fonction non bloqante)
//------------------------------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------------------------------
} // Fin affichage Principale


/************************************************************************************************************************************************************
* Sous Programme Menu par Scrutation
* Fonction : Gestion Boutons : OK pour valider et Bouton (+) ou (-) pour le scroll
************************************************************************************************************************************************************
* Entrée : Bouton Select Scrutation OK et Scroll Bouton (+)  (-) par scrutation
* Sortie : Return de la valeur du menu selectionne
* 0 si rien
* 1 à xx nombre de la fonction selectionne
************************************************************************************************************************************************************/
unsigned char ScanMenu()
{
  if  ( etatSelectOK == 1)
      {
        Serial.println();                                                         
        Serial.println("***** Le Programme est entrer dans la Fonction Menu Configuration Principal");  
        u8g2.clearBuffer();                                                                                         // Erase all.  Attention fonction interne (bug libraire sur l'ESP !!!!)

        int pageFonction = 0 ;                                                                                      // Nombre de page de l'écran Page Fonction 1 ou 2 --> 0 ou 5
        int positionSurligne = 1 ;                                                                                  // position ligne acctuel (affichage inverse)
        
        u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                                                                    //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                                             // Affichage Général : Rectangle bord a bord  // DrawRectangleAt(x, y, width, height, mode)  
      //u8g2.drawStr(xo, yp       ,"-   -    -    -    -   -");                                                     // Display  ,3 decalage a cause du cadre Y , 3 + 8 * ligne    (3 decalage du cadre X) + 8 (taille d'un caractere    
        u8g2.drawStr(3  , 2+8 * 1 ," --- Menu Selection --- ");
        u8g2.sendBuffer();                                                                                          // if ( validAffichage == 1)  { Serial.print("Menu  comptScroll : ");  Serial.print(comptScroll); Serial.print("  pageFonction : ");  Serial.println(pageFonction); }       
        comptScroll = 1;                                                                                            // Initialisation SORTIE de la fonction selectionner avec le bouton + et -        
        ISR_Etat_BoutonMoins = 0; ISR_Etat_BoutonPlus  = 0;
        etatSelectOK = 0;                                                                                           // Aquittement de etatSelectOK : Lancement de la fonction scan a 0     
        while (etatSelectOK == 0)                                                                                   // sort de la boucle while si on appuye sur le bouton OK
             {
                if ( ISR_Etat_BoutonMoins  == 1)  { comptScroll--;   ISR_Etat_BoutonMoins = 0; }                    // Lecture du bouton OK --> intree dans la fonction Menu
                if ( ISR_Etat_BoutonPlus   == 1)  { comptScroll++;   ISR_Etat_BoutonPlus  = 0; }                    // Lecture des boutons (+) et (-) --> validAffichage = 1 et comptScroll++ ou --

                // Serial.print("* comptScroll : ");  Serial.print(comptScroll,DEC); Serial.print(" --- pageFonction : ");  Serial.println(pageFonction,DEC); 
                
                // Gestion de la premiere et derniniere ligne (fin page 2 remonte debut page 1)
                //  Exemple ici             5                  2 = 11
                if (comptScroll == nbrMaxLigneParPage * nbrDePage + 1 )   comptScroll = 1;                                // Fin de page comptScroll = 6 -->  comptScroll = 1 et comptScroll = 11 -->  comptScroll = 1      en fin de ligne 0 vers 10 et 10 vers 0 du menu --> De max menu a 1 on arrive bas et on remonte (roll)
                if (comptScroll == 0)                                     comptScroll = nbrMaxLigneParPage * nbrDePage;   // comptScroll = 0 -->  comptScroll = derniere page
                //  Exemple ici                                                                 5                2 = 10
                // Calcule de pageFonction et positionSurligne exemple pour nbrDePage = 3  
                // comptScroll      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 
                // pageFonction     0 0 0 0 0 1 1 1 1 1  2  2  2  2  2  1 1 
                // positionSurligne 1 2 3 4 5 1 2 3 4 5  1  2  3  4  5  1 2 
                for ( int i = 0 ; i <= nbrDePage ; i++)                                                                    // nbrDePage = 1 ou 2 ou 3 .... selon la taille de TexAffiche
                    {
                    if ( comptScroll > ( i * nbrMaxLigneParPage ) && comptScroll < ( i * nbrMaxLigneParPage + nbrMaxLigneParPage + 1 ) )     // i=0 comptScroll >0 ou <6 // i=1 comptScroll >5 ou <15 ....
                       {
                           pageFonction = i ;                                                                              // 0 pour comptScroll de 1 a 5 // 1 comptScroll de 6 a 10 // 2 comptScroll de 11 a 15
                           positionSurligne = comptScroll - i * nbrMaxLigneParPage;                                        // 
                       }                    
                    }
                // Serial.print("Apres calcul  comptScroll : ");  Serial.print(comptScroll,DEC); Serial.print("  pageFonction : ");  Serial.print(pageFonction,DEC); Serial.print("  positionSurligne : ");  Serial.println(positionSurligne,DEC);               
                
                // Affichage sur l'Ecran LCD des xx lignes et du surlignage                            
                for ( int i = 1 ; i <= nbrMaxLigneParPage ; i++)
                    {                                                                                                                    // Serial.print("Debut Boucle i : ");  Serial.print(i); Serial.print("  pageFonction : ");  Serial.print(pageFonction); Serial.print("  positionSurligne : ");  Serial.print(positionSurligne);  Serial.print("  comptScroll : ");  Serial.println(comptScroll); //Serial.println();                                           
                       if (positionSurligne == i)     
                          {
                               u8g2.setDrawColor(1);                                                                                     // Caractere Blanc sur fond noir   
                               u8g2.drawRBox( 3 , 3+8*(i + LigneDebutMenu - 1) , 128-6 , 8 , 1 );                                        //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                  
                               u8g2.setDrawColor(0); 
                               u8g2.drawStr ( 3 , 2+8*( i + LigneDebutMenu ) , TextAffich[ i + pageFonction * nbrMaxLigneParPage ]);       // Text du tableau : TextAffich[ i + pageFonction et i+1 commence a la troisieme ligne
                               u8g2.setDrawColor(1); 
                          }
                        else                            
                          {
                               u8g2.setDrawColor(0);                                                                                     // Caractere Blanc sur fond noir   
                               u8g2.drawRBox( 3 , 3+8*(i + LigneDebutMenu - 1) , 128-6 , 8 , 1 );                                        //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                  
                               u8g2.setDrawColor(1); 
                               u8g2.drawStr ( 3 , 2+8*( i + LigneDebutMenu ) , TextAffich[ i + pageFonction * nbrMaxLigneParPage ]);       // Text du tableau : TextAffich[ i + pageFonction et i+1 commence a la troisieme ligne                         
                          } 
                     } // For boucle affichage menu
                  u8g2.sendBuffer();                                                                                         
             
                }   //--> Fin Boucle While           
             etatSelectOK = 0;                                                                                                           // Aquittement de etatSelectOK (bouton OK) 
               
             Serial.print  (" - La valeur selectionne est : "); Serial.println( comptScroll );  
             Serial.println("***** Fin de Gestion du Menu Configuration Principal");   Serial.println();
             //if ( comptScroll == countofTxt(TextAffich) - 2)                                                                             // comptScroll == 10 c'est le Exit  
             //   {
             //     u8g2.clearBuffer();   
             //      return 0; 
             //   }                                                                     
             return comptScroll;                                                                                                         // Sortie Fonction  on envoi le nombre du menu selectionne  
      }
   return 0;                                                                                                                             // aucun menu selectionne sortie direct
}

/***********************************************************************************************************************************************************
* Sous Programme Configuration variable Programme 
* Bouton Pin 2/3 : Scroll Menu
************************************************************************************************************************************************************
* Entrée : Bouton Select par Interruption et Scroll + / - par scrutation
* Sortie : Return de la valeur 
************************************************************************************************************************************************************/
void ConfigureLCD(unsigned char selectFonctionConfigure)
{
  Serial.println(F("***** Start Fonction Configure LCD"));
  u8g2.clearBuffer();                                                                                // Erase all.  Attention fonction interne (bug libraire sur l'ESP !!!!)  
  u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                                                           //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                                             // Affichage Général : Rectangle bord a bord  // DrawRectangleAt(x, y, width, height, mode)  
//u8g2.drawStr(xo, yo       ,"-   -    -    -    -   -");                                            // Display  ,3 decalage a cause du cadre Y , 3 + 8 * ligne    (3 decalage du cadre X) + 8 (taille d'un caractere        
  u8g2.drawStr(3  , 2+8 * 1 ," --- Menu Selection --- ");                                            // Display  ,2 decalage a cause du cadre Y , 2 + 8 * ligne    (2 decalage du cadre X) + 8 (taille d'un caractere  
  u8g2.sendBuffer();     

  Serial.print("comptScroll : ");  Serial.println(comptScroll,DEC);
  unsigned char i = 0;
  boolean state = 0;
  etatSelectOK = 0; 
  switch (selectFonctionConfigure)
      {
         case 1 : {
           Serial.println(F("   - Configure WEB ON/OFF"));
           while (etatSelectOK == 0)
           {
                          //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                    // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display);    
              decalPixel = u8g2.drawStr(3, 2+8*3 ,"    WEB : ");                                    // Display  ,2 decalage a cause du cadre Y , 2 + 8 * ligne    (2 decalage du cadre X) + 8 (taille d'un caractere   
              //etatSelectOK = Detect_SelectOK();                                                    // Lecture du bouton OK --> intree dans la fonction Menu
              state =          ISR_Etat_BoutonPlus;                                                  // Lecture des boutons + et -
              state = state || ISR_Etat_BoutonMoins;           
              ISR_Etat_BoutonPlus = 0; ISR_Etat_BoutonMoins = 0;
              if (state == 1 )      { conf.SrvWEBswitch = !conf.SrvWEBswitch; state = 0; }  
              EffaceCaract(3, decalPixel, 3);                                                       // void efface(uint8_t ligne, uint8_t decalPixel, uint8_t nbrCaract);
              conf.SrvWEBswitch == 0 ?  u8g2.drawStr(3+decalPixel , 2+8 * 3 , "OFF") : u8g2.drawStr(3+decalPixel , 2+8 * 3 , "ON ");      
              u8g2.sendBuffer();
           }
         } break;

         case 2 : {
           Serial.println(F("   - Configure FTP ON/OFF"));
           while (etatSelectOK == 0)
           {
                        //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display);    
              decalPixel = u8g2.drawStr(3, 2+8*3 ,"    FTP : ");                                    // Display  ,2 decalage a cause du cadre Y , 2 + 8 * ligne    (2 decalage du cadre X) + 8 (taille d'un caractere   
              //etatSelectOK = Detect_SelectOK();                                                    // Lecture du bouton OK --> intree dans la fonction Menu
              state =          ISR_Etat_BoutonPlus;                                                  // Lecture des boutons + et -
              state = state || ISR_Etat_BoutonMoins;  
              ISR_Etat_BoutonPlus = 0; ISR_Etat_BoutonMoins = 0;         
              if (state == 1 )      { conf.SrvFTPswitch = !conf.SrvFTPswitch; state = 0; }          
              EffaceCaract(3, decalPixel, 3);                                                       // void efface(uint8_t ligne, uint8_t decalPixel, uint8_t nbrCaract);
              conf.SrvFTPswitch == 0 ?  u8g2.drawStr(3+decalPixel , 2+8 * 3 , "OFF") : u8g2.drawStr(3+decalPixel , 2+8 * 3 , "ON ") ;      
              u8g2.sendBuffer();
           }          
         } break;  

         case 3 : {
           Serial.println(F("   - Configure Datalogger ON/OFF"));
           while (etatSelectOK == 0)
           {
                      //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                        // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display);     
              decalPixel = u8g2.drawStr(3, 2+8*3 ," Datalogger : ");                                // Display  ,2 decalage a cause du cadre Y , 2 + 8 * ligne    (2 decalage du cadre X) + 8 (taille d'un caractere   
              //etatSelectOK = Detect_SelectOK();                                                    // Lecture du bouton OK --> intree dans la fonction Menu
              state =          ISR_Etat_BoutonPlus;                                                  // Lecture des boutons + et -
              state = state || ISR_Etat_BoutonMoins;             
              ISR_Etat_BoutonPlus = 0; ISR_Etat_BoutonMoins = 0;
              if (state == 1 )      { conf.dataloggerSwitch = !conf.dataloggerSwitch; state = 0; }   
              EffaceCaract(3, decalPixel, 3);                                                       // void efface(uint8_t ligne, uint8_t decalPixel, uint8_t nbrCaract);         
              conf.dataloggerSwitch == 0 ?  u8g2.drawStr(3+decalPixel , 2+8 * 3 , "OFF") : u8g2.drawStr(3+decalPixel , 2+8 * 3 , "ON ") ;       
              u8g2.sendBuffer();
            }
         } break;  

         case 4 : {
           Serial.println(F("   - Login WEB : "));
           while (etatSelectOK == 0)
           {     
                        //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display);     
              decalPixel = u8g2.drawStr(3, 2+8*3 ,"    LoginWEB : ");                               // Display  ,2 decalage a cause du cadre Y , 2 + 8 * ligne    (2 decalage du cadre X) + 8 (taille d'un caractere   
              //etatSelectOK = Detect_SelectOK();                                                    // Lecture du bouton OK --> intree dans la fonction Menu
              state =          ISR_Etat_BoutonPlus;                                                  // Lecture des boutons + et -
              state = state || ISR_Etat_BoutonMoins;            
              ISR_Etat_BoutonPlus = 0; ISR_Etat_BoutonMoins = 0;             
              if (state == 1 )      { conf.loginWEB = !conf.loginWEB; state = 0; }    
              EffaceCaract(3, decalPixel, 3);                                                       // void efface(uint8_t ligne, uint8_t decalPixel, uint8_t nbrCaract);
              conf.loginWEB == 0 ?  u8g2.drawStr(3+decalPixel , 2+8 * 3 , "OFF") : u8g2.drawStr(3+decalPixel , 2+8 * 3 , "ON ") ;           
              u8g2.sendBuffer();                                                                     // reinitialise Watchdog   https://techtutorialsx.com/2017/01/21/esp8266-watchdog-functions/
           }
         } break;

         case 5 : {           
              Serial.println(F("   - Login telnet"));
            while (etatSelectOK == 0)
            {     
                        //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display);     
              decalPixel = u8g2.drawStr(3, 2+8*3 ,"    LoginTelnet : ");                            // Display  ,2 decalage a cause du cadre Y , 2 + 8 * ligne    (2 decalage du cadre X) + 8 (taille d'un caractere   
              //etatSelectOK = Detect_SelectOK();                                                    // Lecture du bouton OK --> intree dans la fonction Menu
              state =          ISR_Etat_BoutonPlus;                                                  // Lecture des boutons + et -
              state = state || ISR_Etat_BoutonMoins;            
              ISR_Etat_BoutonPlus = 0; ISR_Etat_BoutonMoins = 0;             
              if (state == 1 )      { conf.login_cmdTelnetSwitch = !conf.login_cmdTelnetSwitch; state = 0; }    
              EffaceCaract(3, decalPixel, 3);                                                       // void efface(uint8_t ligne, uint8_t decalPixel, uint8_t nbrCaract);
              conf.login_cmdTelnetSwitch == 0 ?  u8g2.drawStr(3+decalPixel , 2+8 * 3 , "OFF") : u8g2.drawStr(3+decalPixel , 2+8 * 3 , "ON ") ;           
              u8g2.sendBuffer();                
            } 
            Serial.println("Fin Login Telnet");                  
         } break;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

         case 6 : {
           Serial.println(F("   - Configure IP"));
           u8g2.clearBuffer(); 
           u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                                                     //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                                     
           //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
           u8g2.drawStr(3  , 2+8 * 1 ," --- Menu Selection --- ");
           u8g2.sendBuffer();  

           while (i != 4)
           {
              if ( ISR_Etat_BoutonMoins  == 1)  conf.ip[i]--; 
              if ( ISR_Etat_BoutonPlus   == 1)  conf.ip[i]++;                                                                               
              ISR_Etat_BoutonMoins = 0; ISR_Etat_BoutonPlus = 0;
              i = etatSelectOK + i;                                                                     // Lecture du bouton OK --> intree dans la fonction Menu
              etatSelectOK = 0;
              DrawIP(2, 2 + 8*3, " IP : ", conf.ip, i);                                                 // DrawIP(xo, yo, " IP ", testIP, selectedOctet);
           }
           //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
           u8g2.drawStr(3  , 2+8 * 5 ," Reset.......");
           u8g2.sendBuffer(); 
           EEPROM.put(adressBase, conf);
           NVIC_SystemReset();
         } break;  

         case 7 : {
           Serial.println(F("   - Configure Netmask MsR"));
           u8g2.clearBuffer(); 
           u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                                                     //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                                     
           //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
           u8g2.drawStr(3  , 2+8 * 1 ," --- Menu Selection --- ");
           u8g2.sendBuffer();  
 
           while (i != 4)
           {
              DrawIP(2, 2 + 8*3, " MSR : ", conf.subnet, i);                                            // DrawIP(xo, yo, " IP ", testIP, selectedOctet);

              if ( ISR_Etat_BoutonMoins  == 1)  conf.subnet[i]--; 
              if ( ISR_Etat_BoutonPlus   == 1)  conf.subnet[i]++;                                                                               
              ISR_Etat_BoutonMoins = 0; ISR_Etat_BoutonPlus = 0;                       
              i = etatSelectOK + i;                                                                     // Lecture du bouton OK --> intree dans la fonction Menu
              etatSelectOK = 0;
              DrawIP(2, 2 + 8*3, " MSR : ", conf.subnet, i);                                            // DrawIP(xo, yo, " IP ", testIP, selectedOctet);          
           }    
         //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
           u8g2.drawStr(3  , 2+8 * 5 ," Reset.......");
           u8g2.sendBuffer(); 
           EEPROM.put(adressBase, conf);
           NVIC_SystemReset();       
         } break;  

         case 8 : {
           Serial.println(F("   - Configure Gateway"));
           u8g2.clearBuffer(); 
           u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                                                     //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                                     
           //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
           u8g2.drawStr(3  , 2+8 * 1 ," --- Menu Selection --- ");
           u8g2.sendBuffer(); 

           while (i != 4)
           {
              DrawIP(2, 2 + 8*3, " Pass : ", conf.gateway, i);                                          // DrawIP(xo, yo, " IP ", testIP, selectedOctet);
              if ( ISR_Etat_BoutonMoins  == 1)  conf.gateway[i]--; 
              if ( ISR_Etat_BoutonPlus   == 1)  conf.gateway[i]++;                                                                               
              ISR_Etat_BoutonMoins = 0; ISR_Etat_BoutonPlus = 0;                        
              i = etatSelectOK + i;                                                                     // Lecture du bouton OK --> intree dans la fonction Menu
              etatSelectOK = 0;
              DrawIP(2, 2 + 8*3, " Pass : ", conf.gateway, i);                                           // DrawIP(xo, yo, " IP ", testIP, selectedOctet);
           }
         //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                      // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
           u8g2.drawStr(3  , 2+8 * 5 ," Reset.......");
           u8g2.sendBuffer(); 
           EEPROM.put(adressBase, conf);
           NVIC_SystemReset();              
         } break;  

         case 9 : {
          Serial.println(F("   - Ping"));
           uint8_t ip_ping[4];
           //IPAddress ip_ping;
           ip_ping[0] = conf.gateway[0];   ip_ping[1] = conf.gateway[1];   ip_ping[2] = conf.gateway[2];   ip_ping[3] = conf.gateway[3];   
           while (i != 4)
            {
              if ( ISR_Etat_BoutonMoins  == 1)  ip_ping[i]--; 
              if ( ISR_Etat_BoutonPlus   == 1)  ip_ping[i]++;                                                                               
              ISR_Etat_BoutonMoins = 0; ISR_Etat_BoutonPlus = 0;                             
              i = etatSelectOK + i;                                                                     // Lecture du bouton OK --> intree dans la fonction Menu
              etatSelectOK = 0;
              DrawIP(3, 2 + 8*3, " Ping : ", ip_ping, i);                                               // DrawIP(xo, yo, " IP ", testIP, selectedOctet);
            }             

           decalPixel = u8g2.drawStr(2  , 2+8 * 6 ," Ping IP : ");                                        // Display  ,2 decalage a cause du cadre Y , 2 + 8 * ligne    (2 decalage du cadre X) + 8 (taille d'un caractere  
           u8g2.drawStr(3+decalPixel , 2+8 * 6 ," ... Wait");
           u8g2.sendBuffer();
           EthernetICMPEchoReply echoReply = ping(ip_ping,1);
           delay(2000);  
           EffaceCaract(6, decalPixel, 9 );                                                            // EffaceCaract (ligne (1a7), decalPixel (a partir de gauche), nbrCaract a effacer);
           u8g2.sendBuffer();

           if(echoReply.status==SUCCESS) {
              Serial.println("Ping OK");
              u8g2.drawStr(3+decalPixel , 2+8 * 6 ," OK !!"); 
            }
           else {
             Serial.println("Ping FAIL");
             u8g2.drawStr(3+decalPixel , 2+8 * 6 ," Fail :("); 
           }
           u8g2.sendBuffer();
           etatSelectOK = 0;
           while (etatSelectOK == 0)             
                {
                   //etatSelectOK = Detect_SelectOK();                                              // Lecture du bouton OK --> intree dans la fonction Menu
                }            
          Serial.println("Fin Ping");                   
          } break;  

          case 10 : {
          // Exit
          Serial.println("Exit");
          } break;       
    } // Fin Switch
  state = 0;
  etatSelectOK = 0; 
  comptScroll = 1;
  last_comptScroll = 1;
  EEPROM.put(adressBase, conf);

  // Mise a jours affichage LCD : Affichage principale
  u8g2.clearBuffer(); 
  //u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                                                       //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                           
          
  //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");                                          // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
  //u8g2.drawStr(3, 2+8 * 1 ,"  ----  Prise IP  ----  "); 
  Serial.println(F("***** Fin Fonction Configure LCD"));
  Serial.print("> ");
} // Fin ConfigureLCD (configuration Menu deroulant)
/***********************************************************************************************************************************************************
* Sous Programme scan Bouton  OK par Bouton (Interruption)
* Fonction : Gestion Bouton Select
************************************************************************************************************************************************************
* Entrée : Bouton Select par Interruption
* Sortie : Bouton OK variable etatSelectOK = 1
************************************************************************************************************************************************************/
void ISR_Detect_SelectOK()                                                     // Fonction qui se déclanche l'orsqu'on appui sur le bouton Bx
{ 
  volatile unsigned long tempsActuel = millis();
  if ( ( tempsActuel - dernierTemps ) > delaiDebounce)                              // filtre le rebond
      {  
           etatSelectOK = 1;
           //Serial.print("Bouton etatSelectOK = 1: ");  Serial.println(etatSelectOK);
           dernierTemps = tempsActuel;
      }
}
/***********************************************************************************************************************************************************
* Sous Programme scan Bouton (+) rt (-)  par Bouton(Interruption)
* Fonction : Gestion Bouton Select
************************************************************************************************************************************************************
* Entrée : Bouton Select par Interruption
* Sortie : Bouton (+) rt (-) --> compteur mono coup : comptScroll++ ou -- 
* et validAffichage = 1 
************************************************************************************************************************************************************/
void ISR_BoutonScanScrollPlus()                                                // Attention bouton rappel a l etat haut
{ 
  volatile unsigned long tempsActuel = millis();
  if ( ( tempsActuel - dernierTemps ) > delaiDebounce)                         // filtre le rebond
      {  
           //comptScroll++;
           ISR_Etat_BoutonPlus = 1;
           //Serial.print("Bouton ++ : "); Serial.println(comptScroll+1,DEC);
           dernierTemps = tempsActuel;
      }
}

void ISR_BoutonScanScrollMoins()                                               // Attention bouton rappel a l etat haut
{
  volatile unsigned long tempsActuel = millis();
  if ( ( tempsActuel - dernierTemps ) > delaiDebounce)                         // filtre le rebond
      {  
           //comptScroll--;
           ISR_Etat_BoutonMoins = 1;
           //Serial.print("Bouton -- : "); Serial.println(comptScroll-1,DEC);          
           dernierTemps = tempsActuel;
      }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/***********************************************************************************************************************************************************
* Sous Programme Affiche des Points sur la ligne (entree) : Fonction non bloquante 
************************************************************************************************************************************************************
* Entrée : ligne
* Sortie : points sur le LCD
************************************************************************************************************************************************************/
void CoeurPointLigneLCD(unsigned char ligne)
{
  if ( millis() - previousMillisCoeurLCD >= 250 ) 
  {       
      u8g2.drawStr(3+6*comptCoeurLCD , 2+8*ligne, ".");
      comptCoeurLCD++;
      if (comptCoeurLCD >= 20 ) 
         {
                  //u8g2.drawStr(3, 2+8 * 1 ,"-   -    -    -    -   -");        // Affichage 24 caracteres x 1-7 Ligne avec cadre  u8g2.drawStr( xo : decalage 3 , yo : 3 + 8 * ligne (3 decalage du cadre X) + 8 (taille d'un caractere)  , text display); 
             u8g2.drawStr(3+6*0 , 2+8*ligne, "                        ");        // Efface la ligne    
             comptCoeurLCD = 1;                 
         }
      previousMillisCoeurLCD = millis();
      u8g2.sendBuffer();
  }
}                 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************************************************************************************
* Fonction Efface une zone correspondant à un nombre de caractères sur une ligne donnée
************************************************************************************************************************************************************
* Entrée : ligne , decalage , nbr caractere a effacer
* Sortie : vide sur le LCD
************************************************************************************************************************************************************/
void EffaceLigne(uint8_t ligne)
{
    // Vérifie que la ligne est valide : 1 à 7
    if (ligne < 1 || ligne > 7) return;

    const uint8_t decalX = 3;     // décalage horizontal à gauche
    const uint8_t largeurEcran = 128;
    const uint8_t hauteurCar = 8; // hauteur d'un caractère pour profont10

    // Calcul Y : première ligne utile = 2 pixels de décalage du haut + 8*ligne
    uint8_t y = 2 + 8 * ligne - hauteurCar;

    // Dessine rectangle noir pour effacer la ligne
    u8g2.setDrawColor(0);  // 0 = efface
    u8g2.drawBox(decalX, y, largeurEcran - 1 - decalX, hauteurCar);        // largeur - marge gauche/droite  //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour 
    u8g2.setDrawColor(1);  // texte normal
}


/***********************************************************************************************************************************************************
* Sous Efface une zone correspondant à un nombre de caractères sur une ligne donnée
************************************************************************************************************************************************************
* Entrée : ligne , decalage , nbr caractere a effacer
* Sortie : vide sur le LCD
*************************************************************************************************************************************************************/
/*
void EffaceCaract(uint8_t ligne, uint8_t decalPixel, uint8_t nbrCaract)
{
  const uint8_t largeurCar = 6; // largeur d'un caractère pour profont10
  const uint8_t hauteurCar = 8; // hauteur d'un caractère

  //uint8_t nbrCaract = strlen(texte);  // calcule automatiquement le nombre de caractères

  // Dessin fond
  u8g2.setDrawColor(0);  // 0 = effacer
  u8g2.drawBox(3 + decalPixel, 2 + 8*ligne - hauteurCar, nbrCaract * largeurCar, hauteurCar);
  u8g2.setDrawColor(1);  // texte normal
}
 */
void EffaceCaract(uint8_t ligne, uint8_t decalPixel, uint8_t nbrCaract)                                      // EffaceCaract (ligne (1a7), decalPixel (a partir de gauche), nbrCaract a effacer);
{
    // Vérifie que la ligne est valide : 1 à 7
    if (ligne < 1 || ligne > 7) return;

    const uint8_t decalX = 3;       // décalage gauche
    const uint8_t largeurCar = 6;   // largeur caractère profont10
    const uint8_t hauteurCar = 8;   // hauteur caractère

    // Calcul position Y
    uint8_t y = 2 + 8*ligne - hauteurCar;

    // Dessine un rectangle noir pour effacer les caractères
    u8g2.setDrawColor(0);  // 0 = effacer
    u8g2.drawBox(decalX + decalPixel, y, nbrCaract * largeurCar, hauteurCar);

    // Remet couleur texte normale
    u8g2.setDrawColor(1);
}

/***********************************************************************************************************************************************************
* Fonction ---- fonction DrawIP ----- Affichage de l'IP aprer un text 192.168.0.1 avec surlignage de la partie active
* DrawIP(2, 2+8 * 3, " IP : ", conf.ip, i);
* xo yo position
* Text : est affiche avant (  - IP :..........)
* IP adresse
* i : position 1   . 2   .3    . 4  
*              192 . 168 . 100 . 1
************************************************************************************************************************************************************
* Entrée : DrawIP(xo, yo, " IP ", testIP, selectedOctet);
* Sortie : Affichage LCD de l'IP avec surlignage de la partie active
************************************************************************************************************************************************************/
// ----- fonction DrawIP -----
void DrawIP(uint8_t xo, uint8_t yo, const char* text, uint8_t IP[4], uint8_t selected)
{
    u8g2.clearBuffer();
    u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                                                           //  u8g2.drawBox( x0 , yo , w , h , 2 );  - box fil contour arrondi                                                             // Affichage Général : Rectangle bord a bord  // DrawRectangleAt(x, y, width, height, mode)  
  //u8g2.drawStr(xo, yo       ,"-   -    -    -    -   -");                                            // Display  ,3 decalage a cause du cadre Y , 3 + 8 * ligne    (3 decalage du cadre X) + 8 (taille d'un caractere        
    u8g2.drawStr(3  , 2+8 * 1 ," - Configuration d'IP - ");                                            // Display  ,2 decalage a cause du cadre Y , 2 + 8 * ligne    (2 decalage du cadre X) + 8 (taille d'un caractere    
 
    u8g2.drawStr(xo, yo, text);

    uint8_t x = xo + u8g2.getStrWidth(text) + 6;
    //uint8_t charHeight = u8g2.getMaxCharHeight(); // marchais puis bug v63 ok ???????????????????????????,
    uint8_t charHeight = 8;

    
    for (uint8_t i = 0; i < 4; i++)
    {
        char buffer[4];
        itoa(IP[i], buffer, 10);

        uint8_t w = u8g2.getStrWidth(buffer);

        if (i == selected)
        {
            // Fond blanc
            u8g2.setDrawColor(1);
            u8g2.drawBox(x - 1, yo - charHeight + 1, w + 2, charHeight);

            // Texte noir
            u8g2.setDrawColor(0);
            u8g2.drawStr(x, yo, buffer);

            u8g2.setDrawColor(1);
        }
        else
        {
            // Fond noir
            u8g2.setDrawColor(0);
            u8g2.drawBox(x - 1, yo - charHeight + 1, w + 2, charHeight);
            u8g2.setDrawColor(1);
            // text blanc
            u8g2.drawStr(x, yo, buffer);
        }

        x += w;

        if (i < 3)
        {
            u8g2.drawStr(x, yo, ".");
            x += u8g2.getStrWidth(".");
        }
    }
    u8g2.sendBuffer();
}

/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Mini Documentation LCD --- TFT I2C GM12864-59N VER 2.0 (ST7567S) Lib U8g2-2.35.30
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
**************************************************************************
* Mini DOC : Librairie : U8g2lib.h
* ST7567_ENH_DG128064I - Driver pour contrôleur ST7567S   ---- Module type DG128064I (128x64)
*   0,0                 127,0
*    +------------------+   ---> x
*    |                  |
*    |                  |
*    +------------------+
*   0,63                127,63
*    |
*   y
**************************************************************************
ST7567   - contrôleur
JLX12864 - mapping mémoire standard le plus courant
_F_      - Full buffer (1 Ko RAM)
HW_I2C   - I2C matériel (UNO R4 compatible)

U8G2_R0 → rotation 0°  
  u8g2.clearBuffer();                                         // Efface ecran
  u8g2.setFontDirection(0); 
  u8g2.setContrast(200);                                      // contrasr de 0 a 255
  u8g2.sendBuffer();                                          // Affiche sur le LCD 

      
  u8g2.setCursor(15,23);                                      // u8g2.setCursor(x,y);
  u8g2.enableUTF8Print();                                     // enable UTF8 support for the Arduino print() function
  u8g2.print( );                                              // u8g2.print(x);  valeur numerique rement le curceur en 0
  u8x8log.print("millis=");
  u8x8log.print(millis());
  u8x8log.print("\n");

  u8g2.setFont(u8g2_font_profont10_tf);                       // 7 linge de 24 caractere Max avec cadre largeur 5 x hauteur 8        
  u8g2.setFont(u8g2_font_lucasfont_alternate_tf);             //  --- hauteur 8pix - ligne 20 caracters ok
  u8g2.setFontDirection(0);   
  u8g2.drawStr(0 +2, 8 *1+2,"Hello World ok");
  u8g2.drawStr(0 +2, 8 *2+2,"0123456789");
  u8g2.drawStr(0 +2, 8 *3+2,"abcdefghijklm");  
  u8g2.drawStr(0 +2, 8 *4+2,"nopqrstuvwxyz");
  u8g2.drawStr(0 +2, 8 *5+2,"ABCDEFGHIJKLM"); 
  u8g2.drawStr(0 +2, 8 *6+2,"NOPQRSTUVWXYZ");
  u8g2.drawStr(0 +2, 8 *7+2,"012345678901234678901");   
  u8g2.sendBuffer();                                          // Affiche sur le LCD 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  u8g2.drawPixel( 0 , 0 );                                    // u8g2.drawPixel( x , y ); - plot
  u8g2.drawLine( 0 , 0 , 0 , 0 );                             // u8g2.drawLine( x1 , y1 , x2 , y2 ); - trace ligne

  u8g2.drawHLine(0, 0, 0);                                    // u8g2.drawHLine(x0, y0, longueur);
  u8g2.drawVLine(0, 0, 0);                                    // u8g2.drawVLine(x0, y0, longueur);


  u8g2.drawFrame( 0 , 0 , 128 , 64 );                         // u8g2.drawFrame( x0 , yo , w , h );       - box carre fil contour
  u8g2.drawRFrame( 0 , 0 , 128 , 64 , 4 );                    // u8g2.drawRFrame( x0 , yo , w , h , 4 );  - box carre fil contour arrondi

  u8g2.drawBox( 0 , 0 , 127 , 64 );                           // u8g2.drawBox( x0 , yo , w , h );     - box pleine
  u8g2.drawRBox( 10 , 10 , 50 , 120 , 2 );                    // u8g2.drawBox( x0 , yo , w , h , r);  - box pleine arrondi
                                                                   // box entour une ligne avec caractere inverse et cadre autour de l ecran : 
                                                                   // drawRBox( 3 , 3+8* (LigneDebutMenu - 1) , 128-6 , 8 , 1 );   // le -1 cest car son xo yo est en haut de la ligne 

  u8g2.drawCircle( 10 , 10 , 50 , 120);                       // u8g2.DrawCircle( x0, y0, rad, opt);  - cercle fil
  u8g2.DrawDisc(x0, y0, rad, opt);                            // u8g2.DrawDisc(x0, y0, rad, opt);     - disque plein
  
  u8g2.DrawTriangle(&u8g2, x0, y0, x1, y1, x2, y2);           // u8g2_DrawTriangle(&u8g2, x0, y0, x1, y1, x2, y2);  - triangle plein


//---------------------------------------
// Initialisation Librairie u8g2-master (U8g2-2.35.30)
#include <U8g2lib.h>
#include <Wire.h>

U8G2_ST7567_ENH_DG128064I_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);            // Mode _F_ → Full Frame Buffer -- 128 × 64 / 8 = 1024 octets  -- _SW_I2C : Software I²C (bit-banging)
//U8G2_ST7567_ENH_DG128064I_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);                    // plus performant I2C materiel

void setup(void) 
{
   u8g2.setI2CAddress(0x3F * 2);
// u8g2.setBusClock(400000);
   u8g2.setBusClock(200000);
   u8g2.begin();
// Wire.setWireTimeout(3000, true);
   u8g2.clearBuffer();
  
   u8g2.enableUTF8Print();                                       // enable UTF8 support for the Arduino print() function
// u8g2.setFont(u8g2_font_timR08_tf);                            // choose a suitable font  --- ASCII
// u8g2.setFont(u8g2_font_profont10_tf);                         // 7 linge de 24 caractere Max avec cadre 
// u8g2.setFont(u8g2_font_lucasfont_alternate_tf);               //  --- hauteur 8pix - ligne 20 caracters ok
// u8g2.setFont(u8g2_font_6x10_tr);

   u8g2.setFontDirection(0);
   u8g2.setContrast(200);
   u8g2.setDisplayRotation(U8G2_R2);
   u8g2.setFlipMode(1);

}

  u8g2.setFont(u8g2_font_unifont_t_latin);                   // choose a suitable font  --  
//  u8g2.setFont(u8g2_font_pxplusibmcgathin_8f);                   // choose a suitable font  --- 8pix ok Max 16
  u8g2.setFont(u8g2_font_8x13_tf);                   // choose a suitable font  --
  u8g2.setFont(u8g2_font_helvB08_tf);                   // choose a suitable font  --
  u8g2.setFont(u8g2_font_unifont_t_latin);                   // choose a suitable font  --
  u8g2.setFont(u8g2_font_courB12_tf);                   // choose a suitable font  --
  u8g2.setFont(u8g2_font_ncenB08_tr);                   // choose a suitable font  --  



  
//  u8g2.setFont(u8g2_font_lucasfont_alternate_tf);                //  --- hauteur 8pix - ligne 20 caracters
//  u8g2.setFont(u8g2_font_courR08_tf);                            //  --- hauteur 8pix - ligne 20 caracters
//  u8g2.setFont(u8g2_font_timR08_tf);                             //  --- hauteur 8pix - ligne 25 caracters
//  u8g2.setFont(u8g2_font_chikita_tf);                            //  --- hauteur 6pix - ligne 23 caracters
//  u8g2.setFont(u8g2_font_pxplusibmcgathin_8f);                   // choose a suitable font  --- 8pix ok Max 16
//  u8g2.setFont(u8g2_font_helvR08_tf);                            // choose a suitable font  --- 9pix ok Max 20 caractere de long
//  u8g2.setFont(u8g2_font_ncenB08_tr);                            // choose a suitable font  
//  u8g2.setFont(u8g2_font_Terminal_tr);                           // choose a suitable font  
//  u8g2.setFont(u8g2_font_blipfest_07_tr);                        // choose a suitable font  
//  u8g2.setFont(u8g2_font_spleen5x8_mf);                          // choose a suitable font  
//  u8g2.setFont(u8g2_font_artossans8_8r);                         // choose a suitable font    
//  u8g2.setFont(u8g2_font_courB08_tr);                            // choose a suitable font  
//  u8g2.setFont(u8g2_font_helvB08_tr);                            // choose a suitable font  
//  u8g2.setFont(u8g2_font_ncenB08_tf);                            // choose a suitable font  --- gras
//  u8g2.setFont(u8g2_font_ncenB08_tr);                            // choose a suitable font  --- 
//  u8g2.setFont(u8g2_font_helvR08_tf);                            // choose a suitable font  --- 9pix 
//  u8g2.setFont(u8g2_font_pressstart2p_8f);                       // choose a suitable font  --- 8pix gras
//  u8g2.setFont(u8g2_font_pcsenior_8f);                           // choose a suitable font  --- 8pix
//  u8g2.setFont(u8g2_font_ncenB10_tr);                            // choose a suitable font  
//  u8g2.setFont(u8g2_font_ncenB12_tr);                            // choose a suitable font  
//  u8g2.setFont(u8g2_font_ncenB14_tr);  
//  u8g2.setFont(u8g2_font_tom_thumb_4x6_mf);  
//  u8g2.setFont(u8g2_font_inb24_mf); 

//  u8g2.drawBox( 10 , 10 , 15 , 20 );                           //  u8g2.drawBox( x0 , yo , w , h );  - box pleine
//  u8g2.drawRBox( 10 , 10 , 50 , 120 , 2 );                     //  u8g2.drawBox( x0 , yo , w , h , r);  - box pleine arrondi
//  u8g2.drawFrame( 0 , 0 , 128 , 64 );                          //  u8g2.drawBox( x0 , yo , w , h );  - box fil contour







1. Initialisation :

#include <U8g2lib.h>
#include <Wire.h>

// Mode Full Frame Buffer (F) + Software I2C (bit-banging)
U8G2_ST7567_ENH_DG128064I_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);

void setup() {
    u8g2.setI2CAddress(0x3F * 2);       // Adresse I2C
    u8g2.setBusClock(200000);           // Vitesse bus I2C (200 kHz)
    u8g2.begin();                       // Initialise l'écran
    u8g2.clearBuffer();                 // Efface le buffer
    u8g2.enableUTF8Print();             // Support UTF-8 pour print()
    u8g2.setFontDirection(0);           // Orientation du texte : 0 = normal
    u8g2.setContrast(200);              // Contraste (0 à 255)
    u8g2.setDisplayRotation(U8G2_R0);   // Rotation écran (U8G2_R0, R1, R2, R3)
    u8g2.setFlipMode(0);                // 0=normal, 1=inversé verticalement
}

2. Gestion du buffer :

// Toutes les opérations sont faites dans un buffer avant affichage réel
u8g2.clearBuffer();    // Efface le buffer
u8g2.sendBuffer();     // Envoie le buffer à l'écran

3. Texte :

// Déplacement du curseur
u8g2.setCursor(x, y);    // Position en pixels

// Affichage texte/valeur numérique
u8g2.print("Texte");
u8g2.print(123);

// Sélection de la police
u8g2.setFont(u8g2_font_profont10_tf);        // ASCII, hauteur 8px
u8g2.setFont(u8g2_font_lucasfont_alternate_tf); 
u8g2.setFont(u8g2_font_unifont_t_latin);     // Unicode latin
u8g2.setFont(u8g2_font_8x13_tf);             
u8g2.setFont(u8g2_font_courB12_tf);          

// Exemples multi-lignes
u8g2.setFont(u8g2_font_profont10_tf);
u8g2.drawStr(2, 8*1, "Hello World");
u8g2.drawStr(2, 8*2, "0123456789");
u8g2.drawStr(2, 8*3, "ABCDEFG");
u8g2.sendBuffer();

4. Formes graphiques :

// Pixel et lignes
u8g2.drawPixel(x, y);                  // Pixel unique
u8g2.drawLine(x1, y1, x2, y2);        // Ligne
u8g2.drawHLine(x0, y0, longueur);     // Ligne horizontale
u8g2.drawVLine(x0, y0, longueur);     // Ligne verticale

// Rectangles
u8g2.drawFrame(x, y, w, h);           // Contour rectangle
u8g2.drawRFrame(x, y, w, h, r);       // Contour rectangle arrondi
u8g2.drawBox(x, y, w, h);             // Rectangle plein
u8g2.drawRBox(x, y, w, h, r);         // Rectangle plein arrondi

// Cercles et disques
u8g2.drawCircle(x, y, radius, option); // Cercle vide
u8g2.drawDisc(x, y, radius, option);   // Cercle plein

// Triangles
u8g2.drawTriangle(x0, y0, x1, y1, x2, y2); // Triangle plein

// Exemples graphiques
u8g2.drawBox(0, 0, 128, 64);      // Écran plein noir
u8g2.drawFrame(10, 10, 50, 30);   // Rectangle contour
u8g2.drawCircle(64, 32, 20, 0);   // Cercle
u8g2.sendBuffer();

5. Fonctions utiles :

u8g2.setFontDirection(dir);    // 0 = normal, 1 = 90° rotation, 2 = 180°, 3 = 270°
u8g2.setContrast(val);         // Contraste écran 0–255
u8g2.setDisplayRotation(r);    // Rotation écran (U8G2_R0..R3)
u8g2.setFlipMode(0/1);         // Flip vertical de l’écran
u8g2.enableUTF8Print();        // UTF8 support pour print()
u8g2.drawXBM(x, y, w, h, data);      // Affiche image bitmap XBM
u8g2.drawBitmap(x, y, w, h, data);   // Affiche image monochrome 1bit

6. Conseils pratiques :

- Toujours modifier le buffer puis faire sendBuffer() pour afficher.
- Ajuster les polices selon nombre de caractères et hauteur de ligne.
- Préférer HW_I2C pour affichage rapide si possible.
- Coordonnées (x, y) en pixels, pas en colonnes/lignes.
- Les rectangles et cercles supportent options remplissage et contour.

**************************************************************************
*/
