diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index f9c185f7..923dc555 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -25,6 +25,9 @@ unsigned long turnOnTime; // Variables to store timestamps enum State { POWERON, STATE_ON, STATE_OFF }; static State WUPState = POWERON; +enum CmdState { SOH, CELL_VOLTAGE, SOC, CELL_VOLTAGE_AVG }; +static CmdState cmdState = SOH; + const unsigned char crc8_table[256] = { // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0, @@ -266,6 +269,45 @@ CAN_frame_t BMW_5F8 = {.FIR = {.B = .MsgID = 0x5F8, .data = {0x64, 0x01, 0x00, 0x0B, 0x92, 0x03, 0x00, 0x05}}; +CAN_frame_t BMW_6F1_CELL = {.FIR = {.B = + { + .DLC = 5, + .FF = CAN_frame_std, + }}, + .MsgID = 0x6F1, + .data = {0x07, 0x03, 0x22, 0xDD, 0xBF}}; + +CAN_frame_t BMW_6F1_SOH = {.FIR = {.B = + { + .DLC = 5, + .FF = CAN_frame_std, + }}, + .MsgID = 0x6F1, + .data = {0x07, 0x03, 0x22, 0x63, 0x35}}; + +CAN_frame_t BMW_6F1_SOC = {.FIR = {.B = + { + .DLC = 5, + .FF = CAN_frame_std, + }}, + .MsgID = 0x6F1, + .data = {0x07, 0x03, 0x22, 0xDD, 0xBC}}; + +CAN_frame_t BMW_6F1_CELL_VOLTAGE_AVG = {.FIR = {.B = + { + .DLC = 5, + .FF = CAN_frame_std, + }}, + .MsgID = 0x6F1, + .data = {0x07, 0x03, 0x22, 0xDF, 0xA0}}; + +CAN_frame_t BMW_6F1_CONTINUE = {.FIR = {.B = + { + .DLC = 4, + .FF = CAN_frame_std, + }}, + .MsgID = 0x6F1, + .data = {0x07, 0x30, 0x00, 0x02}}; //The above CAN messages need to be sent towards the battery to keep it alive static uint8_t startup_counter_contactor = 0; @@ -306,6 +348,11 @@ static uint16_t battery_prediction_voltage_longterm_charge = 0; static uint16_t battery_prediction_voltage_longterm_discharge = 0; static uint16_t battery_prediction_duration_charging_minutes = 0; static uint16_t battery_target_voltage_in_CV_mode = 0; +static uint16_t battery_soc = 0; +static uint16_t battery_soc_hvmax = 0; +static uint16_t battery_soc_hvmin = 0; +static uint16_t battery_capacity_cah = 0; + static int16_t battery_temperature_HV = 0; static int16_t battery_temperature_heat_exchanger = 0; static int16_t battery_temperature_max = 0; @@ -344,6 +391,10 @@ static uint8_t battery_status_diagnosis_powertrain_maximum_multiplexer = 0; static uint8_t battery_status_diagnosis_powertrain_immediate_multiplexer = 0; static uint8_t battery_ID2 = 0; static uint8_t battery_cellvoltage_mux = 0; +static uint8_t battery_soh = 0; + +static uint8_t message_data[50]; +static uint8_t next_data = 0; static uint8_t calculateCRC(CAN_frame_t rx_frame, uint8_t length, uint8_t initial_value) { uint8_t crc = initial_value; @@ -363,7 +414,7 @@ static uint8_t increment_alive_counter(uint8_t counter) { void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus - system_real_SOC_pptt = (battery_display_SOC * 100); //increase Display_SOC range from 0-100 -> 100.00 + system_real_SOC_pptt = (battery_HVBatt_SOC * 10); system_battery_voltage_dV = battery_volts; //Unit V+1 (5000 = 500.0V) @@ -373,16 +424,17 @@ void update_values_battery() { //This function maps all the values fetched via system_remaining_capacity_Wh = (battery_energy_content_maximum_kWh * 1000); // Convert kWh to Wh - if ((battery_max_charge_amperage * system_battery_voltage_dV) > 65000) { - system_max_charge_power_W = 65000; - } else { - system_max_charge_power_W = (battery_max_charge_amperage * system_battery_voltage_dV); - } + system_SOH_pptt = battery_soh * 100; - if ((battery_max_discharge_amperage * system_battery_voltage_dV) > 65000) { + if (battery_BEV_available_power_longterm_discharge > 65000) { system_max_discharge_power_W = 65000; } else { - system_max_discharge_power_W = (battery_max_discharge_amperage * system_battery_voltage_dV); + system_max_discharge_power_W = battery_BEV_available_power_longterm_discharge; + } + if (battery_BEV_available_power_longterm_charge > 65000) { + system_max_charge_power_W = 65000; + } else { + system_max_charge_power_W = battery_BEV_available_power_longterm_charge; } battery_power = (system_battery_current_dA * (system_battery_voltage_dV / 100)); @@ -393,6 +445,9 @@ void update_values_battery() { //This function maps all the values fetched via system_temperature_max_dC = battery_temperature_max * 10; // Add a decimal + system_cell_min_voltage_mV = system_cellvoltages_mV[0]; + system_cell_max_voltage_mV = system_cellvoltages_mV[1]; + /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/ if (!CANstillAlive) { set_event(EVENT_CAN_RX_FAILURE, 0); @@ -549,7 +604,48 @@ void receive_can_battery(CAN_frame_t rx_frame) { case 0x587: //BMS [5s] Services battery_ID2 = rx_frame.data.u8[0]; break; - case 0x607: //BMS - No use for this message + case 0x607: //BMS - responses to message requests on 0x615 + if (rx_frame.FIR.B.DLC > 6 && next_data == 0 && rx_frame.data.u8[0] == 0xf1) { + uint8_t count = 6; + while (count < rx_frame.FIR.B.DLC && next_data < 49) { + message_data[next_data++] = rx_frame.data.u8[count++]; + } + ESP32Can.CANWriteFrame(&BMW_6F1_CONTINUE); // tell battery to send additional messages + + } else if (rx_frame.FIR.B.DLC > 3 && next_data > 0 && rx_frame.data.u8[0] == 0xf1 && + ((rx_frame.data.u8[1] & 0xF0) == 0x20)) { + uint8_t count = 2; + while (count < rx_frame.FIR.B.DLC && next_data < 49) { + message_data[next_data++] = rx_frame.data.u8[count++]; + } + + switch (cmdState) { + case CELL_VOLTAGE: + if (next_data >= 4) { + system_cellvoltages_mV[0] = (message_data[0] << 8 | message_data[1]); + system_cellvoltages_mV[2] = (message_data[2] << 8 | message_data[3]); + } + break; + case CELL_VOLTAGE_AVG: + if (next_data >= 30) { + system_cellvoltages_mV[1] = (message_data[10] << 8 | message_data[11]) / 10; + battery_capacity_cah = (message_data[4] << 8 | message_data[5]); + } + break; + case SOH: + if (next_data >= 4) { + battery_soh = message_data[3]; + } + break; + case SOC: + if (next_data >= 6) { + battery_soc = (message_data[0] << 8 | message_data[1]); + battery_soc_hvmax = (message_data[2] << 8 | message_data[3]); + battery_soc_hvmin = (message_data[4] << 8 | message_data[5]); + } + break; + } + } break; default: break; @@ -699,6 +795,9 @@ void send_can_battery() { ESP32Can.CANWriteFrame(&BMW_3E4); ESP32Can.CANWriteFrame(&BMW_37B); + next_data = 0; + ESP32Can.CANWriteFrame(&BMW_6F1_CELL); + BMW_3E5.data.u8[0] = 0xFD; // First 3E5 message byte0 we send is unique, once we sent initial value send this } } diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index bfd73b39..46dc114f 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -529,6 +529,7 @@ String processor(const String& var) { } else { // > 0 content += "