mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
202 lines
7.5 KiB
C++
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);
|
|
}
|
|
|
|
}
|
|
}
|