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

// Control de llibreries

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

#include <ArduinoJson.h>

#include <esp_now.h>

#include "WiFi.h"

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>


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

// Control de variables

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

double meACTIU;

double mdACTIU;

double m3ACTIU;

boolean b_override;

StaticJsonDocument<1500> json_data;

char json_temp_data[1500];

DeserializationError json_error;

//uint8_t espnow_peerMAC[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

String espnow_rx_data="";

String espnow_rx_mac="";

esp_err_t espnow_send_result;

esp_now_peer_info_t espnow_peerInfo;

QueueHandle_t espnow_thread_rx_queue;

typedef struct T_espnow_thread_queue_data{ char *data; char *mac;};

T_espnow_thread_queue_data *espnow_thread_queue_data;

bool espnow_encrypted=false;

static const char* ESPNOW_PMK_KEY_STR = "";

static const char* ESPNOW_LMK_KEY_STR  = "";

Adafruit_SSD1306 oled_1(128,64, &Wire,-1);

bool oled_1_autoshow=true;


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

// Control de funcions

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


String fnc_json_get_key_text(String _f){

  if(json_error)return "";

  JsonVariant t=json_data[_f];

  if( t.is<JsonObject>() || t.is<JsonArray>() || t.is<JsonObjectConst>() || t.is<JsonArrayConst>() ){

      serializeJson(t, json_temp_data);

      return String(json_temp_data);

  }

  return String(t.as<const char*>());

}


double fnc_json_get_key_number(String _f){

  if(json_error)return sqrt(-1);

  JsonVariant t=json_data[_f];

  if( (!t.is<double>()) && (!t.is<int>()) ){

      return 0;

  }

  return (double)(t.as<double>());

}


boolean fnc_json_get_key_bool(String _f){

  if(json_error)return false;

  JsonVariant t=json_data[_f];

  if(!t.is<boolean>() ){

      return 0;

  }

  return (boolean)(t.as<boolean>());

}


double fnc_json_get_array_size(String _f){

  if(json_error)return 0;

  if(_f=="")return json_data.size();

  JsonArray t=json_data[_f];

  if(t){

      return t.size();

  }

  return 0;

}


String  fnc_json_get_index_text(int _i){

  if(json_error)return "";

  JsonVariant t=json_data[_i];

  if( t.is<JsonObject>() || t.is<JsonArray>() || t.is<JsonObjectConst>() || t.is<JsonArrayConst>() ){

      serializeJson(t, json_temp_data);

      return String(json_temp_data);

  }

  return String(t.as<const char*>());

}


double fnc_json_get_index_number(int _i){

  if(json_error)return sqrt(-1);

  JsonVariant t=json_data[_i];

  if( (!t.is<double>()) && (!t.is<int>()) ){

      return sqrt(-1);

  }

  return (double)(t.as<double>());

}


boolean fnc_json_get_index_bool(int _i){

  if(json_error)return false;

  JsonVariant t=json_data[_i];

  if( !t.is<boolean>() ){

      return false;

  }

  return (boolean)(t.as<boolean>());

}


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

// Modul de conecció

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

void espnow_on_data_received() {


  json_error = deserializeJson(json_data,String((espnow_rx_data)).c_str());

  if ((!json_error)) {

    meACTIU = fnc_json_get_key_number(String("me"));

    mdACTIU = fnc_json_get_key_number(String("md"));

    m3ACTIU = fnc_json_get_key_number(String("m3"));

  }



}


void espnow_task_queue_rx(void *parameter){


  for(;;){

      T_espnow_thread_queue_data *rxData;

      xQueueReceive(espnow_thread_rx_queue, &rxData, portMAX_DELAY);


    espnow_rx_data=String(rxData->data);

    espnow_rx_mac=String(rxData->mac);


    espnow_on_data_received();


    free(rxData->data);

    free(rxData->mac);

  }

}


void espnow_data_rx(const uint8_t * _mac, const uint8_t *_incomingData, int _len) {


  //remote MAC

  espnow_rx_mac="";

    for (byte i = 0; i < 6; ++i)

    {

      char buf[3];

      sprintf(buf, "%2X", _mac[i]);

      espnow_rx_mac += buf;

      if (i < 5) espnow_rx_mac += ':';

    }


  //payload DATA

  char* buff = (char*) _incomingData;

    buff[_len]=NULL;


  //data packet to rx queue

    espnow_thread_queue_data=(T_espnow_thread_queue_data*) malloc(sizeof(T_espnow_thread_queue_data*));

    espnow_thread_queue_data->data = (char*) malloc(_len+1);

    espnow_thread_queue_data->mac = (char*) malloc(espnow_rx_mac.length()+1);

    strcpy(espnow_thread_queue_data->data, buff);

    strcpy(espnow_thread_queue_data->mac, espnow_rx_mac.c_str());

  xQueueSendToBack(espnow_thread_rx_queue, &espnow_thread_queue_data, portMAX_DELAY);

}

void stop_motors() {

  analogWrite(16,(uint16_t)(0));

  analogWrite(17,(uint16_t)(0));

  digitalWrite(12, LOW);

  digitalWrite(13, LOW);

  digitalWrite(18, LOW);

  digitalWrite(19, LOW);

  digitalWrite(14, LOW);

  digitalWrite(27, LOW);

}


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

// Preparació abans d'iniciar

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


void setup()

{

    pinMode(18, OUTPUT);

  pinMode(19, OUTPUT);

  pinMode(16, OUTPUT);

  pinMode(13, OUTPUT);

  pinMode(12, OUTPUT);

  pinMode(17, OUTPUT);

  pinMode(14, OUTPUT);

  pinMode(27, OUTPUT);



  WiFi.mode(WIFI_STA);


  if (esp_now_init() != ESP_OK){

    delay(1000);

    ESP.restart();

  }


  espnow_thread_rx_queue = xQueueCreate(4, sizeof(T_espnow_thread_queue_data*));

  xTaskCreatePinnedToCore(espnow_task_queue_rx,"T_espnow_rx",2048,NULL,10,NULL,1);

  esp_now_register_recv_cb(esp_now_recv_cb_t(espnow_data_rx));

  oled_1.begin(SSD1306_SWITCHCAPVCC,0x3C);

  oled_1.clearDisplay();

  if(oled_1_autoshow)oled_1.display();

  oled_1.setTextSize(2);

  oled_1.setTextColor(WHITE);

  oled_1.setCursor(0,0);

  oled_1.print(String("MAC"));

  if(oled_1_autoshow)oled_1.display();

  oled_1.setTextSize(1);

  oled_1.setTextColor(WHITE);

  oled_1.setCursor(0,30);

  oled_1.print(WiFi.macAddress());

  if(oled_1_autoshow)oled_1.display();

  b_override = true;

  stop_motors();


}


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

// Bucle Principal

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


void loop()

{

  yield();


    if ((meACTIU > 0)) {

      digitalWrite(18, HIGH);

      digitalWrite(19, LOW);

      analogWrite(16,(uint16_t)(((abs(meACTIU) * 2))));

    }

    else if ((meACTIU < 0)) {

      digitalWrite(18, LOW);

      digitalWrite(19, HIGH);

      analogWrite(16,(uint16_t)(((abs(meACTIU) * 2))));

    }

    else if ((meACTIU == 0)) {

      analogWrite(16,(uint16_t)(0));

    }


    if ((mdACTIU > 0)) {

      digitalWrite(13, HIGH);

      digitalWrite(12, LOW);

      analogWrite(17,(uint16_t)(((abs(mdACTIU) * 2))));

    }

    else if ((mdACTIU < 0)) {

      digitalWrite(13, LOW);

      digitalWrite(12, HIGH);

      analogWrite(17,(uint16_t)(((abs(mdACTIU) * 2))));

    }

    else if ((mdACTIU == 0)) {

      analogWrite(17,(uint16_t)(0));

    }


    if ((m3ACTIU > 0)) {

      digitalWrite(14, LOW);

      digitalWrite(27, HIGH);

    }

    else if ((m3ACTIU < 0)) {

      digitalWrite(14, HIGH);

      digitalWrite(27, LOW);

    }

    else {

      digitalWrite(14, LOW);

      digitalWrite(27, LOW);

    }


}