
#include <Nextion.h>
#include <Adafruit_ADS1X15.h>
#include "Wire.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include <MCP492X.h>  



Adafruit_ADS1115 ads;  //Use this for the 16-bit version ADC
#define ONE_WIRE_BUS 12
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);



#define PIN_SPI_CHIP_SELECT_DAC A3  

MCP492X myDac(PIN_SPI_CHIP_SELECT_DAC);

#define CFG1 A0
#define CFG2 A1
#define CFG3 A2

#define FANpwm 10
#define Mode 2
#define ENprotection 9


#define Button1 8
#define Button2 7
#define Button3 6
#define Button4 5

// SDA = A4
// SCL = A5
// CS = A3
// temp1 = 12
//******************************************* varibles ********************************

uint32_t number;
uint32_t temperature1 = 3;
uint32_t power = 0;
uint32_t voltage = 30;
uint32_t current = 1;
uint32_t resistance = 0;
uint32_t xxx;
float LastEnergy;
float DischEnergy = 0.0;
float Dischcap = 0.0;

int16_t adc0, adc1, adc2, adc3;
float volts0, volts1, volts2, volts3;

unsigned long TimerNow = 0;
unsigned long TimerDisplay = 0;  
unsigned long TimerTemp = 0;     
unsigned long TimerADC = 0;     


uint32_t Ssetpoint = 0;
uint32_t PSetpoint = 0;
uint32_t batCutoff = 0;
uint32_t FanPWM = 22;

enum OperationModes {
  ConstCurrent,    
  ConstPower,       
  ConstResistance, 
  CurrentPulse,    
  Battery,          
  none,            
};

OperationModes OpMode = ConstCurrent;


//******************************************* nextion define object ********************************

//******** CC mode
NexButton Wset = NexButton(0, 5, "b1");  // Button added [page id:0,component id:1, component name: "t0"].
NexButton Rset = NexButton(0, 6, "b2");
NexButton Aset = NexButton(0, 7, "b3");
NexButton Bset = NexButton(0, 8, "b4");
NexButton USB5 = NexButton(0, 9, "b5");
NexButton USB12 = NexButton(0, 10, "b6");
NexButton USB15 = NexButton(0, 11, "b7");
NexButton USB20 = NexButton(0, 12, "b8");
NexButton onoff = NexButton(0, 13, "b9");
NexButton start = NexButton(2, 10, "b0");
NexButton stopp = NexButton(2, 14, "b2");
NexButton onoff1 = NexButton(2, 13, "b1");

NexNumber Sset = NexNumber(0, 7, "n7");

NexNumber BAset = NexNumber(2, 8, "n0");
NexNumber BVset = NexNumber(2, 9, "n1");

NexPage page0 = NexPage(0, 0, "page0");  
NexPage page1 = NexPage(1, 0, "page1");
NexPage page2 = NexPage(2, 0, "page2");


char buffer[100] = { 0 };  // This is needed only if you are going to receive a text from the display. You can remove it otherwise.
// Further on this sketch I do receive text so that's why I created this buffer.

NexTouch *nex_listen_list[] = {
  &Wset,
  &Rset,
  &Aset,
  &Bset,
  &USB5,
  &USB12,
  &USB15,
  &USB20,
  &onoff,
  &onoff1,
  &start,
  &stopp,
  &page0,  // Page added as a touch event
  &page1,  // Page added as a touch event
  &page2,  // Page added as a touch event

  NULL  // String terminated
};      // End of touch event list



//***************************************** nextion void ***************************

void WsetPushCallback(void *ptr) 
{
  Sset.getValue(&Ssetpoint);

  Serial.print("b1.picc=0");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b2.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b3.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b4.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  digitalWrite(4, LOW);
  OpMode = ConstPower;
}

void RsetPushCallback(void *ptr)  
{

  Sset.getValue(&Ssetpoint);

  Serial.print("b1.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b2.picc=0");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b3.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b4.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  digitalWrite(4, HIGH);

  float dsc = (5838.9 * pow(Ssetpoint, -0.973));

  Ssetpoint = dsc;

  //((0.5*4096)/0.8333)/
  myDac.analogWrite(Ssetpoint);
  OpMode = ConstResistance;
}
void AsetPushCallback(void *ptr)  
{

  Sset.getValue(&Ssetpoint);

  Serial.print("b1.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b2.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b3.picc=0");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b4.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  digitalWrite(4, LOW);
  float dsc = 405.31 * (Ssetpoint / 1000.00) + 9.0961;
  Ssetpoint = dsc;
  myDac.analogWrite(Ssetpoint);

  OpMode = ConstCurrent;
}
void BsetPushCallback(void *ptr)  
{
}
void USB5PushCallback(void *ptr) {
  Serial.print("b5.picc=0");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b6.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b7.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b8.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  digitalWrite(CFG1, LOW);
  digitalWrite(CFG2, HIGH);
  digitalWrite(CFG3, HIGH);
}
void USB12PushCallback(void *ptr) {
  Serial.print("b5.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b6.picc=0");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b7.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b8.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  digitalWrite(CFG1, HIGH);
  digitalWrite(CFG2, HIGH);
  digitalWrite(CFG3, LOW);
}
void USB15PushCallback(void *ptr) {
  Serial.print("b5.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b6.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b7.picc=0");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b8.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  digitalWrite(CFG1, HIGH);
  digitalWrite(CFG2, LOW);
  digitalWrite(CFG3, LOW);

  digitalWrite(Mode, LOW);  //relay HIGH=ON
}
void USB20PushCallback(void *ptr) {
  Serial.print("b5.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b6.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b7.picc=1");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.print("b8.picc=0");
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);

  digitalWrite(CFG1, HIGH);
  digitalWrite(CFG2, LOW);
  digitalWrite(CFG3, HIGH);
}
void onoffPushCallback(void *ptr)  
{
  Ssetpoint = 0;
  DischEnergy = 0;
  Dischcap = 0;
  myDac.analogWrite(0);
  OpMode = none;
}
void onoff1PushCallback(void *ptr) 
{
  Ssetpoint = 0;
  DischEnergy = 0;
  Dischcap = 0;
  myDac.analogWrite(0);
  OpMode = none;
}
void startPushCallback(void *ptr)  
{
  BAset.getValue(&Ssetpoint);
  digitalWrite(4, LOW);
  float dsc = 405.31 * (Ssetpoint / 1000.00) + 9.0961;
  Ssetpoint = dsc;
  myDac.analogWrite(Ssetpoint);

  BVset.getValue(&batCutoff);
  OpMode = Battery;
}
void stoppPushCallback(void *ptr)  
{

  myDac.analogWrite(0);

  OpMode = Battery;
}
void page0PushCallback(void *ptr) {
  //OpMode = none;
}
void page1PushCallback(void *ptr) {
  //OpMode = none;
}
void page2PushCallback(void *ptr) {
  //OpMode = none;
}


void setup() {
  sensors.begin();  // Start up the library
  sensors.setResolution(9);

  myDac.begin();
  myDac.analogWrite(0);

  pinMode(4, OUTPUT);
  digitalWrite(4, LOW);

  //ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
  ads.setGain(GAIN_ONE);  // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
  if (!ads.begin()) {
    Serial.println("Failed to initialize ADS.");
    while (1)
      ;
  }


  nexInit();

  Wset.attachPush(WsetPushCallback);
  Rset.attachPush(RsetPushCallback);
  Aset.attachPush(AsetPushCallback);
  Bset.attachPush(BsetPushCallback);
  USB5.attachPush(USB5PushCallback);
  USB12.attachPush(USB12PushCallback);
  USB15.attachPush(USB15PushCallback);
  USB20.attachPush(USB20PushCallback);
  onoff.attachPush(onoffPushCallback);
  onoff1.attachPush(onoff1PushCallback);
  start.attachPush(startPushCallback);
  stopp.attachPush(stoppPushCallback);


  page0.attachPush(page0PushCallback);
  page1.attachPush(page1PushCallback);
  page2.attachPush(page2PushCallback);

  Serial.begin(9600);

  Serial.println("Electronic load");

  delay(500);
  Serial.write(0xff);  // We always have to send this three lines after each command sent to nextion.
  Serial.write(0xff);
  Serial.write(0xff);

  pinMode(Mode, OUTPUT);
  pinMode(FANpwm, OUTPUT);
  pinMode(ENprotection, OUTPUT);
  pinMode(CFG1, OUTPUT);
  pinMode(CFG2, OUTPUT);
  pinMode(CFG3, OUTPUT);

  analogWrite(FANpwm, 0);    // fan
  digitalWrite(Mode, HIGH);  //relay HIGH=ON


  digitalWrite(CFG1, HIGH);
  digitalWrite(CFG2, LOW);
  digitalWrite(CFG3, LOW);
}

void loop() {

  nexLoop(nex_listen_list);

  TimerNow = millis();              
  if (TimerNow - TimerADC >= 200) {  
    TimerADC = TimerNow;
    adc0 = ads.readADC_SingleEnded(0);  // voltage sense
    adc1 = ads.readADC_SingleEnded(1);  // voltage USB C
    adc2 = ads.readADC_SingleEnded(2);  // voltage cap
    adc3 = ads.readADC_SingleEnded(3);  // current

    volts0 = (ads.computeVolts(adc0) * 1.27) * 6;
    volts1 = (ads.computeVolts(adc1) * 7.666);
    volts2 = (ads.computeVolts(adc2) * 7.666);
    volts3 = (ads.computeVolts(adc3) * 1.27) * 2;

    if (OpMode == ConstPower) {

      float dsc = (405.31 * (Ssetpoint / volts0)) + 9.0961;
      PSetpoint = dsc;
      myDac.analogWrite(PSetpoint);
    }
    if (OpMode == Battery) {
      if ((volts0 * 1000) < batCutoff) {
        Ssetpoint = 0;
        myDac.analogWrite(0);
      }
    }
  }
  TimerNow = millis();                                                     
  if (TimerNow - TimerDisplay >= 550) {                                   
    LastEnergy = (volts0 * volts3) * (TimerNow - TimerDisplay) / 3600000;  
    DischEnergy = DischEnergy + LastEnergy;
    LastEnergy = (volts3) * (TimerNow - TimerDisplay) / 3600000;  
    Dischcap = Dischcap + LastEnergy;
    TimerDisplay = TimerNow;
    displayUpdate();
  }
  TimerNow = millis();                 // actual timer tick
  if (TimerNow - TimerTemp >= 2000) {  // display routine every 150ms
    TimerTemp = TimerNow;
    sensors.setWaitForConversion(false);  // makes it async
    sensors.requestTemperatures();
    sensors.setWaitForConversion(true);
    temperature1 = sensors.getTempCByIndex(0);


    if (temperature1 > 30) {
      if (temperature1 > 40) {
        analogWrite(11, 255);
        FanPWM = 255;
      } else {
        analogWrite(11, 150);
        FanPWM = 150;
      }
    } else {
      analogWrite(11, 0);
      FanPWM = 0;
    }
  }
}

void displayUpdate() {

  switch (OpMode) {
    case ConstCurrent:

      xxx = volts3 * 1000;

      Serial.print("x0.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * 1000;

      Serial.print("x1.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * volts3 * 1000;

      Serial.print("x2.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);
      xxx = DischEnergy * 1000;
      Serial.print("x3.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = Dischcap * 1000;
      Serial.print("x4.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n5.val=");
      Serial.print(FanPWM);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n6.val=");
      Serial.print(temperature1);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);
      break;
    case ConstPower:

      xxx = volts3 * 1000;
      Serial.print("x0.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * 1000;
      Serial.print("x1.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * volts3 * 1000;
      Serial.print("x2.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = DischEnergy * 1000;
      Serial.print("x3.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = Dischcap * 1000;
      Serial.print("x4.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n5.val=");
      Serial.print(FanPWM);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n6.val=");
      Serial.print(temperature1);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      break;
    case ConstResistance:
      xxx = volts3 * 1000;
      Serial.print("x0.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * 1000;
      Serial.print("x1.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * volts3 * 1000;
      Serial.print("x2.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = DischEnergy * 1000;
      Serial.print("x3.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = Dischcap * 1000;
      Serial.print("x4.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n5.val=");
      Serial.print(FanPWM);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n6.val=");
      Serial.print(temperature1);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);
      break;

    case none:


      xxx = volts3 * 1000;
      Serial.print("x0.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * 1000;
      Serial.print("x1.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * volts3 * 1000;
      Serial.print("x2.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = DischEnergy * 1000;
      Serial.print("x3.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = Dischcap * 1000;
      Serial.print("x4.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n5.val=");
      Serial.print(FanPWM);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n6.val=");
      Serial.print(temperature1);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);
      break;

    case Battery:
      xxx = volts3 * 1000;
      Serial.print("x0.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * 1000;
      Serial.print("x1.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = volts0 * volts3 * 1000;
      Serial.print("x2.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = DischEnergy * 1000;
      Serial.print("x3.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      xxx = Dischcap * 1000;
      Serial.print("x4.val=");
      Serial.print(xxx);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n5.val=");
      Serial.print(FanPWM);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);

      Serial.print("n6.val=");
      Serial.print(temperature1);
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff);
      break;

    default:

      break;
      break;
  }
}
