/*
  Pong is a two-dimensional sports game that simulates table tennis.
  by Anderson Costa with ❤ for the Wokwi community
  Visit https://wokwi.com to learn about the Wokwi Simulator
*/


// https://sourceforge.net/p/arduino-tvout/wiki/FDcomplete/
//
// https://real2electronics.blogspot.com/2010/11/libreria-tvout.html
//
// https://www.instructables.com/TV-Out-with-Arduino/
//
//https://sourceforge.net/p/arduino-tvout/wiki/FDcomplete/
//
//https://github.com/Avamander/arduino-tvout
//
//
#include <Wire.h>
#include <LowPower.h>
#include <TVout.h>
//#include <TVoutfonts/font4x6.h>
#include "logo.h"
#include "font4x6.h"
#include "font6x8.h"
#include "font8x8.h"
#include "font8x8ext.h"
//#include <TimerOne.h>



// Entradas Y Salidas Ultrasonico
const int Trigger = 6;   // Pin digital 6 para el Trigger del sensor
int Echo_Sensor[6] = {A0, A1, A2, A3, A4, A5};
int Lectura_Sensor[6] = {0, 0, 0, 0, 0, 0};
int nivel_min[6] = {25, 25, 25, 25, 25, 25};
int nivel_max[6] = {5, 5, 5, 5, 5, 5};
int porcentaje_nivel[6] = {0, 0, 0, 0, 0, 0};
bool alarma[6] = {false, false, false, false, false, false};

const int ancho_casilla = 40;
const int largo_casilla = 48;

// Constante velocidad sonido
const float VelSon = 34314.00;   // Velocidad sonido en cm/s
//const float VelSon = 343140.00;   // Velocidad sonido en mm/s

// Entradas menu
#define BOTON_MENU 3
#define BOTON_NEXT 4

bool Pulsacion_LargaA = false;
bool Pulsacion_CortaA = false;
bool PulsadoA = false;
bool Pulsacion_LargaB = false;
bool Pulsacion_CortaB = false;
bool PulsadoB = false;

volatile bool ModoCalib = false;
int segundos_salir = 0;
bool salir_calib = false;

unsigned long Inicio_pulsacionA = 0;
unsigned long duracionA = 0;
unsigned long Inicio_pulsacionB = 0;
unsigned long duracionB = 0;

bool a = false;
bool b = false;

#define buzzerPin 2 //buzzer name and pin 

//int Do = 262; // do
//int Re = 294; // re
//int Mi = 330; // mi
//int Fa = 349; // fa
//int Sol = 392; // sol
//int Lya = 440; // la
//int Si = 494; // si
int pitido = 1000; //
int cnt_pitido = 0;

volatile bool alarmaON = false;

bool parpadeo1 = false;
unsigned long tiempo1 = 0;

int Antirrebote = 250;

#define SCREEN_WIDTH 120
#define SCREEN_HEIGHT 96

////borrar esta variable
int ccnt_nivel = 0;
bool bajar = false;

TVout TV;

void setup() {
  TV.begin(_PAL, SCREEN_WIDTH, SCREEN_HEIGHT);

  attachInterrupt(digitalPinToInterrupt(BOTON_MENU), Despertar, FALLING);
  Serial.begin(9600);


  pinMode(BOTON_MENU, INPUT_PULLUP);
  pinMode(BOTON_NEXT, INPUT_PULLUP);

  pinMode(Trigger, OUTPUT); //pin como salida
  for (int k = 0; k <= 5; k++) {
    pinMode(Echo_Sensor[k], INPUT);
    delay(10);
  }

  digitalWrite(Trigger, LOW);//Inicializamos el pin con 0

  //Conficguracion interrupcion cada segundo Si USO TIMER 0
  //Timer1.initialize(1000000);    //Configura el TIMER en 1 Segundo
  //Timer1.attachInterrupt(Interrupcion) ; //Configura la interrupción del Timer 1

  TV.clear_screen();
  Pantalla_vacia();
  //Lectura_niveles();
  Pintar_niveles();
  delay(100);

}

void loop() {
  //Pantalla_vacia();
  //Lectura_niveles();
  Lectura_niveles2();
  //Serial.println("leer");
  Pintar_niveles();
  //Serial.println("PINTAR");
  alerta_nivel_bajo();
  sonido_alarma();

  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_ON);
  Serial.println("A MIMIR");
  delay(50);
}

void Despertar() {
  ModoCalib = true;
}


void Lectura_niveles2() {


  for (int ii = 0; ii <= 5; ii++) {
    porcentaje_nivel[ii] = ccnt_nivel;
  }
  if ((ccnt_nivel <= 100) && (bajar == false)) {
    ccnt_nivel ++;
  }
  else if ((ccnt_nivel == 100) && (bajar == false)) {
    bajar = true;
  }
  else if ((ccnt_nivel <= 100) && (bajar == true)) {
    ccnt_nivel --;
  }
  else if ((ccnt_nivel == 0) && (bajar == true)) {
    bajar = false;
  }
}


int calibracion_nivel(int indice, int x, int y, String titulo, int nivel_calib) {
  int lectura = 0;

  while ((Pulsacion_CortaB == false) && (salir_calib == false)) {

    leerbotones() ;
    if (millis() > tiempo1 + 700) {
      tiempo1 = millis();
      parpadeo1 = !parpadeo1;
      if (parpadeo1 == true) {
        TV.draw_rect(x + 1, y + 1, 38, 47, 0);
      }
      else if ((parpadeo1 == false)) {
        dibujar_tanque_vacio(x, y, ancho_casilla, largo_casilla, titulo);
        Pintar_nivel_tanque(x, y, ancho_casilla, largo_casilla, nivel_calib);
      }
    }
    lectura = Leer_Sensor(indice);
  }
  dibujar_tanque_vacio(x, y, ancho_casilla, largo_casilla, titulo);
  Pintar_nivel_tanque(x, y, ancho_casilla, largo_casilla, nivel_calib);

  delay(250);
  return lectura;

}

void leerbotones() {

  segundos_salir = 0;
  duracionA = 0;
  duracionB = 0;

  Pulsacion_LargaA = false;
  Pulsacion_CortaA = false;
  Pulsacion_LargaB = false;
  Pulsacion_CortaB = false;

  delay(5);
  a = digitalRead(BOTON_MENU); // pin donde miras la señal digital

  if ((a == LOW) && (PulsadoA == false)) { // si hay flanco 0 a 1 entonces

    Inicio_pulsacionA = millis();
    PulsadoA = true;
    //   Serial.print("Inicio_pulsacionA = ");
    // Serial.println(Inicio_pulsacionA);
  }
  if ((a == HIGH) && (PulsadoA == true)) { // si el flanco es 1 a 0, entonces detengo la cuenta
    duracionA = millis() - Inicio_pulsacionA; // en milisegundos
    // Serial.print("duracionA = ");
    // Serial.println(duracionA);
  }

  if ((duracionA >= 150) && (duracionA < 3000)) {
    Serial.println("Pulsacion Corta A");
    Pulsacion_CortaA = true;
    PulsadoA = false;
  }
  if (duracionA >= 3000) {
    Serial.println("Pulsacion Larga A");
    Pulsacion_LargaA = true;
    PulsadoA = false;
  }

  b = digitalRead(BOTON_NEXT); // pin donde miras la señal digital

  if ((b == LOW) && (PulsadoB == false)) { // si hay flanco 0 a 1 entonces

    Inicio_pulsacionB = millis();
    PulsadoB = true;
    //   Serial.print("Inicio_pulsacionB = ");
    // Serial.println(Inicio_pulsacionB);
  }
  if ((b == HIGH) && (PulsadoB == true)) { // si el flanco es 1 a 0, entonces detengo la cuenta
    duracionB = millis() - Inicio_pulsacionB; // en milisegundos
    // Serial.print("duracionB = ");
    // Serial.println(duracionB);
  }

  if ((duracionB >= 1000) && (duracionB < 2000)) {
    Serial.println("Pulsacion Corta B");
    Pulsacion_CortaB = true;
    PulsadoB = false;
  }
  if (duracionB >= 2000) {
    Serial.println("Pulsacion Larga B");
    Pulsacion_LargaB = true;
    PulsadoB = false;
  }
  delay(5);

}


void Pantalla_vacia() {
  marcos();
  dibujar_tanque_vacio(0, 0, ancho_casilla, largo_casilla, "SOL A1");
  dibujar_tanque_vacio(ancho_casilla, 0, ancho_casilla, largo_casilla, "SOL B1");
  dibujar_tanque_vacio(2 * ancho_casilla, 0, ancho_casilla, largo_casilla, "BAJ PH");
  dibujar_tanque_vacio(0, largo_casilla, ancho_casilla, largo_casilla, "SOL A2");
  dibujar_tanque_vacio(ancho_casilla, largo_casilla, ancho_casilla, largo_casilla, "SOL B2");
  dibujar_tanque_vacio(2 * ancho_casilla, largo_casilla, ancho_casilla, largo_casilla, "BAJ PH");
}

void  dibujar_tanque_vacio(int x, int y, int tam_x, int tam_y, String texto) {
  // x coordenada hotizontal,
  // y coordenada vertical
  // tam_x dimension en horizontal
  // tam_x dimension en vertical
 
  // dibujar titulo de tanque
  TV.select_font(font4x6);
  TV.set_cursor((x + 4), (y + 3));
  for (int i = 0; i < texto.length(); i++) {
    TV.print(texto.charAt(i));
  }

  //dibujar origen de recuadro
  //tft.drawLine(x, y, x, y, ILI9341_RED);
  int margen_x = 5;
  int margen_x_d = 15;
  int margen_y = 5;
  int margen_y_sup = 10;

  // dibujar lineas de tanque
  int x1 = (x + margen_x);
  int y1 = (y + margen_y_sup);

  int x2 = x1;
  int y2 = y + (tam_y - margen_y);

  int x3 = x + (tam_x - margen_x_d);
  int y3 = y2;

  int x4 = x + (tam_x - margen_x_d);
  int y4  = y1;


  TV.draw_line(x1, y1, x2, y2, 1);
  TV.draw_line(x2, y2, x3, y3, 1);
  TV.draw_line(x3, y3, x4, y4, 1);

  //  Marcas llenado
  TV.draw_line(x4, y1 + 3, x4 + 3, y1 + 3, 1); //100%
  TV.draw_line(x4, y1 + 10, x4 + 2, y1 + 10, 1); //75%
  TV.draw_line(x4, y1 + 16, x4 + 3, y1 + 16, 1); //50%
  TV.draw_line(x4, y1 + 24, x4 + 2, y1 + 24, 1); //50%
  TV.draw_line(x4, y2 - 2, x4 + 3, y2 - 2, 1); //0%
  // TEXTOS NIVEL
  TV.select_font(font4x6);
  TV.set_cursor(x4 + 4, y1);
  TV.print("F");
  TV.set_cursor(x4 + 4, y1 + 13);
  TV.print("M");
  TV.set_cursor(x4 + 4, y1 + 28);
  TV.print("V");

}

void Pintar_niveles() {
  Pintar_nivel_tanque(0, 0, ancho_casilla, largo_casilla, porcentaje_nivel[0]);
  Pintar_nivel_tanque(ancho_casilla, 0, ancho_casilla, largo_casilla,  porcentaje_nivel[1]);
  Pintar_nivel_tanque(2 * ancho_casilla, 0, ancho_casilla, largo_casilla,  porcentaje_nivel[2]);
  Pintar_nivel_tanque(0, largo_casilla, ancho_casilla, largo_casilla,  porcentaje_nivel[3]);
  Pintar_nivel_tanque(ancho_casilla, largo_casilla, ancho_casilla, largo_casilla,  porcentaje_nivel[4]);
  Pintar_nivel_tanque(2 * ancho_casilla, largo_casilla, ancho_casilla, largo_casilla,  porcentaje_nivel[5]);
}


void Lectura_niveles() {

  for (int i = 0; i <= 5; i++) {

    Lectura_Sensor[i] = Leer_Sensor(i);
    delay(5);

    // Calculo de porcenaje
    porcentaje_nivel[i] = map(Lectura_Sensor[i], nivel_min[i], nivel_max[i], 0, 100);
    delay(350);
  }
  for (int ii = 0; ii <= 5; ii++) {

    if (porcentaje_nivel[ii] >= 100) {
      porcentaje_nivel[ii] = 100;
    }
    if (porcentaje_nivel[ii] <= 0) {
      porcentaje_nivel[ii] = 0;
    }
    Serial.print(porcentaje_nivel[ii]);
    Serial.print(",");

  }
  Serial.println(" ");

}

int Leer_Sensor(int indice) {
  int muestras = 5;  // numero de muestras
  float suma = 0;
  float media = 0;

  unsigned long t = 0; //timepo que demora en llegar el eco
  float d = 0; //distancia en centimetros
  suma = 0;
  delay(5);
  for (int j = 0; j < muestras; j++) {
    digitalWrite(Trigger, LOW);
    delayMicroseconds (5);
    digitalWrite(Trigger, HIGH);
    delayMicroseconds(10);          //Enviamos un pulso de 10us
    digitalWrite(Trigger, LOW);

    t = pulseIn(Echo_Sensor[indice], HIGH); //obtenemos el ancho del pulso
    // d = t / 59;

    // Obtenemos la distancia en cm, hay que convertir el tiempo en segudos ya que está en microsegundos
    // por eso se multiplica por 0.000001
    // Si queremos precision mm/s tenemos que desmarcar la opcion VelSon en mm/s y comentar la cm/s
    d = t * 0.000001 * VelSon / 2.0;

    suma = suma + d;
    delay(70);
  }
  media = suma / muestras;

  return media;
}

void alerta_nivel_bajo() {
  // Serial.println("mirandoooo");
  for (int i = 0; i < 6; i++) {
    // Serial.print(porcentaje_nivel[i]);
    //  Serial.print(",");
    if (porcentaje_nivel[i] <= 10) {

      alarma[i] = true;
    }
    else {
      alarma[i] = false;
    }
    delay(1);
  }
  // Serial.println(" ");


  //recuento alarmas
  int n_alarma = 0;
  for (int i = 0; i < 6; i++) {
    // Serial.print(alarma[i]);
    //    Serial.print(",");
    if (alarma[i] == true) {
      n_alarma ++;
    }
    delay(1);
  }
  // Serial.println(" ");

  // comprobamos si hay alarmas
  if (n_alarma >= 1) {
    alarmaON = true;
  }
  else if (n_alarma == 0) {
    alarmaON = false;
  }
  //Serial.println(n_alarma);

  // Serial.println(alarmaON);
  //llamamos a la rutina de alarma
  //sonido_alarma();
}

void sonido_alarma() {
  // Serial.println("ENTRAMOSSSSA SONIDO ");
  // Activate the buzzer (produce sound)
  if ((alarmaON == true) && (ModoCalib == false)) {
    // Serial.println("alarma");

    for (int h = 0; h < 3; h++) {
      for (int hh = 0; hh < 3; hh++) {
        // Serial.println("PITIDO");
        tone(buzzerPin, pitido); // You can adjust the f
        delay(333);
        noTone(buzzerPin); // You can adjust the f
        delay(333);
      }
      delay(500);
    }
    alarmaON = false;
  }
}


void Pintar_nivel_tanque(int x, int y, int tam_x, int tam_y, int num) {

  int margen_x = 5;
  int margen_x_d = 15;
  int margen_y = 5;
  int margen_y_sup = 10;
  int l0 = 0;
  int l100 = tam_y - (margen_y + margen_y_sup + 5);
  int level = map(num, 0, 100, l0, l100);

  // dibujar lineas de tanque
  int x1 = (x + margen_x) + 2;
  int y1 =  y + (tam_y - margen_y) - 2;

  int x2 =  (tam_x -  (margen_x_d + margen_x)) - 4;
  int y2 = - level;

  //BORRAR ANTIGUO

  TV.draw_rect(x1, y1, x2, -l100, 0);

  //pINTAR NUEVO
  for (int h = l0; h <= level; h++) {
    TV.draw_rect(x1, y1, x2, -h, 1);
    //delay(1);
  }

}

void marcos() {

  int largo = 6;
  TV.draw_rect(0, 0, 119, 95, 1);

  TV.draw_line(0, 47, largo, 47, 1);
  TV.draw_line(119 - largo, 47, 119, 47, 1);

  TV.draw_line(39, 0, 39, largo, 1);
  TV.draw_line(39, 95 - largo, 39, 95, 1);

  TV.draw_line(79, 0, 79, largo, 1);
  TV.draw_line(79, 95 - largo, 79, 95, 1);

  TV.draw_line(39 - (largo - 4), 47,  39 + (largo - 3), 47, 1);
  TV.draw_line(39, 47 - (largo - 3),  39, 47 + (largo - 3), 1);


  TV.draw_line(79 - (largo - 4), 47,  79 + (largo - 3), 47, 1);
  TV.draw_line(79, 47 - (largo - 3),  79, 47 + (largo - 3), 1);
}
BTN MENU
BTN NEXT
SOL. B1
SOL. A2
SOL. A1
SOL B2
PH- 1
PH- 2