/*
   MODDER: @RED9030
*/
/*
   TITLE: Control de Leds de manera inalambrica mediante uso de protocolo ESPNOW (RECEPTOR)
   SIMULATION: https://wokwi.com/projects/
   HARDWARE: ESP32
*/

/*
   CHARLIEPLEXING
        PIN A  PIN B  PIN C
   LED	PIN26	 PIN25  PIN14
   1	  LOW	   HIGH	  INPUT
   2	  HIGH	 LOW	  INPUT
   3	  INPUT  LOW	  HIGH
   4	  INPUT  HIGH	  LOW
   5	  LOW	   INPUT  HIGH
   6	  HIGH	 INPUT  LOW

   Pins ESP32 34,35,36,39 no output
*/
/*
 *****************************************************
      LIBRERIAS
 *****************************************************
*/
//esp8266 LIBRARIES
//#include <espnow.h>
//#include <ESP8266WiFi.h>

//esp32 LIBRARIES
#include <esp_now.h>
#include <WiFi.h>

/*
 *****************************************************
      VARIABLES
 *****************************************************
*/
const int resolution = 12;  //Cambiar resolución depende del dispositivo en esp32 son 12bits y esp8266 son 10bits
const int leds_numbers = 6; //Números de leds a colocar para multiplexar de la ecuacion #leds=#pines(#pines-1).
int valor = 0;

// Definimos los pines a utilizar
//ESP32 PINS plexing 12bits resolution
#define PIN_A 26      // Pin A 
#define PIN_B 25      // Pin B
#define PIN_C 14      // Pin C

//ESP8266 PINS plexing 10bits resolution
//const int pin_pot = A0; //Pin ADC con entrada del potenciometro ESP8266 00-A0 (lectura de analógico)
//#define PIN_A 4     // Pin A D2 
//#define PIN_B 5     // Pin B D1
//#define PIN_C 0     // Pin C D0

//ESTRUCTURA DE LOS DATOS RECIBIDOS [ESCLAVO] (RECEPTOR)
typedef struct mensaje_recibido {
  uint16_t pot = 0;
  //uint32_t tiempo = 0;
} mensaje_recibido;

// Create a struct_message called myData
mensaje_recibido myData;

/*
 *****************************************************
      INICIO
 *****************************************************
*/
//NOTA: EN ESP8266 ESP_OK ES UN VALOR DE 0

void setup() {
  // Inicialización del puerto serial
  Serial.begin(115200);

  // Colocamos el dispositivo en modo estación
  WiFi.mode(WIFI_STA);
 
  // Inicialización del protocolo ESP-NOW
  if (esp_now_init() != ESP_OK) {
      Serial.println("Error initializing ESP-NOW");
      return;
    }
  /*
  Una vez que ESPNow haya iniciado con éxito, nos registraremos 
  en recvCB para obtener información del empaquetador recv
  */
  //esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); //Asigna el rol del dispositivo (Esclavo o Maestro) (ESP8266)
  
  valor = (((pow(2,resolution)-1)/leds_numbers)+0.5); // Obtenemos el valor analogico para cada vuelta del potenciometro
  delay(200);
}


/*
 *****************************************************
      REPETICIÓN
 *****************************************************
*/
void loop() {
  esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));//Registramos los datos recibidos por el transmisor
  delay(2000);
}

/*
 *****************************************************
      FUNCIONES
 *****************************************************
*/

// Callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac,const uint8_t *incomingData, int data_len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print(". Dato potenciometro: "); 
  Serial.println(myData.pot);
  control_analogo_leds(myData.pot,valor);
}

//Función para el control de encendido analógico de los leds mediante uso del potenciometro 
void control_analogo_leds(int pot, int valor){
    //Escribo los datos sobre el pin del led
  if (pot > 0 && pot < (valor)) {
    encenderLed(1);
  } else {
    if (pot > (valor) && pot < (2 * valor)) {
      encenderLed(2);
    } else {
      if (pot > (2 * valor) && pot < (3 * valor)) {
        encenderLed(3);
      } else {
        if (pot > (3 * valor) && pot < (4 * valor)) {
          encenderLed(4);
        } else {
          if (pot > (4 * valor) && pot < (5 * valor)) {
            encenderLed(5);
          } else {
            if (pot > (5 * valor) && pot < (6 * valor)) {
              encenderLed(6);
            }
          }
        }
      }
    }
  }  
}

// Esta función se va a encargar de aplicar la lógica dependiendo del LED que queramos encender
void encenderLed(int led_num)
{
  switch (led_num)
  {
    case 1:
      ponerEstados(PIN_B, PIN_A, PIN_C);
      break;
    case 2:
      ponerEstados(PIN_A, PIN_B, PIN_C);
      break;
    case 3:
      ponerEstados(PIN_C, PIN_B, PIN_A);
      break;
    case 4:
      ponerEstados(PIN_B, PIN_C, PIN_A);
      break;
    case 5:
      ponerEstados(PIN_C, PIN_A, PIN_B);
      break;
    case 6:
      ponerEstados(PIN_A, PIN_C, PIN_B);
      break;
  }
}

// Función que pondrá en los estados correctos para encender un LED (HIGH, LOW e INPUT)
void ponerEstados(int pinHigh, int pinLow, int pinInput)
{
  pinMode(pinHigh, OUTPUT);
  digitalWrite(pinHigh, HIGH);
  pinMode(pinLow, OUTPUT);
  digitalWrite(pinLow, LOW);
  pinMode(pinInput, INPUT);
}