Battery-Emulator/Software/CHADEMO-BATTERY.cpp
2023-07-25 15:35:29 +03:00

202 lines
7.5 KiB
C++

#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);
}
}
}