//
#include "Define.h"
#include "NtpDateTime.h"
#include "SDCard.h"
//
const char* WIFI_SSID     = "FritzBoxSA7";
const char* WIFI_PASSWORD = "01234567890123456789";
//
const unsigned int UDP_PORT = 1234;
const unsigned SIZE_RESPONSECOUNT = 3;
const int PIN_LEDSYSTEM = 2;
//
extern char GlobalBuffer;
extern char GlobalLine[];
WiFiUDP UDP;
char RxBuffer[SIZE_GLOBALBUFFER];
char TxBuffer[SIZE_GLOBALBUFFER];
bool IsRemoteIP = false;
long unsigned TicksPreset;
unsigned ResponseLedCount = SIZE_RESPONSECOUNT;
unsigned ResponseDateTimeCount = SIZE_RESPONSECOUNT;
//
const char* NTPSERVER = "pool.ntp.org";
const long  GMTOFFSET = 3600; // [s]
const int   DAYLIGHTOFFSET = 0; // [s]
//
long unsigned MillisPreset;
CNtpDateTime NtpDateTime;
CSDCard SDCard(PIN_SPIL_SS);
//
char DirectoryYY[4];
char DirectoryMM[4]; 
char DirectoryDD[4];
//
//
const char* GetStateLed(void)
{
  if (digitalRead(PIN_LEDSYSTEM))
  {
    return "ON";
  }
  return "OFF";
}
//
void setup() 
{
  Serial.begin(115200);
  Serial.println("\r\n");
  Serial.println("*****************************");
  Serial.println("* Esp32HomeAutomationServer *");
  Serial.println("* Version....: 01V00        *");
  Serial.println("* Date.......: 221107       *");
  Serial.println("* Time.......: 1059         *");
  Serial.println("* Author.....: OMdevelop    *");
  Serial.println("*****************************");
  //
  pinMode(PIN_LEDSYSTEM, OUTPUT);
  for (int I = 0; I < 3; I++)
  {
    digitalWrite(PIN_LEDSYSTEM, HIGH);
    delay(200); 
    digitalWrite(PIN_LEDSYSTEM, LOW);
    delay(200); 
  }
  //
  NtpDateTime.ConnectWifi(WIFI_SSID, WIFI_PASSWORD);
  NtpDateTime.Initialise(NTPSERVER, GMTOFFSET, DAYLIGHTOFFSET);
  //
  UDP.begin(UDP_PORT);
  Serial.print("Listening on UDP-Port: ");
  Serial.println(UDP_PORT);
  //
  if (!SDCard.Initialise())
  {
    Error("Card Mount Failed");
    return;
  }
  Message("SDCard correct initialised");
  ECardType CT = SDCard.GetCardType();
  if ((ctNone == CT) || (ctUnknown == CT))
  {
    Error("CardType undefined");
     return;
  }
  Term("CardType: ");
  Message(CardTypeText(CT));
  sprintf(GlobalLine, "CardSize: %lluMB", SDCard.GetCardSizeMB());
  Message(GlobalLine); 
  //
  TicksPreset = millis();
}

void loop() 
{
  int SP = UDP.parsePacket();
  if (0 < SP) 
  {
    Serial.print("RxData: Size[B]: ");
    Serial.println(SP); 
    int LR = UDP.read(RxBuffer, SIZE_GLOBALBUFFER);
    if (0 < LR)
    {
      RxBuffer[LR] = '\0';
    }
    Serial.print("Packet received: ");
    Serial.println(RxBuffer);
    IsRemoteIP = true;
    if (0 == strncmp("LSO", RxBuffer, 3))
    {
      digitalWrite(PIN_LEDSYSTEM, HIGH);
      sprintf(TxBuffer, "Command-Handshake[%s]", RxBuffer);
      UDP.beginPacket(UDP.remoteIP(), UDP.remotePort());
      UDP.print(TxBuffer);
      UDP.endPacket();    
      ResponseLedCount = 0;
    }
    else
    if (0 == strncmp("GDT", RxBuffer, 3))
    {
      sprintf(TxBuffer, "Command-Handshake[%s]", RxBuffer);
      UDP.beginPacket(UDP.remoteIP(), UDP.remotePort());
      UDP.print(TxBuffer);
      UDP.endPacket();    
      ResponseDateTimeCount = 0;
    }
  }
  if (1000 < (millis() - TicksPreset))
  {
    TicksPreset = millis();
    // write each cycle to sdcard:
    struct tm DateTime;
    if (!NtpDateTime.GetDateTimeStructure(DateTime))
    {
      Error("Cannot access DateTime");
    }
    else
    { // DirectoryYY
      sprintf(&GlobalBuffer, "/%2.2u", DateTime.tm_year);
      SDCard.CreateDirectory(&GlobalBuffer);
      // DirectoryMM
      sprintf(&GlobalBuffer, "/%2.2u/%2.2u", 
              DateTime.tm_year, DateTime.tm_mon);
      SDCard.CreateDirectory(&GlobalBuffer);
      // DirectoryDD
      sprintf(&GlobalBuffer, "/%2.2u/%2.2u/%2.2u", 
              DateTime.tm_year, DateTime.tm_mon, DateTime.tm_mday);
      SDCard.CreateDirectory(&GlobalBuffer);
      // DataFile
      sprintf(&GlobalBuffer, "/%2.2u/%2.2u/%2.2u/%2.2u%2.2u.txt", 
              DateTime.tm_year, DateTime.tm_mon, DateTime.tm_mday,
              DateTime.tm_hour, DateTime.tm_min);
      SDCard.OpenAppend(&GlobalBuffer);
      // Measurement
      float Data = 10.0 + 10 * sin(6.28318531 * DateTime.tm_sec / 20.0);
      sprintf(&GlobalBuffer, "%2.2u%2.2u%2.2u%2.2u%2.2u%2.2u %6.3f", 
              DateTime.tm_year, DateTime.tm_mon, DateTime.tm_mday, 
              DateTime.tm_hour, DateTime.tm_min, DateTime.tm_sec, Data);
      SDCard.WriteLine(&GlobalBuffer);
      SDCard.CloseWrite();
      Message(&GlobalBuffer);
    }
    // ...
    // network...
    if (IsRemoteIP)
    {
      if (ResponseLedCount < SIZE_RESPONSECOUNT)
      {
        ResponseLedCount++;
        sprintf(TxBuffer, "Response[%d/%d]<%s>", 
                ResponseLedCount, SIZE_RESPONSECOUNT, GetStateLed());
        Serial.println(TxBuffer);
        UDP.beginPacket(UDP.remoteIP(), UDP.remotePort());
        UDP.print(TxBuffer);
        UDP.endPacket();
      }
      else
      { // wait for next Client-Request
        digitalWrite(PIN_LEDSYSTEM, LOW);
      }
      if (ResponseDateTimeCount < SIZE_RESPONSECOUNT)
      {
        ResponseDateTimeCount++;
        sprintf(&GlobalBuffer, "DateTime[%s]",  NtpDateTime.GetDateTimeText());
        if (strlen(&GlobalBuffer) < 12)
        {
          Error("Cannot access DateTime");
        }
        else
        {
          Message(&GlobalBuffer);
        }
      }
    }
  }

}
