//#include <LiquidCrystal_I2C.h>

//SDA pin 19 and SCL pin 23 Lolin 32 lite
#include "LiquidMenu.h"
#include "AiEsp32RotaryEncoder.h"
#include "Arduino.h"
//#include <LiquidCrystal.h>

// Uso de la libreria AI Esp32RotaryEncoder
#if defined(ESP32)
#define ROTARY_ENCODER_A_PIN 27 // Pin CLK
#define ROTARY_ENCODER_B_PIN 26  // Pin DT
#define ROTARY_ENCODER_BUTTON_PIN 25  //Pîn SW
#endif
#define ROTARY_ENCODER_VCC_PIN -1 /* 27 put -1 of Rotary encoder Vcc is connected directly to 3,3V; else you can use declared output pin for powering rotary encoder */

#define ROTARY_ENCODER_STEPS 4

AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, ROTARY_ENCODER_VCC_PIN, ROTARY_ENCODER_STEPS);
unsigned long shortPressAfterMiliseconds = 50;
unsigned long longPressAfterMiliseconds = 500;


// int led_seleccionado = 0;
bool mode = false;  // Activa el while del movimiento del motor
int x = 0;  // Variable que cuenta los pasos del motor (Analizar si para a variable local)
TaskHandle_t Tarea0;

int lastvalor = 0;
int valor = 0;

int Contauxcero;
bool testcero = false;
int x1 = 0; // Variable que cuenta los ciclos del motor
int delayciclos;
int demora;
int timer = 0;
int cursorPos;
int cursorPos2 = 0;
int Contaux = 0;
unsigned long Ciclos = 0;
unsigned long Ciclos_1 = 0;
unsigned long Ciclos_2 = 0;
unsigned long tanterior;
int Cont_1 = 0;
int Cont_2 = 0;
int Cont_3 = 0;
boolean Giro = true; // Variable que indica el sentido de giro del motor
boolean auxGiro;
String Gir;
boolean a = false; // Variable para ver si se activan por ciclos o no, si es FALSE se activa (invertir eso)
boolean b = false; // Variable para ver si se activan la opcion cantidad, si es FALSE se activa (invertir eso), se usa para la opcion de solo mover izq o der.
unsigned long Pasos = 0;
bool showChar = true;

//Driver Motor Step
const int steppin = 33;
const int dirpin = 32;

//Display 16x2
LiquidCrystal_I2C lcd(0x27, 16, 2);
//const int RS = 23, EN = 22, D4 = 5, D5 = 18, D6 = 19, D7 = 21;
//LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);

byte tpuntos[] = {
  0b00000,
  0b00000,
  0b00001,
  0b01000,
  0b11100,
  0b01001,
  0b01000,
  0b01100
}; // t:

byte ipuntos[] = {
  0b00000,
  0b00000,
  0b00001,
  0b01000,
  0b00000,
  0b01001,
  0b01000,
  0b01100
}; //i:

byte s[] = {
  0b00000,
  0b01000,
  0b10011,
  0b10100,
  0b10010,
  0b10001,
  0b01110,
  0b00000
}; //(s

byte paren[] = {
  0b00000,
  0b10000,
  0b01000,
  0b01000,
  0b01000,
  0b01000,
  0b10000,
  0b00000
}; // )

byte uve[]{
  0b00000,
  0b00000,
  0b10101,
  0b10100,
  0b10100,
  0b10101,
  0b01000,
  0b00000
};

byte UP[]{
  0b00100,
  0b01110,
  0b11111,
  0b00100,
  0b00100,
  0b00100,
  0b00000,
  0b00000,
};

const int Pulsa = 10;

//ENCODER
//const int outputA = 17; // CLK
//const int outputB = 16; // DT
//const int SW = 4;
int incremento = 0;
int incrementos = 0;
int aState;
int bState;
int aLastState;
//const int UPs = 16;
//const int DW  = 4;  // Pin del pulsador para moverse hacia abajo
int buttonUpState;
int buttonDownState;
int lastButtonUpState = LOW;
int lastButtonDownState = LOW;
unsigned long lastDebounceTimeUp = 0;
unsigned long lastDebounceTimeDown = 0;
unsigned long debounceDelay = 50;
unsigned long lastDebounceTime = 0;
//const int UPs = 16;
//unsigned long debounceDelay = 50;

//LiquidMenu
//Pantalla 1
LiquidLine linea1(1, 0, "Volumen");
LiquidLine linea2(1, 1, "Encender");
//LiquidLine linea3(1, 0, "Ciclos?");
LiquidLine linea3(1, 0, "Opciones");
//LiquidLine linea4(1, 1, "Hola a todos");
LiquidScreen pantalla1(linea1,linea2,linea3);

//Pantalla linea 1 -> Pantalla 2
LiquidLine linea1_2(1, 0, "Cantidad");
LiquidLine linea2_2(1, 1, "Repeticiones");
LiquidLine linea3_2(1, 0, "Atras");
LiquidScreen pantalla2(linea1_2,linea2_2,linea3_2);

//Pantalla linea 2 -> Pantalla 3
LiquidLine linea1_3(1, 0, "Hacia la Der.");
//LiquidLine linea2_3(1, 1, "Hacia la Izq.");
LiquidLine linea3_3(1, 1, "Atras");
LiquidScreen pantalla3(linea1_3,/*linea2_3,*/linea3_3);

//Pantalla linea 4 -> Pantalla 4
LiquidLine linea1_4(1, 0, "Opcion 1");
LiquidLine linea2_4(1, 1, "Opcion 2");
LiquidLine linea3_4(1, 1, "Atras");
LiquidScreen pantalla4(linea1_4,linea2_4,linea3_4);

LiquidMenu menu(lcd,pantalla1,pantalla2,pantalla3,pantalla4);

void IRAM_ATTR readEncoderISR(){

	rotaryEncoder.readEncoder_ISR();
}

void setup() {

	rotaryEncoder.begin();
	rotaryEncoder.setup(readEncoderISR);
	bool circleValues = false;
	rotaryEncoder.setBoundaries(-10000, 10000, circleValues); //minValue, maxValue, circleValues true|false (when max go to min and vice versa)
	//rotaryEncoder.disableAcceleration(); //acceleration is now enabled by default - disable if you dont need it
  rotaryEncoder.setAcceleration(250); //or set the value - larger number = more accelearation; 0 or 1 means disabled acceleration

  Serial.begin(115200);
  pinMode(Pulsa, INPUT_PULLUP);
  pinMode(steppin, OUTPUT);
  pinMode(dirpin, OUTPUT);

  xTaskCreatePinnedToCore(Motor, "Tarea_0", 1000, NULL, 1, &Tarea0, 0);

  lcd.init();
  //lcd.clear();
  lcd.backlight();
  menu.init();
  //lcd.begin(16, 2);
  lcd.createChar (0, tpuntos);
  lcd.createChar (1, ipuntos);
  lcd.createChar (2, s);
  lcd.createChar (3, paren);
  lcd.createChar (4, uve);

  //tanterior = millis();

  linea1.set_focusPosition(Position::LEFT); 
  linea2.set_focusPosition(Position::LEFT); 
  linea3.set_focusPosition(Position::LEFT); 
   
  linea1.attach_function(1, fn_volumen); 
  linea2.attach_function(1, fn_encender);
  linea3.attach_function(1, fn_opciones);
  
  menu.add_screen(pantalla1);
  
//---------------------------------------------

  linea1_2.set_focusPosition(Position::LEFT);
  linea2_2.set_focusPosition(Position::LEFT);
  linea3_2.set_focusPosition(Position::LEFT);
  
  linea1_2.attach_function(1, fn_cantidad);
  linea2_2.attach_function(1, fn_ciclos);
  linea3_2.attach_function(1, fn_atras);
   
  menu.add_screen(pantalla2);

//---------------------------------------------

  linea1_3.set_focusPosition(Position::LEFT); 
  //linea2_3.set_focusPosition(Position::LEFT);
  linea3_3.set_focusPosition(Position::LEFT); 
   
  linea1_3.attach_function(1, fn_onR); 
  //linea2_3.attach_function(1, fn_onL);
  linea3_3.attach_function(1, fn_atras); 
    
  menu.add_screen(pantalla3);

//---------------------------------------------

  linea1_4.set_focusPosition(Position::LEFT);
  linea2_4.set_focusPosition(Position::LEFT);
  linea3_4.set_focusPosition(Position::LEFT);
   
  linea1_4.attach_function(1, fn_opcion1);
  linea2_4.attach_function(1, fn_opcion2);
  linea3_4.attach_function(1, fn_atras);

  menu.add_screen(pantalla4);

//---------------------------------------------
  pantalla1.set_displayLineCount(2);
  pantalla2.set_displayLineCount(2);
  pantalla3.set_displayLineCount(2);
  pantalla4.set_displayLineCount(2);

  menu.set_focusedLine(0);

  menu.update();
}

void rotary_loop(){

	//dont print anything unless value changed
	if (rotaryEncoder.encoderChanged()){
    //delay(250);
    valor = rotaryEncoder.readEncoder();
		Serial.print("Value: ");
		Serial.println(rotaryEncoder.readEncoder());

        //delay(10);
      
        if(valor - lastvalor < 0){            
          
          menu.switch_focus(false);
        }     
        else {

          menu.switch_focus(true);
        }
        menu.update();
        //lastvalor = valor;
      lastvalor = rotaryEncoder.readEncoder();
	}

  

	if (rotaryEncoder.isEncoderButtonClicked()){
  
    menu.call_function(1);  //Antigua void selectOption()
    delay(500);
	}
  
  handle_rotary_button();
}

void handle_rotary_button() {

  static unsigned long lastTimeButtonDown = 0;
  static bool wasButtonDown = false;
  bool isEncoderButtonDown = rotaryEncoder.isEncoderButtonDown();
  //isEncoderButtonDown = !isEncoderButtonDown; //uncomment this line if your button is reversed

  if (isEncoderButtonDown) {
    Serial.print("+");  //REMOVE THIS LINE IF YOU DONT WANT TO SEE
    if (!wasButtonDown) {
      //start measuring
      lastTimeButtonDown = millis();
    }
    //else we wait since button is still down
    wasButtonDown = true;
    return;
  }
  //button is up
  if (wasButtonDown) {
    Serial.println("");  //REMOVE THIS LINE IF YOU DONT WANT TO SEE
    //click happened, lets see if it was short click, long click or just too short
    if (millis() - lastTimeButtonDown >= longPressAfterMiliseconds) {
      on_button_long_click();
    } else if (millis() - lastTimeButtonDown >= shortPressAfterMiliseconds) {
      on_button_short_click();
    }
  }
  wasButtonDown = false;
}

void rotary_onButtonClick()
{
  	static unsigned long lastTimePressed = 0;
	  //ignore multiple press in that time milliseconds
	  if (millis() - lastTimePressed < 500)
	  {
		  return;
	  }

	  lastTimePressed = millis();
	  Serial.print("button pressed ");
	  Serial.print(millis());
	  Serial.println(" milliseconds after restart");

}

void loop() {

  rotary_loop();
  atrass();

}


void on_button_short_click() {
  Serial.print("button SHORT press ");
  Serial.print(millis());
  Serial.println(" milliseconds after restart");
}

void on_button_long_click() {
  Serial.print("button LONG press ");
  Serial.print(millis());
  Serial.println(" milliseconds after restart");
}

void Motor(void *parameter){
 
  while(1==1){
    while(mode == true && x1 < Ciclos){
      for(x1 = 0; x1 < Ciclos; x1++){
        delay(delayciclos);
        digitalWrite(dirpin, Giro);
        for(x = 0; x < Pasos; x++){
          digitalWrite(steppin, HIGH);
          digitalWrite(steppin, LOW);
          delayMicroseconds(5000);
          if(digitalRead(Pulsa) == LOW){
            break;
            atrass();
          }
        }
      }
      Giro = true;
    }
    vTaskDelay(50);
  }
}



//Funciones:::::
/*void selectOption(){
  if(rotaryEncoder.isEncoderButtonClicked(){
    menu.call_function(1);
    delay(500);
  }
}*/

void fn_volumen(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
}

void fn_encender(){
  menu.change_screen(3);
  menu.set_focusedLine(0);
}

void fn_opciones(){
  menu.change_screen(4);
  menu.set_focusedLine(0);
}

void fn_off(){
  menu.change_screen(1);
  menu.set_focusedLine(0);
}

void fn_atras(){
  menu.change_screen(1);
  menu.set_focusedLine(0);
}


void fn_onR(){

  Pasos = 4294967295;
  Ciclos = 4294967295;
  delayciclos = 0;
  Giro = true;
  a = true;
  b = true;
  fn_ciclos();
  menu.change_screen(3);
  menu.set_focusedLine(0);
}

/*void fn_onL(){
  
  Pasos = 4294967295;
  Ciclos = 4294967295;
  delayciclos = 0;
  Giro = false;
  a = true;
  b = true;
  fn_ciclos();
  menu.change_screen(3);
  menu.set_focusedLine(1);
}*/

void fn_cantidad(){

  Ciclos = 1;
  delayciclos = 0;
  a = true;
  fn_ciclos();
}

void fn_ciclos(){

  lcd.clear();
  Serial.print("entra a ciclos, a = " + String(a));
  delay(250);
  for(int i = 0; i < 2; i++){

      while(rotaryEncoder.isEncoderButtonClicked() == false && a == false){
      if(digitalRead(Pulsa) == LOW){
       break;
       atrass();
      }
      rotaryEncoder.setAcceleration(50);
      Movement();
      
      switch(i){
        case 0:
        Ciclos_1 = Contaux;
        cursorPos = 11;
        //lcd.setCursor(11, 0);
        //lcd.print(Ciclos_1);
        lcd.setCursor(11,1);
        lcd.print(demora);
        break;
        case 1:
        demora = Contaux;
        lcd.setCursor(11, 0);
        lcd.print(Ciclos);
        cursorPos = 11;
        cursorPos2 = 1;
        break;
        /*case 2:
        Ciclos_2 = Contaux;
        cursorPos = 11;
        lcd.setCursor(12, 0);
        lcd.print(Ciclos_1);
        lcd.setCursor(11,1);
        lcd.print(demora);
        Serial.println("case 1");

        break;*/
      }
      lcd.setCursor(1, 0);
      lcd.write(165);
      lcd.print("Repet. = ");
      lcd.setCursor(1, 1);
      lcd.write(165);
      lcd.print("Demora = ");
      lcd.setCursor(14,1);
      lcd.write((byte)2);
      lcd.write((byte)3);
      //lcd.print("(s)");

      lcd.setCursor(cursorPos, cursorPos2);
    
      if (millis() - tanterior >= 290) {
        tanterior = millis();

        if (showChar) {
          lcd.print(Contaux);
        } 
        else {
          lcd.print("   ");
        }
        showChar = !showChar;
      }

      Ciclos = Ciclos_1;
      
      delayciclos = demora*1000;
    }
    delay(250);
    Contaux = 0;
    cursorPos2 = 0;
    lcd.clear();
    delay(100);
  }
  Ciclos_1 = 0; Ciclos_2 = 0;

  if(b == false){
    for(int i = 0; i < 3; i++){
      
      if(digitalRead(Pulsa) == LOW){
        break;
        i = 2;
        atrass();
      }
      delay(150);

      while(rotaryEncoder.isEncoderButtonClicked() == false && digitalRead(Pulsa) == false){
        Serial.println("aqui");
        rotaryEncoder.setAcceleration(250);
        Movement();
        switch(i){
          case 0:
            Cont_1 = Contaux;
            lcd.setCursor(10, 0);
            lcd.print(Cont_3);
            lcd.print(Cont_2);
            break;
          case 1:
            Cont_2 = Contaux;
            lcd.setCursor(10, 0);
            lcd.print(Cont_3);
            lcd.setCursor(12, 0);
            lcd.print(Cont_1);
            break;
          case 2:
            Cont_3 = Contaux;
            lcd.setCursor(11, 0);
            lcd.print(Cont_2);
            lcd.print(Cont_1);
            break;
          /*case 3:
            cursorPos2 = 1;
            lcd.setCursor(10,0);
            lcd.print(Pasos);
            lcd.setCursor(1,1);
            if(auxGiro == 1){
              auxGiro = "Funca 1";
              lcd.print("Funca pa un lao");
              
            }
            else{
              auxGiro = "Funca 0";
              lcd.print("Funca pal otro lao");
            }
            break;*/

        }
        lcd.setCursor(0, 0);
        lcd.print("Cant. => ");
        lcd.setCursor(14, 0);
        lcd.print("ml ");
        cursorPos = 12 - i;

        lcd.setCursor(cursorPos, cursorPos2);
        if (millis() - tanterior >= 350) {
          tanterior = millis();

          if (showChar) {
          lcd.print(Contaux);
          } 
          else {
          lcd.print(" ");
          }
          showChar = !showChar;
        }
      }
      Pasos = (Cont_1 + 10*Cont_2 + 100*Cont_3);
      
      delay(150);
      Contaux = 0;
      demora = 0;
      lcd.clear();
    }
  }

  Cont_1 = 0; Cont_2 = 0; Cont_3 = 0;
  cursorPos2 = 0;
  x1 = 0;
  a = false;
  b = false;
  mode = true;
  proceso();
}


void fn_opcion1(){
  lcd.clear();
  lcd.setCursor(4, 0);
  //lcd.print(cantidad);
  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000);
  delay(2000);
}

void fn_opcion2(){
  lcd.print("hello, world!");
  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000);
  delay(2000);
}

void Movement(){

  if (rotaryEncoder.encoderChanged()){
    valor = rotaryEncoder.readEncoder();

    while(testcero == false){
      Contauxcero = valor;
      testcero = true;
      Serial.print("entra while cero");
    }
    if(rotaryEncoder.readEncoder() == 0){
      Contauxcero = 0;
    }

      Contaux = abs(rotaryEncoder.readEncoder()) - Contauxcero;
      auxGiro = 1;

    lastvalor = rotaryEncoder.readEncoder();

    lcd.clear();

   }


  if(Contaux < 0){
    Contaux = 0;
  }
  
  /*if(Contaux > 9){
    Contaux = 9;
  }*/
}


void proceso(){

  lcd.clear();
  while(mode == true && x1 < Ciclos){
    if(digitalRead(Pulsa) == LOW){
      mode = false;
      x1 = 0;
      Pasos = 0;
      Ciclos = 0;
      x1 = 0;
      break;
    }
    lcd.setCursor(0, 0);
    lcd.print("R");
    lcd.write((byte)0);
    if(Ciclos != 4294967295){
      lcd.print(Ciclos);
    }
    else{
      lcd.print("0");
    }
    lcd.setCursor(6, 0);
    lcd.print("R");
    lcd.write((byte)1);
    lcd.print(x1);
    lcd.setCursor(12,0);
    if(Giro == true){
      lcd.print("DER");
    }
    else{
      lcd.print("IZQ");
    }
    lcd.setCursor(0, 1);
    lcd.print("t:" + String(delayciclos/1000));
    lcd.write((byte)2);
    lcd.write((byte)3);
    lcd.setCursor(6, 1);
    lcd.write((byte)4);
    if(Pasos != 4294967295){
    lcd.print(Pasos);
    }
    else{
      lcd.print("0");
    }
    lcd.print("/");
    lcd.print(x);
    lcd.setCursor(14,1);
    lcd.print("u");

    if(1 < x && x < 10){
      lcd.clear();
    }
  }
  mode = false;
}

void atrass(){

  if(digitalRead(Pulsa) == LOW){
    Pasos = 0;
    mode = false;
    menu.change_screen(1);
    menu.set_focusedLine(0);
    digitalWrite(steppin,LOW);
  }
}
A4988