//Mit kell tudni a programnak a számítőgépről történő vezérléshez?
//A kommunikációt konzolból enterrel elküldött parancsokkal fogjuk végezni
//A beküldött szöveget feldaraboljuk speciális karakterek mentén "=" "," "\n". A darabolásra az strtok funkciót használjuk.
//A parancs szerkezete: 
//parancs felépítés 1 paraméterrel:  PARANCS_NEVE=parameter1
//Parancs felépítés 3 paraméterrel:  PARANCS_NEVE=parameter1,parameter2,parameter3
//Led ki-be parancs:                 LED=1 vagy LED=0
//Szín változtatás parancs:          RGB=255,255,255
//Fényerő parancs:                   FENYERO=100

//Itt állíthatod be a megfelelő pineket ESP/Arduino-n
#ifdef ESP8266
  #define LED_FENYERO A0
  #define LED_ZOLD D1
  #define LED_KEK D2
  #define LED_PIROS D0
  #define PWM_MAX 1024
#else
  #define LED_FENYERO A0
  #define LED_ZOLD 3
  #define LED_KEK 5
  #define LED_PIROS 6
  #define PWM_MAX 255
#endif

//tures ertek a potmeterhez
#define ANALOG_TURES 5
//max feldolgozhato parameter szam a serial-bol
#define MAX_PARAMETER 3
//globalis fenyero
uint8_t fenyero = 0; //utoljára beállított fényerő értéke 0 - 100 között
uint8_t fenyero_aktualis = 0; //ebbe olvassuk ki az aktuális loopban mért analóg értéket 0-1023 ról a map funkcióval 0-100-ra konvertált értékkel
unsigned long utolso_fenyerovaltozas = 0; //az utolsó fizikai potméter érték változásának időpontja
unsigned long fenyerovaltozastures = 100; //500ms enként 1 változás lehet
bool potmeterstatusz = true; //fizikai potméter használat ki(false) - be(true)

//globális aktuális szin eltarolas, az uint8_t 0-255 ig tárol
uint8_t led_piros = 0;
uint8_t led_kek = 0;
uint8_t led_zold = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("Indulas ...");
  pinMode(LED_FENYERO, INPUT);
  pinMode(LED_ZOLD, OUTPUT);
  pinMode(LED_KEK, OUTPUT);
  pinMode(LED_PIROS, OUTPUT);
  analogWrite(LED_ZOLD, 0);
  analogWrite(LED_KEK, 0);
  analogWrite(LED_PIROS, 0);
  //strtokPelda();
}

void loop() {
    //van a serialon feldolgozando adat?
    if (Serial.available()>0) {
      //a \n az "ENTER" amit a parancs utan fuz a Serial monitor kuldeskor
      String packet = Serial.readStringUntil('\n');
      
      //aktualisan beolvasott parameterek taroloja
      int parametertomb[MAX_PARAMETER];
      //parameter_szam az aktuális paramtere indexet tárolja, hogy hányadik helyre rakjuk a kiolvasott paramétert
      uint8_t parameter_szam = 0;
      //aktualis parancs
      char* parancs;

      //Formatum: PARANCS=param1,param2,param3,param4 ....
      char* seq = strtok(&packet[0],"=");
      parancs = seq;
      // paramétertömb nullazasa, (-1) mivel a parameterek kozott lehet 0 is
      for (int i = 0; i < MAX_PARAMETER; i++) {
        parametertomb[i] = -1;
      }
      
      if (seq != NULL) {
          //maradek kikerese (PARANCS=[ezt_a_reszt,lehet]
          seq = strtok(NULL,"=");
          //vannak parameterek
          if (seq != NULL) {
            //nullázuk a paraméter tömb indexét
            parameter_szam = 0;
            seq = strtok(seq,",");
            //feltoltjuk a parametertombot
            while (seq != NULL && parameter_szam < MAX_PARAMETER) {
                parametertomb[parameter_szam] = atoi(seq); //atoi(char* str) funkció a seq char* változót int-re konvertálja
                parameter_szam++; // növeljük a paraméter tömb indexét
                seq = strtok(NULL,","); //tovább léptetjük a seq-et, hogy olvassa ki a következő paraméter értékét
            }
          }
      }
       /*
        Ellenőrzés
       */
      
        /*Serial.println("----------Ellenőrzés kezdete------------");
        Serial.println("Parancs: "+String(parancs));
        for (int i = 0; i < MAX_PARAMETER; i++) {
          Serial.println("Parameter("+String(i+1)+"): "+String(parametertomb[i]));
        }
        Serial.println("-----------Ellenőrzés vége--------------");*/
      //void ParancsVegrehajtas(char* parancs, int* parametertomb) funkció hívása 
      ParancsVegrehajtas(parancs, parametertomb);
    }

    int analogErtek = analogRead(LED_FENYERO); //kiolvasott analog érték
    if (analogErtek < ANALOG_TURES) { analogErtek = 0; } //ha tűrés alatt van a jel akkor 0-ra húzzuk az értékét
    fenyero_aktualis = map(analogErtek, 0, 1024, 0, 100); //az akutális fényerőbe mapeljuk az analóg jelet

    //ez a korábban már használt érték változást és az utolsó interakciótól minimum eltelt tűrési időt vizsgáló logikai kapu  
    if (fenyero_aktualis != fenyero && (utolso_fenyerovaltozas == 0 || utolso_fenyerovaltozas < millis() - fenyerovaltozastures)) {
        fenyero = fenyero_aktualis;
        //alapértelmezetten lefut, kivéve ha a  potméter ki lett kapcsolva a POTMETER=0 paranccsal
        if (potmeterstatusz) {
          LedSzalagFenyero(fenyero);
        }
        utolso_fenyerovaltozas = millis();
    }
}

void strtokPelda(){
   /*
    strtok példa
    */
    String packet_pelda = "RGB=255,254,253";
    char* parancs_pelda;
    char* seq_pelda = strtok(&packet_pelda[0],"="); 
     //az strtok, amíg nem kap új értéket az első paraméterben egy belső változóban eltárolja az utoljára átadott értéket
    parancs_pelda = seq_pelda;
    Serial.println("-------PARANCS OLVASÁS UTÁN, LÉPTETÉS ELŐTT---------");
    Serial.println("parancs_pelda erteke = "+String(parancs_pelda));
    Serial.println("seq_pelda erteke = "+String(seq_pelda));
    Serial.println("-------PARANCS OLVASÁS LÉPTETÉSE--------");
    seq_pelda = strtok(NULL,"=");
     //ha NULL értékkel hivatkozunk az első paraméterben akkor a belső változójából eltávolítja az előző találatot 
     //és a második paraméterben átadott elválasztóig keres tovább, ha nincs már a szövegben ilyen paraméter, akkor az összes maradékot visszaadja
     //amennyiben NULL a visszatérési értéke,akkor kiürült a változó
    Serial.println("seq_pelda erteke = "+String(seq_pelda));
    Serial.println("-------PARAMÉTER OLVASÁS LÉPÉS 1--------");
    seq_pelda = strtok(seq_pelda,",");
    Serial.println("seq_pelda erteke = "+String(seq_pelda));
    Serial.println("-------PARAMÉTER OLVASÁS LÉPTETÉS 2--------");
    seq_pelda = strtok(NULL,",");
    Serial.println("seq_pelda erteke = "+String(seq_pelda));
    Serial.println("-------PARAMÉTER OLVASÁS LÉPTETÉS 3--------");
    seq_pelda = strtok(NULL,",");
    Serial.println("seq_pelda erteke = "+String(seq_pelda));
     Serial.println("-------PARAMÉTER OLVASÁS LÉPTETÉS 4--------");
    seq_pelda = strtok(NULL,",");
    if(seq_pelda == NULL){
       Serial.println("seq_pelda erteke KIÜRÜLT");
    }
    else{
      Serial.println("seq_pelda erteke = "+String(seq_pelda));
    }      
    /*
    strtok példa vége
   */
}

void ParancsVegrehajtas(char* parancs, int* parametertomb) {
    //ledszalag be/ki kapcsolasa adott szinnel
    if (String(parancs) == "LED") {
        if (parametertomb[0] == 1) {
           LedSzalagSzin(255,255,255, true); // ledszalag bekapcsolasa feherre
           Serial.println("Ok, LED bekapcsolva (feher)");
        //ledszalag kikapcsolasa
        }else {
           LedSzalagSzin(0,0,0, true);
           Serial.println("Ok, LED kikapcsolva");
        }
    //RGB ledszalag szinenek beallitasa
    }else if(String(parancs) == "RGB") {
        //ertekek ellenorzese
        for (int i=0; i<3; i++) {
            //ha a parametertomb[i] nagyobb mint -1 van beállított értéke
            if (parametertomb[i] > -1 && parametertomb[i] <= 255) {
            }else{
               Serial.println("RGB, "+String((i+1))+". parameter rossz ertek! (0-255)");
               return; //funkció futásának megszakítása, de értékeket is tud vissza adni
            }
        }
        //szin beallitasa
        LedSzalagSzin(parametertomb[0], parametertomb[1], parametertomb[2], true);
        Serial.println("Ok, RGB SZIN beallitva");
    }
    //FENYERO=
    else if(String(parancs) == "FENYERO") {
        potmeterstatusz = false;
        if (parametertomb[0] >= 0 && parametertomb[0] <= 100) {
            LedSzalagFenyero(parametertomb[0]);
            Serial.println("Ok, FENYERO mostantól = "+ String(parametertomb[0]));
        }else {
            Serial.println("FENYERO, 1. parameter rossz ertek! (0-100)");
        }
    }
    else if(String(parancs) == "POTMETER") {
        if (parametertomb[0]==1) { potmeterstatusz = true; }
        else { potmeterstatusz = false; }
        Serial.println("Ok, POTMETER státusz mostantól = "+ String(potmeterstatusz?"BE":"KI"));
    }
    else {
        Serial.println("Ismeretlen parancs: "+String(parancs));
    }
}

void LedSzalagFenyero(uint8_t ertek) {
   //a globális színek értékét csökkentsük az értékben megadott százalékra, float változókat használunk, mivel tört értékeket is létrejöhetnek
   float p = led_piros * ((float)ertek / 100);
   float k = led_kek  * ((float)ertek / 100);
   float z = led_zold * ((float)ertek / 100);

   utolso_fenyerovaltozas = millis(); //felírjuk az utolsó fényerő módosulás idejét
   //(int)ceil(float szam) kódrésszel, a float értékű törteket egész számmá konvertáljuk
    //a contrain funkcióval korlátozzuk az új értékeket, hogy biztosan 0 - 255 közötti értéket vehessenek csak fel
   LedSzalagSzin(
      constrain((int)ceil(p),0,255),
      constrain((int)ceil(z),0,255),
      constrain((int)ceil(k),0,255),
      false //színkeverés esetén nem tároljuk a globális változóba a módosított színeket
   );
}

void LedSzalagSzin(uint8_t piros, uint8_t zold, uint8_t kek, bool szin_eltarolasa) {
  //szin eltarolasa
  if (szin_eltarolasa) {
     led_piros = piros;
     led_zold = zold;
     led_kek = kek;
  }

   //skalazzuk az a bejovo 0-255 ertekeket az aktualis MAX_PWM szerint (Arduino,Esp)
   analogWrite(LED_ZOLD,  map(zold, 0, 255, 0, PWM_MAX));
   analogWrite(LED_KEK,   map(kek, 0, 255, 0, PWM_MAX));
   analogWrite(LED_PIROS, map(piros, 0, 255, 0, PWM_MAX));
}
