#include "CHADEMO-BATTERY.h"
#include "ESP32CAN.h"
#include "CAN_config.h"

/* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
static const int interval100 = 100; // interval (ms) at which send CAN Messages
const int rx_queue_size = 10; // Receive Queue size
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive 
static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic

CAN_frame_t CHADEMO_108 = {.FIR = {.B = {.DLC = 8,.FF = CAN_frame_std,}},.MsgID = 0x108,.data = {0x01, 0xF4, 0x01, 0x0F, 0xB3, 0x01, 0x00, 0x00}};
CAN_frame_t CHADEMO_109 = {.FIR = {.B = {.DLC = 8,.FF = CAN_frame_std,}},.MsgID = 0x109,.data = {0x02, 0x00, 0x00, 0x00, 0x01, 0x20, 0xFF, 0xFF}};
//For chademo v2.0 only
CAN_frame_t CHADEMO_118 = {.FIR = {.B = {.DLC = 8,.FF = CAN_frame_std,}},.MsgID = 0x118,.data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}};
CAN_frame_t CHADEMO_208 = {.FIR = {.B = {.DLC = 8,.FF = CAN_frame_std,}},.MsgID = 0x208,.data = {0xFF, 0xF4, 0x01, 0xF0, 0x00, 0x00, 0xFA, 0x00}};
CAN_frame_t CHADEMO_209 = {.FIR = {.B = {.DLC = 8,.FF = CAN_frame_std,}},.MsgID = 0x209,.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};

//H100
uint8_t MinimumChargeCurrent = 0;
uint16_t MinumumBatteryVoltage = 0;
uint16_t MaximumBatteryVoltage = 0;
uint8_t ConstantOfChargingRateIndication = 0;
//H101
uint8_t MaxChargingTime10sBit = 0;
uint8_t MaxChargingTime1minBit = 0;
uint8_t EstimatedChargingTime = 0;
uint16_t RatedBatteryCapacity = 0;
//H102
uint8_t ControlProtocolNumberEV = 0;
uint16_t TargetBatteryVoltage = 0;
uint8_t ChargingCurrentRequest = 0;
uint8_t FaultBatteryVoltageDeviation = 0;
uint8_t FaultHighBatteryTemperature = 0;
uint8_t FaultBatteryCurrentDeviation = 0;
uint8_t FaultBatteryUndervoltage = 0;
uint8_t FaultBatteryOvervoltage = 0;
uint8_t StatusNormalStopRequest = 0;
uint8_t StatusVehicle = 0;
uint8_t StatusChargingSystem = 0;
uint8_t StatusVehicleShifterPosition = 0;
uint8_t StatusVehicleCharging = 0;
uint8_t ChargingRate = 0;
//H200
uint8_t MaximumDischargeCurrent = 0;
uint16_t MinimumDischargeVoltage = 0;
uint8_t MinimumBatteryDischargeLevel = 0;
uint8_t MaxRemainingCapacityForCharging = 0;
//H201
uint8_t V2HchargeDischargeSequenceNum = 0;
uint16_t ApproxDischargeCompletionTime = 0;
uint16_t AvailableVehicleEnergy = 0;
//H700
uint8_t AutomakerCode = 0;
uint32_t OptionalContent = 0;
//H118
uint8_t DynamicControlStatus = 0;
uint8_t HighCurrentControlStatus = 0;
uint8_t HighVoltageControlStatus = 0;


void update_values_chademo_battery()
{ //This function maps all the values fetched via CAN to the correct parameters used for the inverter
  bms_status = ACTIVE; //Startout in active mode
  
  SOC = ChargingRate;

  max_target_discharge_power = (MaximumDischargeCurrent*MaximumBatteryVoltage); //In Watts, Convert A to P

  battery_voltage = TargetBatteryVoltage; //Todo, scaling?

	capacity_Wh = ((RatedBatteryCapacity/0.11)*1000); //(Added in CHAdeMO v1.0.1), maybe handle hardcoded on lower protocol version?

	remaining_capacity_Wh = (SOC/100)*capacity_Wh;

  /* Check if the Vehicle is still sending CAN messages. If we go 60s without messages we raise an error*/
  if(!CANstillAlive)
  {
    bms_status = FAULT;
    errorCode = 7;
    Serial.println("No CAN communication detected for 60s. Shutting down battery control.");
  }
  else
  {
    CANstillAlive--;
  }

  if(printValues)
  {  //values heading towards the modbus registers
    if(errorCode > 0)
      {
        Serial.print("ERROR CODE ACTIVE IN SYSTEM. NUMBER: ");
        Serial.println(errorCode);
      }
    Serial.print("BMS Status (3=OK): ");
    Serial.println(bms_status);
    switch (bms_char_dis_status)
			{
      case 0:
        Serial.println("Battery Idle");
        break;
      case 1:
        Serial.println("Battery Discharging");
        break;
      case 2:
        Serial.println("Battery Charging");
        break;
      default:
        break;
      }
    Serial.print("Max discharge power: ");
    Serial.println(max_target_discharge_power);
    Serial.print("Max charge power: ");
    Serial.println(max_target_charge_power);
    Serial.print("SOH%: ");
    Serial.println(StateOfHealth);
    Serial.print("SOC% to Inverter: ");
    Serial.println(SOC);
    Serial.print("Temperature Min: ");
    Serial.println(temperature_min);
    Serial.print("Temperature Max: ");
    Serial.println(temperature_max);
  }
}

void receive_can_chademo_battery(CAN_frame_t rx_frame)
{
  CANstillAlive == 12; //We are getting CAN messages from the vehicle, inform the watchdog

  switch (rx_frame.MsgID)
  {
  case 0x100:
    MinimumChargeCurrent = rx_frame.data.u8[0];
    MinumumBatteryVoltage = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
    MaximumBatteryVoltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
    ConstantOfChargingRateIndication = rx_frame.data.u8[6];
    break;
  case 0x101:
    MaxChargingTime10sBit = rx_frame.data.u8[1];
    MaxChargingTime1minBit = rx_frame.data.u8[2];
    EstimatedChargingTime = rx_frame.data.u8[3];
    RatedBatteryCapacity = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]);
    break;
  case 0x102:
    ControlProtocolNumberEV = rx_frame.data.u8[0];
    TargetBatteryVoltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
    ChargingCurrentRequest = rx_frame.data.u8[3];
    FaultBatteryOvervoltage = (rx_frame.data.u8[4] & 0x01);
    FaultBatteryUndervoltage = (rx_frame.data.u8[4] & 0x02) >> 1;
    FaultBatteryCurrentDeviation = (rx_frame.data.u8[4] & 0x04) >> 2;
    FaultHighBatteryTemperature = (rx_frame.data.u8[4] & 0x08) >> 3;
    FaultBatteryVoltageDeviation =  (rx_frame.data.u8[4] & 0x10) >> 4;
    StatusVehicleCharging = (rx_frame.data.u8[5] & 0x01);
    StatusVehicleShifterPosition = (rx_frame.data.u8[5] & 0x02) >> 1;
    StatusChargingSystem = (rx_frame.data.u8[5] & 0x04) >> 2;
    StatusVehicle = (rx_frame.data.u8[5] & 0x08) >> 3;
    StatusNormalStopRequest =  (rx_frame.data.u8[5] & 0x10) >> 4;
    ChargingRate = rx_frame.data.u8[6];
    break;
  case 0x200: //For V2X
    MaximumDischargeCurrent = rx_frame.data.u8[0];
    MinimumDischargeVoltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
    MinimumBatteryDischargeLevel = rx_frame.data.u8[6];
    MaxRemainingCapacityForCharging = rx_frame.data.u8[7];
    break;
  case 0x201: //For V2X
    V2HchargeDischargeSequenceNum = rx_frame.data.u8[0];
    ApproxDischargeCompletionTime = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
    AvailableVehicleEnergy = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
    break;
  case 0x700:
    AutomakerCode = rx_frame.data.u8[0];
    OptionalContent = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); //Actually more bytes, but not needed for our purpose
    break;
  case 0x110: //Only present on Chademo v2.0
    DynamicControlStatus = (rx_frame.data.u8[0] & 0x01);
    HighCurrentControlStatus = (rx_frame.data.u8[0] & 0x02) >> 1;
    HighVoltageControlStatus = (rx_frame.data.u8[0] & 0x04) >> 2;
  default:
    break;
  }      
}
void send_can_chademo_battery()
{
  unsigned long currentMillis = millis();
	// Send 100ms CAN Message
	if (currentMillis - previousMillis100 >= interval100)
	{
		previousMillis100 = currentMillis;

		ESP32Can.CANWriteFrame(&CHADEMO_108); 
    ESP32Can.CANWriteFrame(&CHADEMO_109);
    ESP32Can.CANWriteFrame(&CHADEMO_208);
    ESP32Can.CANWriteFrame(&CHADEMO_209);
    
    if(ControlProtocolNumberEV >= 0x03)
    { //Only send the following on Chademo 2.0 vehicles?
      ESP32Can.CANWriteFrame(&CHADEMO_118);
    }

	}
}
