/**************************************************************************/
#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <math.h>
#include <Adafruit_ADS1X15.h>
void modeCC();
void setAh();
void modeCV();
void showNewNumber();
void pC();

//////// ASIGNACION DE VARIABLES ///////////////
Adafruit_MCP4725 dac;
Adafruit_MCP4725 dac1;
Adafruit_ADS1115 ads;

float multiplier = 0.1875F;

#define LED_PIN 13
#define LED_CC 2
#define LED_CV 3
#define LED_END 4
enum State : uint8_t {
  DESCONECTADO,
  CC,
  CV,
  STOP
};
State mode = State::DESCONECTADO;

//unsigned long previousMillis = 0;  // will store last time LED was updated
const long intervalo = 1000;        // interval at which to blink (milliseconds)
unsigned long cycle_time = 0;

const byte numChars = 32;
char receivedChars[numChars];  // an array to store the received data

boolean newData = false;
int16_t adc0;
int dataNumber = 0;  // new for this version

float Vb;
uint32_t Output, Output1, chag1, chag2;
float Diferencia, Ah, setpoint, setpointOutput, Vsense, Vsen, Ibatt, Ibattm, Vbattm, Vbat, error, paso, Vbatt = 0;
int bandCC = 0;
boolean bandINICIO = false;

//    counter = a1 + b1*Iout + c1*Iout^2 + d1*Iout^3 + e1*Iout^4

float a1 = -2.52038889494;
float b1 = 7.73919458332125;
float c1 = -5.329353665626146E-03;
float d1 = 5.063958804605470E-05;
float e1 = -1.482742475253906E-07;

//    counter = a2 + b2*Vbatt + c2*Vbatt^2 + d2*Vbatt^3 + e2*Vbatt^4

float a2 = -2.900715447070478E+02;
float b2 = 1.494749132002313E+00;
float c2 = -4.514553954116232E-04;
float d2 = 1.194080149869407E-07;
float e2 = -1.069615000397186E-11;

//***********************************************************************************************
//*************************************** SETUP *************************************************
//***********************************************************************************************
void setup(void) {
  pinMode(LED_CC, OUTPUT);
  digitalWrite(LED_CC, LOW);
  pinMode(LED_CV, OUTPUT);
  digitalWrite(LED_CV, LOW);
  pinMode(LED_END, OUTPUT);
  digitalWrite(LED_END, LOW);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  Serial.begin(9600);       //Start a serial session
  Serial.println("Begin");  // Hello World!

  // For MCP4725A1 the address is 0x62 or 0x63
  // For MCP4725A0 the address is 0x60 or 0x61
  // For MCP4725A2 the address is 0x64 or 0x65
  // Set the ADC ADS1015
  // Descomentar el que interese
  ads.setGain(GAIN_TWOTHIRDS);  //+/- 6.144V/32768 -  1 bit = 0.1875mV (default) CV
  // ads1.setGain(GAIN_ONE);        //+/- 4.096V/32768 -  1 bit = 0.125mV        CC
  // ads.setGain(GAIN_TWO);        //+/- 2.048V/32768 -  1 bit = 0.0625mV
  // ads.setGain(GAIN_FOUR);          //+/- 1.024V/32768 -  1 bit = 0.03125mV = multiplier
  // ads.setGain(GAIN_EIGHT);      //+/- 0.512V/32768 -  1 bit = 0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    //+/- 0.256V/32768 -  1 bit = 0.0078125mV

  ads.begin((0x48));
  dac.begin(0x60);
  dac1.begin(0x61);

  Output = 0;
  setpoint = 0;
  mode = DESCONECTADO;
  analogReference(DEFAULT);
  while (Serial.available() > 0) {  // limpia el buffer
    Serial.read();
  }
}  // setup()
//***********************************************************************************************
//*************************************** LOOP  *************************************************
//***********************************************************************************************
void loop() {
  if (millis() > cycle_time) {
    cycle_time = millis() + intervalo;
    pC();                                   // calculate Vbattm, Vsense, Ibattm
    Serial.print(" mode = ");
    Serial.println((mode == 0) ? "DESCONECTADO" : (mode == 1) ? "CC"
                   : (mode == 2) ? "CV"
                   : "STOP");
    float limite = 0.08 * Ah; // hay que declarar las variables fuera del switch case, otherwise se friza
    switch (mode) {
      case State::DESCONECTADO:  //////////////////////////////////////////////////////////////////////////////////////
        digitalWrite(LED_CC, LOW);
        digitalWrite(LED_CV, LOW);
        digitalWrite(LED_END, LOW);
        if ((bandINICIO == false) && (Vbattm > 300)) {//  transition to CC
          mode = CC;
          bandINICIO = true;
          showNewNumber();
        }
        break;
      case State::CC:  //////////////////////////////////////////////////////////////////////////////////////////////////
        if (Vbattm > 4100) {// transition to CV
          setpoint = 4670;
          setAh();
          mode = CV;
        }
        if ((Vbattm > 6000)) {//                          transition to DESCONECTADO
          mode = DESCONECTADO;
        } else {
          modeCC();
          Output1 = 0;
        }
        bandINICIO = false;
        break;
      case State::CV:  /////////////////////////////////////////////////////////////////////////////////////////////////
        modeCV();
        if (Ibattm < limite) {//                          transition to STOP
          mode = STOP;
        } else if (Vbattm > 6000) {//                     transition to DESCONECTADO
          mode = DESCONECTADO;
        }
        break;
      case State::STOP:  //////////////////////////////////////////////////////////////////////////////////////////////
        digitalWrite(LED_CC, LOW);
        digitalWrite(LED_CV, LOW);
        digitalWrite(LED_END, HIGH);
        Output1 = 0;
        Output = 0;
        if ((Vbattm < 400) || (Vbattm > 6000))  //        transition to DESCONECTADO
        {
          mode = DESCONECTADO;
        }
        break;
      default:
        Serial.print(" Wrong case ");
        break;
    }// switch (mode)
  }// if(millis() > cycle_time)
}  // loop()
