/*configurações bluetooth hc-05
  senha: 2570
  velocidade: 115200
  versão software: 3.0-20170601
  nome K-bot
  modo de operação: slave
*/
//Portas de comunicação bluetooth
#define Tx 3
#define Rx 2
//portas de controle de motores e acessórios
#define In1 5
#define In2 6
#define In3 9
#define In4 10
//       L  C
#define Buzina 11
#define LedF A3
#define LedB A2
//porta do ESC
#define ESC A0
//Porta de sensores
#define WSensor A1
//Bibliotecas
//#include <Servo.h>
#include "neotimer.h"
#include <ServoTimer2.h>
#include <SoftwareSerial.h>
//variáveis
int Pw = 1000;           // Valor inicial em microsegundos (mínimo)
int Max_Pw = 2000;       // Máximo para ESC (não ultrapassar 2000 µs)
int SMin = 1500;         // define o valor minimo para que o sensor desligue a serra após ligada
int Pw_Gain = 10;        // Ganho por ciclo
int Tp_Pw = 100;         // Tempo entre cada ciclo de aumento
int Sv_Pw = 0;           // Define se a serra está ou não ligada
byte DY = 0;
boolean Ats = false;
char Crct = "";
int estadoLed[] = {LOW, LOW};
/*
  Motores Dmax - Emax
  aqui será definido o quanto a velocidade
  dos motores será reduzida para que seja
  feita uma curva ao ir para frente/ré (1 - 100)
*/
byte Dmax = 100;
byte Emax = 100;
byte VMMin = 50; //define a velocidade minima do motor
byte cmm = 0;
byte Pw_Vel[] = {0, 0, 0, 0};
String Text = "";       //guarda todos os comandos recebidos pelo modulo bluetooth
int Nivel[] = {95, 95}; //guarda os valores do eixo x y
SoftwareSerial Bt(Rx, Tx);
ServoTimer2 Esc;
//Servo Esc;
Neotimer Delay0 = Neotimer(Tp_Pw);
Neotimer Delay1 = Neotimer(2000); // Tempo para rearmar ESC
Neotimer Delay2 = Neotimer(200); // tempo de resposta do comando
Neotimer Delay3 = Neotimer(10);
//---------------------------------------------------------------------------------------------------//
bool isValidCommand(String cmd) {
  cmd.trim();
  // Comandos simples: W, A, S, D
  if (cmd == "W" || cmd == "A" || cmd == "S" || cmd == "D") return true;
  // Comandos numéricos com letra final (ex: 123X, 255Y)
  if (cmd.length() >= 2 && cmd.length() <= 5) {
    char lastChar = cmd.charAt(cmd.length() - 1);
    if (lastChar == 'X' || lastChar == 'Y') {
      String numberPart = cmd.substring(0, cmd.length() - 1);
      int val = numberPart.toInt();
      if (val >= 0 && val <= 180) return true;
    }
  }
  return false;
}
//---------------------------------------------------------------------------------------------------//
void setup() {
  Esc.attach(ESC);
  Serial.begin(115200);
  Serial.println("Iniciando monitor");
  Bt.begin(115200);
  // Arming ESC: enviar sinal mínimo e aguardar
  //Esc.writeMicroseconds(1000);
  Esc.write(1000);
  delay(2000);  // Espera o ESC armar (pode ouvir os bipes do motor)
  pinMode(In1, OUTPUT);
  pinMode(In2, OUTPUT);
  pinMode(In3, OUTPUT);
  pinMode(In4, OUTPUT);
  pinMode(WSensor, INPUT);
}
void loop() {
  Mc();
  Bluetooth();
  if (Ats == true) { //verifica se a serra foi ativada
    DY = 1; //guarda 1 em DY para pular o tempo de espera do Delay1
    Serra(); //chama a função de trabalho da serra
  } else {
    //Esc.writeMicroseconds(1000); //desluga o motor da serra
    Esc.write(1000); //desliga o motor da serra
    DY = 0;
    Pw = 1000; //reseta o aumenta de velocidade da serra
    Delay1.repeatReset(); //reseta o tempo de segurança para ligar a serra
  }
}
void Serra() {
  // Esc.writeMicroseconds(Pw); //envia o valor de Pw para aumentar a velocidade da serra
  Esc.write(Pw); //envia o valor de Pw para aumentar a velocidade da serra
  if (Delay1.repeat(1)) { //tempo de segurança para reativamento da serra
    DY = 1;
  }
  if (Pw <= Max_Pw && DY == 1) { //aumenta gradativamente a velocidade da serra caso DY seja 1.
    if (Delay0.repeat()) {
      Pw = Pw + Pw_Gain;
      if (Pw >= Max_Pw) {
        Pw = Max_Pw;
        DY = 0;
      }
    }
  }
  if (digitalRead(WSensor) == HIGH) { //verifica se o sensor está ativo
    if (Pw >= SMin) { //desliga a serra caso a mesma esteja em uma velocidade média apos o ativamento do sensor
      Pw = 1000;
      DY = 0;
      Esc.write(Pw);
      Delay1.repeatReset();
    }
  }
}
/*void Bluetooth() {
  
   if (Bt.available()) {
    char c = Bt.read();
    // Filtro de caracteres ASCII válidos (evita bytes corrompidos)
    if (c >= 32 && c <= 126) {
      if (c == '\n' || c == '\r') {
        if (isValidCommand(Text)) {
          Serial.print("Comando válido: ");
          Serial.println(Text);
          // Aqui você executaria a lógica do comando
          if (Crct == 'X') { //verifica qual é o valor de X
        Serial.println(Text);
        Nivel[0] = Text.toInt(); //Converte o texto em um valor numérico "180X" -> 180 e guarda em Nivel[0]
        Text = "";
      }
      if (Text == 'Y') { //verifica qual é o valor de Y
        Serial.println(Text);
        Nivel[1] = Text.toInt(); //Converte o texto em um valor numérico "180Y" -> 180 e guarda em Nivel[1]
        Text = "";
      }
      if (Text == 'D') { //Comando que ativa a buzina (Prioridade)
        Serial.println(Text);
        tone(Buzina, 391); //liga a buzina
        Text = "";
      } 
  if (Delay2.repeat()) {      
      if (Text == 'S') { //comando que liga ou desliga as luzes traseiras
        if (cmm == 0) {
          Serial.println(Text);
          estadoLed[0] = !estadoLed[0];
          digitalWrite(LedB, estadoLed[0]); //inverte o estado anterior de saida da porta
          cmm = 1; //altera o valor de cmm para o comando não se repetir caso o botão esteja pressionado
        }
        Text = "";
      } else if (Text == 'W') { //Comando que liga ou desliga as luzes dianteiras
        if (cmm == 0) {
          Serial.println(Text);
          estadoLed[1] = !estadoLed[1];
          digitalWrite(LedF, estadoLed[1]); //inverte o estado anterior de saida da porta
          cmm = 1; //altera o valor de cmm para o comando não se repetir caso o botão esteja pressionado
        }
        Text = "";
      } else if (Text == 'A' ) { //comando que liga ou desliga a serra
        if (cmm == 0) {
          Ats = !Ats;
          cmm = 1;
        }
        Text = "";
      } else {
        noTone(Buzina); //desliga a buzina
        cmm = 0;
      }
        } else {
          Serial.print("Comando inválido: ");
          Serial.println(Text);
        }
        Text = ""; // Reset do buffer
      } else {
        Text += c;
      }
      // Limite de segurança para evitar buffer overflow
      if (Text.length() > 10) {
        Text = "";
      }
    } else {
      // Ignora caracteres não imprimíveis (possível corrupção)
    }
  }
   }
  /*if (Bt.available()) { //verifica se algum comando foi recebido (Recebe primeiro um valor numerico e em seguida uma letra)
    Crct = Bt.read(); //guarda um caractere lido en Crct
    Text += Crct; //Junta todos os caracteres recebidos e guarda na String Text
      if (Crct == 'X') { //verifica qual é o valor de X
        Serial.println(Text);
        Nivel[0] = Text.toInt(); //Converte o texto em um valor numérico "180X" -> 180 e guarda em Nivel[0]
        Text = "";
      }
      if (Crct == 'Y') { //verifica qual é o valor de Y
        Serial.println(Text);
        Nivel[1] = Text.toInt(); //Converte o texto em um valor numérico "180Y" -> 180 e guarda em Nivel[1]
        Text = "";
      }
      if (Crct == 'D') { //Comando que ativa a buzina (Prioridade)
        Serial.println(Text);
        tone(Buzina, 391); //liga a buzina
        Text = "";
      } 
  if (Delay2.repeat()) {      
      if (Crct == 'S') { //comando que liga ou desliga as luzes traseiras
        if (cmm == 0) {
          Serial.println(Text);
          estadoLed[0] = !estadoLed[0];
          digitalWrite(LedB, estadoLed[0]); //inverte o estado anterior de saida da porta
          cmm = 1; //altera o valor de cmm para o comando não se repetir caso o botão esteja pressionado
        }
        Text = "";
      } else if (Crct == 'W') { //Comando que liga ou desliga as luzes dianteiras
        if (cmm == 0) {
          Serial.println(Text);
          estadoLed[1] = !estadoLed[1];
          digitalWrite(LedF, estadoLed[1]); //inverte o estado anterior de saida da porta
          cmm = 1; //altera o valor de cmm para o comando não se repetir caso o botão esteja pressionado
        }
        Text = "";
      } else if (Crct == 'A' ) { //comando que liga ou desliga a serra
        if (cmm == 0) {
          Ats = !Ats;
          cmm = 1;
        }
        Text = "";
      } else {
        noTone(Buzina); //desliga a buzina
        cmm = 0;
      }
    }
  }
}*/
void Bluetooth() {
  while (Bt.available()) {
    Crct = Bt.read();
    // Filtro de caracteres ASCII válidos (evita ruído)
    if (Crct >= 32 && Crct <= 126) {
      Text += Crct;
      // Se recebeu um comando direto (1 caractere), já trata
      if (Text == "W" || Text == "A" || Text == "S" || Text == "D") {
        Serial.print("Comando direto: ");
        Serial.println(Text);
        if (Text == "D") tone(Buzina, 391);
        else if (Text == "S") {
          if (cmm == 0) {
            estadoLed[0] = !estadoLed[0];
            digitalWrite(LedB, estadoLed[0]);
            cmm = 1;
          }
        }
        else if (Text == "W") {
          if (cmm == 0) {
            estadoLed[1] = !estadoLed[1];
            digitalWrite(LedF, estadoLed[1]);
            cmm = 1;
          }
        }
        else if (Text == "A") {
          if (cmm == 0) {
            Ats = !Ats;
            cmm = 1;
          }
        }
        Text = "";
      }
      // Comandos com final 'X' ou 'Y' (ex: 120X, 80Y)
      if (Text.endsWith("X") || Text.endsWith("Y")) {
        char eixo = Text.charAt(Text.length() - 1);
        String valorStr = Text.substring(0, Text.length() - 1);
        int valor = valorStr.toInt();
        if (valor >= 0 && valor <= 180) {
          if (eixo == 'X') {
            Nivel[0] = valor;
            Serial.print("Eixo X: ");
            Serial.println(valor);
          } else {
            Nivel[1] = valor;
            Serial.print("Eixo Y: ");
            Serial.println(valor);
          }
        } else {
          Serial.print("Valor inválido: ");
          Serial.println(Text);
        }
        Text = "";
      }
      // Limita o buffer para não acumular lixo
      if (Text.length() > 6) Text = "";
    }
  }
  // Zera cmm se nenhum botão estiver pressionado (evita travamento)
  if (!Bt.available()) {
    cmm = 0;
    noTone(Buzina);
  }
}
void Mc() {
  /* Função de movimento dos motores
     contorle por potenciometro de 0 a 180
     Nivel[] recebe os valores e guarda em (X, Y).
     X define a direção e o quanto o robô conseguirar virar para tal direção
     Y Define a velocidade e se o robô deverá seguir para frente ou para Tras
     110 - 180X define a Esquerda
        80 - 0X define a Direita
     110 - 180Y faz ir para Frente
        80 - 0Y faz ir para Tras
     90 - 100X/Y centro - nada acontece
  */
  if (Nivel[1] >= 150 && Nivel[0] >= 150) { //frente + esquerda
    //motor direito
    analogWrite(In1, 0); //define o quanto a velocidade aumenta para ir para frente
    analogWrite(In2, 0);
    //motor esquerdo
    analogWrite(In3, 255);
    analogWrite(In4, 0);
  } else if (Nivel[1] >= 150 && Nivel[0] <= 60) { //frente + direita
    //motor direito
    analogWrite(In1, 255);
    analogWrite(In2, 0);
    //motor esquerdo
    analogWrite(In3, 0); //define o quanto a velocidade aumenta para ir para frente
    analogWrite(In4, 0);
  } else if (Nivel[1] <= 60 && Nivel[0] >= 150) { //ré + esquerda
    //motor direito
    analogWrite(In2, 255); //define o quanto a velocidade aumenta para ir para tras
    analogWrite(In1, 0);
    //motor esquerdo
    analogWrite(In4, 100);
    analogWrite(In3, 0);
  } else if (Nivel[1] <= 60 && Nivel[0] <= 60) { //ré + direita
    //motor direito
    analogWrite(In2, 100);
    analogWrite(In1, 0);
    //motor esquerdo
    analogWrite(In4, 255); //define o quanto a velocidade aumenta para ir para tras
    analogWrite(In3, 0);
  } else if (Nivel[1] >= 150) { //frente
    //motor direito
    analogWrite(In1, 255);
    analogWrite(In2, 0);
    //motor esquerdo
    analogWrite(In3, 255);
    analogWrite(In4, 0);
  } else if (Nivel[1] <= 60) { //ré
    //motor direito
    analogWrite(In1, 0);
    analogWrite(In2, 255);
    //motor esquerdo
    analogWrite(In3, 0);
    analogWrite(In4, 255);
  } else if (Nivel[0] >= 150) { //esquerda
    //motor direito
    analogWrite(In1, 255);
    analogWrite(In2, 0);
    //motor esquerdo
    analogWrite(In3, 0);
    analogWrite(In4, 255);
  } else if (Nivel[0] <= 60) { //direita
    //motor direito
    analogWrite(In1, 0);
    analogWrite(In2, 255);
    //motor esquerdo
    analogWrite(In3, 255);
    analogWrite(In4, 0);
  } else {
    //motor direito
    analogWrite(In2, 0);
    analogWrite(In1, 0);
    //motor esquerdo
    analogWrite(In4, 0);
    analogWrite(In3, 0);
  }
}