/*
  Ping Example
 
 This example sends an ICMP pings every 500 milliseconds, sends the human-readable
 result over the serial port. 

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 
 created 30 Sep 2010
 by Blake Foster
 
 */

//#define dureeWatchdog  (5UL * 60UL * 1000UL)                                                       // 5 minutes en millisecondes
//#include <TickTwo.h>                                                                               // Librairie Interruption : Pour cree un Watchdog
//void ISRwatchdog();
//TickTwo WatchDog(ISRwatchdog, dureeWatchdog, 0);


#include <EEPROM.h>                                                                 // Libairie LOCAL de l'IDE d'Arduino :Librairie eemprom 
#include <SPI.h>                                                                    // Libairie LOCAL de l'IDE d'Arduino      
#include <Ethernet.h>


#include <SdFat.h>
#define SD_CS   4
#define ETH_CS 10
SdFat sd;                                                                           // SdFs sd;
FsFile root;
boolean microSD = 0;     




#include <utility/w5100.h>
#include <EthernetICMP.h>



SOCKET pingSocket = 0;

char buffer [256];
EthernetICMPPing ping(pingSocket, (uint16_t)random(0, 255));

// DNS
#include <Dns.h>
IPAddress timeServer;                                                               //https://services.renater.fr/ntp/serveurs_francais

// Time NTP 
#include <NTPClient.h>
//#include <EthernetUdp.h>
EthernetUDP ntpUDP;
NTPClient timeClient(ntpUDP);
char date[10] = {0};

#include <FtpServer.h>
FtpServer ftpSrv;                                                                     //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial
char etatFTP = 2;                                                                     // Met etatFTP a 2 au cas ou il est en off  ::  etatFTP = 2 pas connecte -- 3 4 5 109 en cours connexion -- 5 connecte -- 77 copie en cours

// Fichier CSV
String fileTxt; 
EthernetServer serverFTP(21);

EthernetServer server(80);

// Initialisation de la Librairie Client Telnet 
EthernetServer serverTelnet(23);                                                      // EthernetServer serverTelnet = EthernetServer(23);
EthernetClient clientTelnet;
boolean premiereConnexionTelnet = 1;                                                  // variable de demarrage (pour nexecuter qu'une foi l intro
unsigned long timeoutDeconnexionTelnet = 0; // 


// Librairie Ecran LCD
#include <U8g2lib.h>
#include <Wire.h>
U8G2_ST7567_ENH_DG128064I_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);    

// Libraire Commande Line CmdLine
#include <CmdLineTelnet_UNOR4.h> 
CmdLine cmdLine(Serial);
CmdLine cmdLineTelnet(clientTelnet);
#define countof(commands) (sizeof(commands)/sizeof(commands[0]))


byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // max address for ethernet shield
byte ip[] = {192,168,0,177}; // ip address for ethernet shield
IPAddress pingAddr(192,168,0,253); // ip address to ping



// Print RAM Free
#include <MemoryFree.h>
#include <pgmStrToRAM.h>

#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
         
         
// Declaration Fonction
boolean Detect_SelectOK();
boolean BoutonScanScrollPlus();
boolean BoutonScanScrollMoins();
int ScanMenu();

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



IPAddress myDNS(1,1,1,1);                               // coudFare
//const byte DNS1[] = { 4, 4, 4, 4 };                   // DNS  //const byte DNS1[] = { 212, 27, 40, 240 }; // DNS Free  //const byte DNS0[] = { 89, 2, 0, 1 };                  // DNS

// Variable Structure EEPROM
#define VALID        100000062                          // Pour valider les Info dans l'EEPROM 

typedef struct {                                        // https://www.squalenet.net/fr/ti/tutorial_c/14-structures-unions.php5
  uint32_t validity;                                    // ID Cette variable permet de verifier que l'EEPROM a deja ete programme par ce programme Valeur de test pour savoir si des donnes sont valid en EEPROM (de type Adresse IP)
  char nameSystem[40];                                  // Nom du system
  boolean SrvWEBswitch;                                 // Switch Serveur WEB
  boolean SrvFTPswitch;                                 // Switch Serveur FTP
     
  boolean led;                                          // Etat de la LED 

  uint8_t mac[6];                                       // local MAC address
  boolean dhcp;                                         // Arduino configure en IP STATC = 0 // Arduino configure en IP DHCP = 1 
  uint8_t ip[4];                                        // local IP address
  uint8_t subnet[4];  
  uint8_t gateway[4];
  uint16_t port;                                        // Port serveur WEB

  boolean loginWEB;                                     // ON / OFF : Login et Password du site WEB
  char loginPasswordWEB[40];                            // dXNlcjpwYXNz = 'user:pass' (user:pass) base64  /////  (admin:01_Admin YWRtaW46MDFfQWRtaW4=)   https://www.base64encode.org/ 

  char loginFTP[40];
  char passwordFTP[40];
  
// Datalogger
  boolean dataloggerSwitch;                             // Valide Datalogger
  char fichierEnCours[40];
  unsigned char lcdRetro;                               // retroeclairage
  char timeReboot[25];                                  // temps du dernier reboot "YYYY-MM-DDTHH:MM:SSZ"
  
} conf_t;
conf_t conf;                                            // conf est la variable structure avec les information conf.ip[] , conf.subnet[] ....
conf_t conf_TMP;

// Definition des valeurs Reseau par defaut
const conf_t default_conf = {
  VALID,                                                // ID Cette variable permet de verifier que l'EEPROM a deja ete programme par ce programme 
  "PriseIP_UNO_R4",                                     // Nom du system
  1,                                                    // WEB Switch
  1,                                                    // FTP Switch
  
  0,                                                    // Etat LED

  {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xB1},                 // mac  DE:AD:BE:EF:FE:B1   DE:AD:BE:EF:FE:B2
  0,                                                    // dhcp
  { 192, 168, 0,   10  },                               // ip
  { 255, 255, 255, 0   },                               // Masque sous reseau
  { 192, 168, 0,   254 },                               // Passeralle
  80,                                                   // PORT WEB 0-- 65536 Par defaut port serveur WEB : 80

  0,                                                    // Enable =1 // Disable = 0 --> Login et Password
  "dXNlcjpwYXNz",                                       // dXNlcjpwYXNz = 'user:pass' (user:pass) base64  ////   https://www.base64encode.org/ 
  
  "arduino",                                            // Login FTP
  "arduino",                                            // MdP FTP

  0,                                                    // ON / OFF Datalogger  
  "datalogger.csv",                                     // Nom fichier datalogger
  200,                                                  // conf.lcdRetro retro de 0 a 255
  "YYYY-MM-DDTHH:MM:SSZ",                               // taille suffisante pour "YYYY-MM-DDTHH:MM:SSZ" + '\0'
};
// Nom du Fichier ino : Attention il faur cree le __FILE__ dans le fichier principale (ino)   // https://forum.arduino.cc/t/filename-ino-as-string-variable/583738/20
  String ino = __FILE__;
//  ino = (ino.substring((ino.indexOf(".")), (ino.lastIndexOf("\\")) + 1));
  String date_ino = __DATE__;
  String time_ino = __TIME__;
  
// Declaration Valeurs programme (Etiquette = Valeur) 
unsigned char adressBase = 5;                               // Adresse de base de depart de l'ecriture des DATA en EEPROM
boolean etatWAN = 0;                                        // Etat connexion Internet (google DNS)
boolean dhcpEtat = 0;                                       // Etat du mode de la carte reseau ( basculement automatique en mode dhcp si l aconfiguration reseau de l'Arduino est fausse)

const char * fichierSD_datalogger = "datalogger.csv";       // Nom du Fichier copier dans la partition SD !!! Voir procedure pour televerser le fichier !!!!
const char * formatCSV = "Date ; Heure ; Etat LED";         // Entete du Fichier Excel

// Serial
unsigned long startSerial = millis();
boolean premiereConnexionSerial = 1;
boolean etatPrecedentConnexionSerial = 0;
boolean etatActuelConnexionSerial = 0;

// Variable Menu LCD ( Boucle principale loop)
char fonctionSelect = 0;                                                                 // Variable de sortie contenant le numero du menu LCD choisis
int decalCaract = 0;

// 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
char comptAffichageLCD = 0;                                                              // 
unsigned long previousMillisAffichageLCD = 0;                                            // previousMillisAffichageLCD
boolean validMessConnexionFTP = 0;
char bufferIP[16];                                                                       // "255.255.255.255" + \0
unsigned long previousMillisConnexionInternet = 0;                                       //

// Declaration PORT Entrer Sortie de l'Arduino 
#define pinled D5                     

















void setup() 
{
  // start Ethernet
  Ethernet.begin(mac, ip);
  Serial.begin(115200);





 // 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(800000);
  u8g2.setBusClock(400000);
// 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










}

void loop()
{
  EthernetICMPEchoReply echoReply = ping(pingAddr, 4);
  if (echoReply.status == SUCCESS)
  {
    sprintf(buffer,
            "Reply[%d] from: %d.%d.%d.%d: bytes=%d time=%ldms TTL=%d",
            echoReply.data.seq,
            echoReply.addr[0],
            echoReply.addr[1],
            echoReply.addr[2],
            echoReply.addr[3],
            REQ_DATASIZE,
            millis() - echoReply.data.time,
            echoReply.ttl);
  }
  else
  {
    sprintf(buffer, "Echo request failed; %d", echoReply.status);
  }
  Serial.println(buffer);
  delay(500);
}





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
      {  
           ISR_Etat_BoutonPlus = 1;
           //comptScroll++;
           //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;
      }
}
