From 702149f38820b16a18055b2e0e06a61e9b73c0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 9 Jun 2025 22:00:31 +0300 Subject: [PATCH 01/14] Add event for SMA pairing event to aid troubleshooting --- Software/src/devboard/utils/events.cpp | 3 +++ Software/src/devboard/utils/events.h | 1 + Software/src/inverter/SMA-BYD-H-CAN.cpp | 2 ++ Software/src/inverter/SMA-BYD-H-CAN.h | 1 + Software/src/inverter/SMA-BYD-HVS-CAN.cpp | 2 ++ Software/src/inverter/SMA-BYD-HVS-CAN.h | 1 + Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 5 +++++ Software/src/inverter/SMA-TRIPOWER-CAN.h | 1 + 8 files changed, 16 insertions(+) diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 0f3c68e7..6ea94c3f 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -101,6 +101,7 @@ void init_events(void) { events.entries[EVENT_SERIAL_RX_FAILURE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_SERIAL_TX_FAILURE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_SERIAL_TRANSMITTER_FAILURE].level = EVENT_LEVEL_ERROR; + events.entries[EVENT_SMA_PAIRING].level = EVENT_LEVEL_INFO; events.entries[EVENT_RESET_UNKNOWN].level = EVENT_LEVEL_INFO; events.entries[EVENT_RESET_POWERON].level = EVENT_LEVEL_INFO; events.entries[EVENT_RESET_EXT].level = EVENT_LEVEL_INFO; @@ -305,6 +306,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) { return "Error in serial function: No ACK from receiver!"; case EVENT_SERIAL_TRANSMITTER_FAILURE: return "Error in serial function: Some ERROR level fault in transmitter, received by receiver"; + case EVENT_SMA_PAIRING: + return "SMA inverter trying to pair, contactors will close and open according to Enable line"; case EVENT_OTA_UPDATE: return "OTA update started!"; case EVENT_OTA_UPDATE_TIMEOUT: diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index ecff3118..c6b6ddc9 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -74,6 +74,7 @@ XX(EVENT_SERIAL_RX_FAILURE) \ XX(EVENT_SERIAL_TX_FAILURE) \ XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \ + XX(EVENT_SMA_PAIRING) \ XX(EVENT_TASK_OVERRUN) \ XX(EVENT_RESET_UNKNOWN) \ XX(EVENT_RESET_POWERON) \ diff --git a/Software/src/inverter/SMA-BYD-H-CAN.cpp b/Software/src/inverter/SMA-BYD-H-CAN.cpp index 7754a4a7..a0b5d2ba 100644 --- a/Software/src/inverter/SMA-BYD-H-CAN.cpp +++ b/Software/src/inverter/SMA-BYD-H-CAN.cpp @@ -216,6 +216,8 @@ void SmaBydHInverter::map_can_frame_to_variable(CAN_frame rx_frame) { #ifdef DEBUG_LOG logging.println("Received 0x5E7: SMA pairing request"); #endif // DEBUG_LOG + pairing_events++; + set_event(EVENT_SMA_PAIRING, pairing_events); datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; transmit_can_init(); break; diff --git a/Software/src/inverter/SMA-BYD-H-CAN.h b/Software/src/inverter/SMA-BYD-H-CAN.h index fc1e7fb2..eee66893 100644 --- a/Software/src/inverter/SMA-BYD-H-CAN.h +++ b/Software/src/inverter/SMA-BYD-H-CAN.h @@ -24,6 +24,7 @@ class SmaBydHInverter : public CanInverterProtocol { unsigned long previousMillis100ms = 0; + uint8_t pairing_events = 0; uint32_t inverter_time = 0; uint16_t inverter_voltage = 0; int16_t inverter_current = 0; diff --git a/Software/src/inverter/SMA-BYD-HVS-CAN.cpp b/Software/src/inverter/SMA-BYD-HVS-CAN.cpp index 1975b3ff..a14fbb42 100644 --- a/Software/src/inverter/SMA-BYD-HVS-CAN.cpp +++ b/Software/src/inverter/SMA-BYD-HVS-CAN.cpp @@ -206,6 +206,8 @@ void SmaBydHvsInverter::map_can_frame_to_variable(CAN_frame rx_frame) { #ifdef DEBUG_LOG logging.println("Received 0x5E7: SMA pairing request"); #endif // DEBUG_LOG + pairing_events++; + set_event(EVENT_SMA_PAIRING, pairing_events); datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; transmit_can_init = true; break; diff --git a/Software/src/inverter/SMA-BYD-HVS-CAN.h b/Software/src/inverter/SMA-BYD-HVS-CAN.h index 2604b1ad..00494a0a 100644 --- a/Software/src/inverter/SMA-BYD-HVS-CAN.h +++ b/Software/src/inverter/SMA-BYD-HVS-CAN.h @@ -28,6 +28,7 @@ class SmaBydHvsInverter : public CanInverterProtocol { 7; //TODO, tweak to as low as possible before performance issues/crashes appear bool transmit_can_init = false; + uint8_t pairing_events = 0; uint32_t inverter_time = 0; uint16_t inverter_voltage = 0; int16_t inverter_current = 0; diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index e7d8ac6e..7e031f63 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -100,6 +100,11 @@ void SmaTripowerInverter::map_can_frame_to_variable(CAN_frame rx_frame) { //Inverter brand (frame1-3 = 0x53 0x4D 0x41) = SMA break; case 0x660: //Message originating from SMA inverter - Pairing request +#ifdef DEBUG_LOG + logging.println("Received 0x660: SMA pairing request"); +#endif // DEBUG_LOG + pairing_events++; + set_event(EVENT_SMA_PAIRING, pairing_events); datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; transmit_can_init(); break; diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index 4e6bb80c..0fbd22a9 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -42,6 +42,7 @@ class SmaTripowerInverter : public CanInverterProtocol { uint32_t inverter_time = 0; uint16_t inverter_voltage = 0; int16_t inverter_current = 0; + uint8_t pairing_events = 0; bool pairing_completed = false; int16_t temperature_average = 0; uint16_t ampere_hours_remaining = 0; From 5d7023f463f78284db41cc6b15d82878e181d8c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 10 Jun 2025 10:12:51 +0300 Subject: [PATCH 02/14] Add more sanity checking for cellvoltages --- Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 60e95b83..0bf2368d 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -114,8 +114,9 @@ void KiaHyundai64Battery:: void KiaHyundai64Battery::update_number_of_cells() { //If we have cell values and number_of_cells not initialized yet if (cellvoltages_mv[0] > 0 && datalayer_battery->info.number_of_cells == 0) { - // Check if we have 98S or 90S battery - if (datalayer_battery->status.cell_voltages_mV[97] > 0) { + // Check if we have 98S or 90S battery. If the 98th cell is valid range, we are on a 98S battery + if ((datalayer_battery->status.cell_voltages_mV[97] > 2000) && + (datalayer_battery->status.cell_voltages_mV[97] < 4300)) { datalayer_battery->info.number_of_cells = 98; datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_98S_DV; From 779c53a5ac44943343246366d60e4e164d1b4b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 10 Jun 2025 22:36:10 +0300 Subject: [PATCH 03/14] Update Software.ino --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index 0f0f8203..1941f8b8 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -50,7 +50,7 @@ volatile unsigned long long bmsResetTimeOffset = 0; // The current software version, shown on webserver -const char* version_number = "8.14.dev"; +const char* version_number = "8.14.0"; // Interval timers volatile unsigned long currentMillis = 0; From 27ca07c6bbdb243a79df2e4a5cda17a749b06cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 10 Jun 2025 23:42:50 +0300 Subject: [PATCH 04/14] Update Software.ino --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index 1941f8b8..e1870b1d 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -50,7 +50,7 @@ volatile unsigned long long bmsResetTimeOffset = 0; // The current software version, shown on webserver -const char* version_number = "8.14.0"; +const char* version_number = "8.15.dev"; // Interval timers volatile unsigned long currentMillis = 0; From f44091997f2310a5af8acc71d03127d540a10fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 12 Jun 2025 12:55:31 +0300 Subject: [PATCH 05/14] Improvement: ECMP contactor closing (#1177) * Add contactor closing and diagnostic commands --- Software/src/battery/Battery.h | 4 + Software/src/battery/ECMP-BATTERY.cpp | 1240 ++++++++++++++++- Software/src/battery/ECMP-BATTERY.h | 399 +++++- Software/src/battery/ECMP-HTML.h | 362 ++++- Software/src/datalayer/datalayer_extended.h | 72 + .../webserver/advanced_battery_html.cpp | 10 + Software/src/devboard/webserver/webserver.cpp | 7 +- 7 files changed, 2051 insertions(+), 43 deletions(-) diff --git a/Software/src/battery/Battery.h b/Software/src/battery/Battery.h index 0611ef92..0c0b3b40 100644 --- a/Software/src/battery/Battery.h +++ b/Software/src/battery/Battery.h @@ -26,14 +26,17 @@ class Battery { virtual bool supports_reset_SOH() { return false; } virtual bool supports_reset_BECM() { return false; } virtual bool supports_contactor_close() { return false; } + virtual bool supports_contactor_reset() { return false; } virtual bool supports_set_fake_voltage() { return false; } virtual bool supports_manual_balancing() { return false; } virtual bool supports_real_BMS_status() { return false; } virtual bool supports_toggle_SOC_method() { return false; } + virtual bool supports_factory_mode_method() { return false; } virtual void clear_isolation() {} virtual void reset_BMS() {} virtual void reset_crash() {} + virtual void reset_contactor() {} virtual void reset_NVROL() {} virtual void reset_DTC() {} virtual void read_DTC() {} @@ -42,6 +45,7 @@ class Battery { virtual void request_open_contactors() {} virtual void request_close_contactors() {} virtual void toggle_SOC_method() {} + virtual void set_factory_mode() {} virtual void set_fake_voltage(float v) {} virtual float get_voltage() { return static_cast(datalayer.battery.status.voltage_dV) / 10.0; } diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index e1f1d9ec..dbab7c0f 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -8,9 +8,8 @@ /* TODO: This integration is still ongoing. Here is what still needs to be done in order to use this battery type -- Figure out contactor closing - - Which CAN messages need to be sent towards the battery? -- Handle 54/70kWh cellcounting properly +- Disable the isolation resistance requirement that opens contactors after 30s +- Battery says it might need 37E and 485, but no logs of this? */ /* Do not change code below unless you are sure what you are doing */ @@ -58,6 +57,87 @@ void EcmpBattery::update_values() { // Update extended datalayer (More Battery Info page) datalayer_extended.stellantisECMP.MainConnectorState = battery_MainConnectorState; datalayer_extended.stellantisECMP.InsulationResistance = battery_insulationResistanceKOhm; + datalayer_extended.stellantisECMP.InsulationDiag = battery_insulation_failure_diag; + datalayer_extended.stellantisECMP.InterlockOpen = battery_InterlockOpen; + datalayer_extended.stellantisECMP.pid_welding_detection = pid_welding_detection; + datalayer_extended.stellantisECMP.pid_reason_open = pid_reason_open; + datalayer_extended.stellantisECMP.pid_contactor_status = pid_contactor_status; + datalayer_extended.stellantisECMP.pid_negative_contactor_control = pid_negative_contactor_control; + datalayer_extended.stellantisECMP.pid_negative_contactor_status = pid_negative_contactor_status; + datalayer_extended.stellantisECMP.pid_positive_contactor_control = pid_positive_contactor_control; + datalayer_extended.stellantisECMP.pid_positive_contactor_status = pid_positive_contactor_status; + datalayer_extended.stellantisECMP.pid_contactor_negative = pid_contactor_negative; + datalayer_extended.stellantisECMP.pid_contactor_positive = pid_contactor_positive; + datalayer_extended.stellantisECMP.pid_precharge_relay_control = pid_precharge_relay_control; + datalayer_extended.stellantisECMP.pid_precharge_relay_status = pid_precharge_relay_status; + datalayer_extended.stellantisECMP.pid_recharge_status = pid_recharge_status; + datalayer_extended.stellantisECMP.pid_delta_temperature = pid_delta_temperature; + datalayer_extended.stellantisECMP.pid_coldest_module = pid_coldest_module; + datalayer_extended.stellantisECMP.pid_lowest_temperature = pid_lowest_temperature; + datalayer_extended.stellantisECMP.pid_average_temperature = pid_average_temperature; + datalayer_extended.stellantisECMP.pid_highest_temperature = pid_highest_temperature; + datalayer_extended.stellantisECMP.pid_hottest_module = pid_hottest_module; + datalayer_extended.stellantisECMP.pid_avg_cell_voltage = pid_avg_cell_voltage; + datalayer_extended.stellantisECMP.pid_current = pid_current; + datalayer_extended.stellantisECMP.pid_insulation_res_neg = pid_insulation_res_neg; + datalayer_extended.stellantisECMP.pid_insulation_res_pos = pid_insulation_res_pos; + datalayer_extended.stellantisECMP.pid_max_current_10s = pid_max_current_10s; + datalayer_extended.stellantisECMP.pid_max_discharge_10s = pid_max_discharge_10s; + datalayer_extended.stellantisECMP.pid_max_discharge_30s = pid_max_discharge_30s; + datalayer_extended.stellantisECMP.pid_max_charge_10s = pid_max_charge_10s; + datalayer_extended.stellantisECMP.pid_max_charge_30s = pid_max_charge_30s; + datalayer_extended.stellantisECMP.pid_energy_capacity = pid_energy_capacity; + datalayer_extended.stellantisECMP.pid_highest_cell_voltage_num = pid_highest_cell_voltage_num; + datalayer_extended.stellantisECMP.pid_lowest_cell_voltage_num = pid_lowest_cell_voltage_num; + datalayer_extended.stellantisECMP.pid_sum_of_cells = pid_sum_of_cells; + datalayer_extended.stellantisECMP.pid_cell_min_capacity = pid_cell_min_capacity; + datalayer_extended.stellantisECMP.pid_cell_voltage_measurement_status = pid_cell_voltage_measurement_status; + datalayer_extended.stellantisECMP.pid_insulation_res = pid_insulation_res; + datalayer_extended.stellantisECMP.pid_pack_voltage = pid_pack_voltage; + datalayer_extended.stellantisECMP.pid_high_cell_voltage = pid_high_cell_voltage; + datalayer_extended.stellantisECMP.pid_low_cell_voltage = pid_low_cell_voltage; + datalayer_extended.stellantisECMP.pid_battery_energy = pid_battery_energy; + datalayer_extended.stellantisECMP.pid_crash_counter = pid_crash_counter; + datalayer_extended.stellantisECMP.pid_wire_crash = pid_wire_crash; + datalayer_extended.stellantisECMP.pid_CAN_crash = pid_CAN_crash; + datalayer_extended.stellantisECMP.pid_history_data = pid_history_data; + datalayer_extended.stellantisECMP.pid_lowsoc_counter = pid_lowsoc_counter; + datalayer_extended.stellantisECMP.pid_last_can_failure_detail = pid_last_can_failure_detail; + datalayer_extended.stellantisECMP.pid_hw_version_num = pid_hw_version_num; + datalayer_extended.stellantisECMP.pid_sw_version_num = pid_sw_version_num; + datalayer_extended.stellantisECMP.pid_factory_mode_control = pid_factory_mode_control; + memcpy(datalayer_extended.stellantisECMP.pid_battery_serial, pid_battery_serial, sizeof(pid_battery_serial)); + uint8_t pid_battery_serial[13] = {0}; + datalayer_extended.stellantisECMP.pid_aux_fuse_state = pid_aux_fuse_state; + datalayer_extended.stellantisECMP.pid_battery_state = pid_battery_state; + datalayer_extended.stellantisECMP.pid_precharge_short_circuit = pid_precharge_short_circuit; + datalayer_extended.stellantisECMP.pid_eservice_plug_state = pid_eservice_plug_state; + datalayer_extended.stellantisECMP.pid_mainfuse_state = pid_mainfuse_state; + datalayer_extended.stellantisECMP.pid_most_critical_fault = pid_most_critical_fault; + datalayer_extended.stellantisECMP.pid_current_time = pid_current_time; + datalayer_extended.stellantisECMP.pid_time_sent_by_car = pid_time_sent_by_car; + datalayer_extended.stellantisECMP.pid_12v = pid_12v; + datalayer_extended.stellantisECMP.pid_12v_abnormal = pid_12v_abnormal; + datalayer_extended.stellantisECMP.pid_hvil_in_voltage = pid_hvil_in_voltage; + datalayer_extended.stellantisECMP.pid_hvil_out_voltage = pid_hvil_out_voltage; + datalayer_extended.stellantisECMP.pid_hvil_state = pid_hvil_state; + datalayer_extended.stellantisECMP.pid_bms_state = pid_bms_state; + datalayer_extended.stellantisECMP.pid_vehicle_speed = pid_vehicle_speed; + datalayer_extended.stellantisECMP.pid_time_spent_over_55c = pid_time_spent_over_55c; + datalayer_extended.stellantisECMP.pid_contactor_closing_counter = pid_contactor_closing_counter; + datalayer_extended.stellantisECMP.pid_date_of_manufacture = pid_date_of_manufacture; + + if (battery_InterlockOpen) { + set_event(EVENT_HVIL_FAILURE, 0); + } else { + clear_event(EVENT_HVIL_FAILURE); + } + + if (pid_12v < 11000) { + set_event(EVENT_12V_LOW, 11); + } else { + clear_event(EVENT_12V_LOW); + } } void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { @@ -66,14 +146,11 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { case 0x125: //Common battery_soc = (rx_frame.data.u8[0] << 2) | (rx_frame.data.u8[1] >> 6); // Byte1, bit 7 length 10 (0x3FE when abnormal) (0-1000 ppt) - battery_MainConnectorState = ((rx_frame.data.u8[2] & 0x30) >> - 4); //Byte2 , bit 4, length 2 ((00 contactors open, 01 precharged, 11 invalid)) + battery_MainConnectorState = ((rx_frame.data.u8[2] & 0x18) >> + 3); //Byte2 , bit 4, length 2 ((00 contactors open, 01 precharged, 11 invalid)) battery_voltage = (rx_frame.data.u8[3] << 1) | (rx_frame.data.u8[4] >> 7); //Byte 4, bit 7, length 9 (0x1FE if invalid) - battery_current = (((rx_frame.data.u8[4] & 0x7F) << 5) | (rx_frame.data.u8[5] >> 3)) - - 600; // Byte5, Bit 3 length 12 (0xFFE when abnormal) (-600 to 600 , offset -600) - //battery_RelayOpenRequest = // Byte 5, bit 6, length 1 (0 no request, 1 battery requests contactor opening) - //Stellantis doc seems wrong, could Byte5 be misspelled as Byte2? Bit will otherwise collide with battery_current + battery_current = (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[5]) - 600; // TODO: Test break; case 0x127: //DFM specific battery_AllowedMaxChargeCurrent = @@ -86,6 +163,8 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { case 0x129: //PSA specific break; case 0x31B: + battery_InterlockOpen = ((rx_frame.data.u8[1] & 0x10) >> 4); //Best guess, seems to work? + //TODO: frame7 contains checksum, we can use this to check for CAN message corruption break; case 0x358: //Common battery_highestTemperature = rx_frame.data.u8[6] - 40; @@ -93,7 +172,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { break; case 0x359: break; - case 0x361: + case 0x361: //BMS6_361 , removed on batteries newer than 5/7/2022 break; case 0x362: break; @@ -102,6 +181,9 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { case 0x494: break; case 0x594: + battery_insulation_failure_diag = ((rx_frame.data.u8[6] & 0xE0) >> 5); //Unsure if this is right position + //byte pos 6, bit pos 7, signal lenth 3 + //0 = no failure, 1 = symmetric failure, 4 = invalid value , forbidden value 5-7 break; case 0x6D0: //Common battery_insulationResistanceKOhm = @@ -287,36 +369,1150 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages[107] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages, 108 * sizeof(uint16_t)); break; - case 0x794: - break; - default: - break; + case 0x694: // Poll reply + + // Handle user requested functionality first if ongoing + if (datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring) { + if ((rx_frame.data.u8[0] == 0x06) && (rx_frame.data.u8[1] == 0x50) && (rx_frame.data.u8[2] == 0x03)) { + //06,50,03,00,C8,00,14,00, + DisableIsoMonitoringStatemachine = 2; //Send ECMP_FACTORY_MODE_ACTIVATION next loop + } + //if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F) && (rx_frame.data.u8[2] == 0x2E)) { + if (DisableIsoMonitoringStatemachine == 3) { + DisableIsoMonitoringStatemachine = 4; + } + //if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F) && (rx_frame.data.u8[2] == 0x2E)) { + if (DisableIsoMonitoringStatemachine == 5) { + DisableIsoMonitoringStatemachine = 6; + } + //if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F) && (rx_frame.data.u8[2] == 0x31)) { + if (DisableIsoMonitoringStatemachine == 7) { + //UNKNOWN? 03,7F,31,24 (or 7F?) + DisableIsoMonitoringStatemachine = COMPLETED_STATE; + datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring = false; + timeSpentDisableIsoMonitoring = COMPLETED_STATE; + } + + } else if (datalayer_extended.stellantisECMP.UserRequestContactorReset) { + if ((rx_frame.data.u8[0] == 0x06) && (rx_frame.data.u8[1] == 0x50) && (rx_frame.data.u8[2] == 0x03)) { + //06,50,03,00,C8,00,14,00, + ContactorResetStatemachine = 2; //Send ECMP_CONTACTOR_RESET_START next loop + } + if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x71) && (rx_frame.data.u8[2] == 0x01)) { + //05,71,01,DD,35,01,00,00, + ContactorResetStatemachine = 4; //Send ECMP_CONTACTOR_RESET_PROGRESS next loop + } + if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x71) && (rx_frame.data.u8[2] == 0x03)) { + //05,71,03,DD,35,02,00,00, + ContactorResetStatemachine = COMPLETED_STATE; + datalayer_extended.stellantisECMP.UserRequestContactorReset = false; + timeSpentContactorReset = COMPLETED_STATE; + } + + } else if (datalayer_extended.stellantisECMP.UserRequestCollisionReset) { + if ((rx_frame.data.u8[0] == 0x06) && (rx_frame.data.u8[1] == 0x50) && (rx_frame.data.u8[2] == 0x03)) { + //06,50,03,00,C8,00,14,00, + CollisionResetStatemachine = 2; //Send ECMP_COLLISION_RESET_START next loop + } + if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x71) && (rx_frame.data.u8[2] == 0x01)) { + //05,71,01,DF,60,01,00,00, + CollisionResetStatemachine = 4; //Send ECMP_COLLISION_RESET_PROGRESS next loop + } + if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x71) && (rx_frame.data.u8[2] == 0x03)) { + if (rx_frame.data.u8[5] == 0x01) { + //05,71,03,DF,60,01,00,00, + CollisionResetStatemachine = 4; //Send ECMP_COLLISION_RESET_PROGRESS next loop + } + if (rx_frame.data.u8[5] == 0x02) { + //05,71,03,DF,60,02,00,00, + CollisionResetStatemachine = COMPLETED_STATE; + datalayer_extended.stellantisECMP.UserRequestCollisionReset = false; + timeSpentCollisionReset = COMPLETED_STATE; + } + } + + } else if (datalayer_extended.stellantisECMP.UserRequestIsolationReset) { + if ((rx_frame.data.u8[0] == 0x06) && (rx_frame.data.u8[1] == 0x50) && (rx_frame.data.u8[2] == 0x03)) { + //06,50,03,00,C8,00,14,00, + IsolationResetStatemachine = 2; //Send ECMP_ISOLATION_RESET_START next loop + } + if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x71) && (rx_frame.data.u8[2] == 0x01)) { + //05,71,01,DF,46,01,00,00, + IsolationResetStatemachine = 4; //Send ECMP_ISOLATION_RESET_PROGRESS next loop + } + if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x71) && (rx_frame.data.u8[2] == 0x03)) { + if (rx_frame.data.u8[5] == 0x01) { + //05,71,03,DF,46,01,00,00, + IsolationResetStatemachine = 4; //Send ECMP_ISOLATION_RESET_PROGRESS next loop + } + if (rx_frame.data.u8[5] == 0x02) { + //05,71,03,DF,46,02,00,00, + IsolationResetStatemachine = COMPLETED_STATE; + datalayer_extended.stellantisECMP.UserRequestIsolationReset = false; + timeSpentIsolationReset = COMPLETED_STATE; + } + } + + } else { //Normal PID polling ongoing + + if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK + transmit_can_frame(&ECMP_ACK, can_config.battery); + //Multiframe has the poll reply slightly different location + incoming_poll = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]; + } + + if (rx_frame.data.u8[0] == 0x11) { //One line response, with special handling + incoming_poll = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]; + + switch (incoming_poll) { //One line responses, special + case PID_HISTORY_DATA: + pid_history_data = ((rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + default: + break; + } + } + + if (rx_frame.data.u8[0] < 0x10) { //One line responses + incoming_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + + switch (incoming_poll) { //One line responses + case PID_WELD_CHECK: + pid_welding_detection = (rx_frame.data.u8[4]); + break; + case PID_CONT_REASON_OPEN: + pid_reason_open = (rx_frame.data.u8[4]); + break; + case PID_CONTACTOR_STATUS: + pid_contactor_status = (rx_frame.data.u8[4]); + break; + case PID_NEG_CONT_CONTROL: + pid_negative_contactor_control = (rx_frame.data.u8[4]); + break; + case PID_NEG_CONT_STATUS: + pid_negative_contactor_status = (rx_frame.data.u8[4]); + break; + case PID_POS_CONT_CONTROL: + pid_positive_contactor_control = (rx_frame.data.u8[4]); + break; + case PID_POS_CONT_STATUS: + pid_positive_contactor_status = (rx_frame.data.u8[4]); + break; + case PID_CONTACTOR_NEGATIVE: + pid_contactor_negative = (rx_frame.data.u8[4]); + break; + case PID_CONTACTOR_POSITIVE: + pid_contactor_positive = (rx_frame.data.u8[4]); + break; + case PID_PRECHARGE_RELAY_CONTROL: + pid_precharge_relay_control = (rx_frame.data.u8[4]); + break; + case PID_PRECHARGE_RELAY_STATUS: + pid_precharge_relay_status = (rx_frame.data.u8[4]); + break; + case PID_RECHARGE_STATUS: + pid_recharge_status = (rx_frame.data.u8[4]); + break; + case PID_DELTA_TEMPERATURE: + pid_delta_temperature = (rx_frame.data.u8[4]); + break; + case PID_COLDEST_MODULE: + pid_coldest_module = (rx_frame.data.u8[4]); + break; + case PID_LOWEST_TEMPERATURE: + pid_lowest_temperature = (rx_frame.data.u8[4] - 40); + break; + case PID_AVERAGE_TEMPERATURE: + pid_average_temperature = (rx_frame.data.u8[4] - 40); + break; + case PID_HIGHEST_TEMPERATURE: + pid_highest_temperature = (rx_frame.data.u8[4] - 40); + break; + case PID_HOTTEST_MODULE: + pid_hottest_module = (rx_frame.data.u8[4]); + break; + case PID_AVG_CELL_VOLTAGE: + pid_avg_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_CURRENT: + pid_current = (((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[6] << 8) | + rx_frame.data.u8[7]) - + 76800) * + 10; + break; + case PID_INSULATION_NEG: + pid_insulation_res_neg = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_INSULATION_POS: + pid_insulation_res_pos = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_MAX_CURRENT_10S: + pid_max_current_10s = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_MAX_DISCHARGE_10S: + pid_max_discharge_10s = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_MAX_DISCHARGE_30S: + pid_max_discharge_30s = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_MAX_CHARGE_10S: + pid_max_charge_10s = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_MAX_CHARGE_30S: + pid_max_charge_30s = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_ENERGY_CAPACITY: + pid_energy_capacity = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_HIGH_CELL_NUM: + pid_highest_cell_voltage_num = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_LOW_CELL_NUM: + pid_lowest_cell_voltage_num = (rx_frame.data.u8[4]); + break; + case PID_SUM_OF_CELLS: + pid_sum_of_cells = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_CELL_MIN_CAPACITY: + pid_cell_min_capacity = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_CELL_VOLTAGE_MEAS_STATUS: + pid_cell_voltage_measurement_status = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_INSULATION_RES: + pid_insulation_res = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_PACK_VOLTAGE: + pid_pack_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 2; + break; + case PID_HIGH_CELL_VOLTAGE: + pid_high_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_ALL_CELL_VOLTAGES: + //Multi frame, handled in other function + break; + case PID_LOW_CELL_VOLTAGE: + pid_low_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_BATTERY_ENERGY: + pid_battery_energy = (rx_frame.data.u8[4]); + break; + case PID_CELLBALANCE_STATUS: + //Multi frame?, handled in other function + break; + case PID_CELLBALANCE_HWERR_MASK: + //Multi frame, handled in other function + break; + case PID_CRASH_COUNTER: + pid_crash_counter = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_WIRE_CRASH: + pid_wire_crash = (rx_frame.data.u8[4]); + break; + case PID_CAN_CRASH: + pid_CAN_crash = (rx_frame.data.u8[4]); + break; + case PID_HISTORY_DATA: + //handled in 0x11 handler + break; + case PID_LOWSOC_COUNTER: + pid_lowsoc_counter = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_LAST_CAN_FAILURE_DETAIL: + pid_last_can_failure_detail = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_HW_VERSION_NUM: + //pid_hw_version_num = rx_frame.data.u8[4]; Not available on all batteries + break; + case PID_SW_VERSION_NUM: + //pid_sw_version_num = rx_frame.data.u8[4]; Not available on all batteries + break; + case PID_FACTORY_MODE_CONTROL: + pid_factory_mode_control = rx_frame.data.u8[4]; + break; + case PID_BATTERY_SERIAL: + // Multiframe, handled separately down below + break; + case PID_AUX_FUSE_STATE: + pid_aux_fuse_state = rx_frame.data.u8[4]; + break; + case PID_BATTERY_STATE: + pid_battery_state = rx_frame.data.u8[4]; + break; + case PID_PRECHARGE_SHORT_CIRCUIT: + pid_precharge_short_circuit = rx_frame.data.u8[4]; + break; + case PID_ESERVICE_PLUG_STATE: + pid_eservice_plug_state = rx_frame.data.u8[4]; + break; + case PID_MAINFUSE_STATE: + pid_mainfuse_state = rx_frame.data.u8[4]; + break; + case PID_MOST_CRITICAL_FAULT: + pid_most_critical_fault = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case PID_CURRENT_TIME: + //Multiframe, handled separately down below + break; + case PID_TIME_SENT_BY_CAR: + pid_time_sent_by_car = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_12V: + pid_12v = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_12V_ABNORMAL: + pid_12v_abnormal = rx_frame.data.u8[4]; + break; + case PID_HVIL_IN_VOLTAGE: + pid_hvil_in_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_HVIL_OUT_VOLTAGE: + pid_hvil_out_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case PID_HVIL_STATE: + pid_hvil_state = rx_frame.data.u8[4]; + break; + case PID_BMS_STATE: + pid_bms_state = rx_frame.data.u8[4]; + break; + case PID_VEHICLE_SPEED: + pid_vehicle_speed = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_TIME_SPENT_OVER_55C: + pid_time_spent_over_55c = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_CONTACTOR_CLOSING_COUNTER: + pid_contactor_closing_counter = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case PID_DATE_OF_MANUFACTURE: + pid_date_of_manufacture = + ((rx_frame.data.u8[4] << 16) | (rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6])); + break; + default: + break; + } + } + + switch (incoming_poll) //Multiframe responses + { + case PID_ALL_CELL_VOLTAGES: + switch (rx_frame.data.u8[0]) { + case 0x10: + break; + case 0x21: + break; + case 0x22: + break; + case 0x23: + break; + case 0x24: + break; + case 0x25: + break; + case 0x26: + break; + case 0x27: + break; + case 0x28: + break; + case 0x29: + break; + default: + break; + } + break; + case PID_CELLBALANCE_STATUS: + switch (rx_frame.data.u8[0]) { + case 0x10: + break; + case 0x21: + break; + case 0x22: + break; + case 0x23: + break; + default: + break; + } + break; + case PID_CELLBALANCE_HWERR_MASK: + switch (rx_frame.data.u8[0]) { + case 0x10: + break; + case 0x21: + break; + case 0x22: + break; + case 0x23: + break; + default: + break; + } + break; + case PID_CURRENT_TIME: + switch (rx_frame.data.u8[0]) { + case 0x10: + pid_current_time = (pid_current_time | rx_frame.data.u8[7]); + break; + case 0x21: + pid_current_time = (rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | + (rx_frame.data.u8[1] << 8) | pid_current_time; + break; + default: + break; + } + break; + case PID_BATTERY_SERIAL: + switch (rx_frame.data.u8[0]) { + case 0x10: //10,11,62,D9,01,33,34,41, + pid_battery_serial[0] = rx_frame.data.u8[5]; + pid_battery_serial[1] = rx_frame.data.u8[6]; + pid_battery_serial[2] = rx_frame.data.u8[7]; + break; + case 0x21: //21,41,41,46,30,30,30,32, + pid_battery_serial[3] = rx_frame.data.u8[1]; + pid_battery_serial[4] = rx_frame.data.u8[2]; + pid_battery_serial[5] = rx_frame.data.u8[3]; + pid_battery_serial[6] = rx_frame.data.u8[4]; + pid_battery_serial[7] = rx_frame.data.u8[5]; + pid_battery_serial[8] = rx_frame.data.u8[6]; + pid_battery_serial[9] = rx_frame.data.u8[7]; + break; + case 0x22: //22,32,33,31,00,00,00,00, + pid_battery_serial[10] = rx_frame.data.u8[1]; + pid_battery_serial[11] = rx_frame.data.u8[2]; + pid_battery_serial[12] = rx_frame.data.u8[3]; + pid_battery_serial[13] = rx_frame.data.u8[4]; + break; + default: + break; + } + break; + default: + //Not a multiframe response, do nothing + break; + } + break; + default: + break; + } } } +uint8_t checksum_calc(uint8_t counter, CAN_frame rx_frame) { + // Confirmed working on IDs 0F0,0F2,17B,31B,31D,31E,3A2(special),3A3,112,351 + // Sum of frame ID nibbles + Sum all nibbles of data bytes (frames 0–6 and high nibble of frame7) + int sum = ((rx_frame.ID >> 8) & 0xF) + ((rx_frame.ID >> 4) & 0xF) + (rx_frame.ID & 0xF); + sum += (rx_frame.data.u8[0] >> 4) + (rx_frame.data.u8[0] & 0xF); + sum += (rx_frame.data.u8[1] >> 4) + (rx_frame.data.u8[1] & 0xF); + sum += (rx_frame.data.u8[2] >> 4) + (rx_frame.data.u8[2] & 0xF); + sum += (rx_frame.data.u8[3] >> 4) + (rx_frame.data.u8[3] & 0xF); + sum += (rx_frame.data.u8[4] >> 4) + (rx_frame.data.u8[4] & 0xF); + sum += (rx_frame.data.u8[5] >> 4) + (rx_frame.data.u8[5] & 0xF); + sum += (rx_frame.data.u8[6] >> 4) + (rx_frame.data.u8[6] & 0xF); + sum += (counter); //high nibble of frame7 + + // Compute: (0xF - sum) % 16 + return (0xF - sum) & 0xF; // Masking with & 0xF ensures modulo 16 +} + void EcmpBattery::transmit_can(unsigned long currentMillis) { - // Send 20ms CAN Message + + // Send 250ms diagnostic CAN Messages + if (currentMillis - previousMillis250 >= INTERVAL_250_MS) { + previousMillis250 = currentMillis; + + //To be able to use the battery, isolation monitoring needs to be disabled + //Failure to do this results in the contactors opening after 30 seconds with load + if (datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring) { + if (DisableIsoMonitoringStatemachine == 0) { + transmit_can_frame(&ECMP_DIAG_START, can_config.battery); + DisableIsoMonitoringStatemachine = 1; + } + if (DisableIsoMonitoringStatemachine == 2) { + transmit_can_frame(&ECMP_FACTORY_MODE_ACTIVATION_NEW, can_config.battery); + DisableIsoMonitoringStatemachine = 3; + } + if (DisableIsoMonitoringStatemachine == 4) { + transmit_can_frame(&ECMP_DISABLE_ISOLATION_REQ, can_config.battery); + DisableIsoMonitoringStatemachine = 5; + } + if (DisableIsoMonitoringStatemachine == 6) { + transmit_can_frame(&ECMP_FACTORY_MODE_ACTIVATION, can_config.battery); + DisableIsoMonitoringStatemachine = 7; + } + timeSpentDisableIsoMonitoring++; + if (timeSpentDisableIsoMonitoring > 40) { //Timeout, if command takes more than 10s to complete + datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring = false; + DisableIsoMonitoringStatemachine = COMPLETED_STATE; + timeSpentDisableIsoMonitoring = COMPLETED_STATE; + } + } else if (datalayer_extended.stellantisECMP.UserRequestContactorReset) { + if (ContactorResetStatemachine == 0) { + transmit_can_frame(&ECMP_DIAG_START, can_config.battery); + ContactorResetStatemachine = 1; + } + if (ContactorResetStatemachine == 2) { + transmit_can_frame(&ECMP_CONTACTOR_RESET_START, can_config.battery); + ContactorResetStatemachine = 3; + } + if (ContactorResetStatemachine == 4) { + transmit_can_frame(&ECMP_CONTACTOR_RESET_PROGRESS, can_config.battery); + ContactorResetStatemachine = 5; + } + + timeSpentContactorReset++; + if (timeSpentContactorReset > 40) { //Timeout, if command takes more than 10s to complete + datalayer_extended.stellantisECMP.UserRequestContactorReset = false; + ContactorResetStatemachine = COMPLETED_STATE; + timeSpentContactorReset = COMPLETED_STATE; + } + + } else if (datalayer_extended.stellantisECMP.UserRequestCollisionReset) { + + if (CollisionResetStatemachine == 0) { + transmit_can_frame(&ECMP_DIAG_START, can_config.battery); + CollisionResetStatemachine = 1; + } + if (CollisionResetStatemachine == 2) { + transmit_can_frame(&ECMP_COLLISION_RESET_START, can_config.battery); + CollisionResetStatemachine = 3; + } + if (CollisionResetStatemachine == 4) { + transmit_can_frame(&ECMP_COLLISION_RESET_PROGRESS, can_config.battery); + CollisionResetStatemachine = 5; + } + + timeSpentCollisionReset++; + if (timeSpentCollisionReset > 40) { //Timeout, if command takes more than 10s to complete + datalayer_extended.stellantisECMP.UserRequestCollisionReset = false; + CollisionResetStatemachine = COMPLETED_STATE; + timeSpentCollisionReset = COMPLETED_STATE; + } + + } else if (datalayer_extended.stellantisECMP.UserRequestIsolationReset) { + + if (IsolationResetStatemachine == 0) { + transmit_can_frame(&ECMP_DIAG_START, can_config.battery); + IsolationResetStatemachine = 1; + } + if (IsolationResetStatemachine == 2) { + transmit_can_frame(&ECMP_ISOLATION_RESET_START, can_config.battery); + IsolationResetStatemachine = 3; + } + if (IsolationResetStatemachine == 4) { + transmit_can_frame(&ECMP_ISOLATION_RESET_PROGRESS, can_config.battery); + IsolationResetStatemachine = 5; + } + + timeSpentIsolationReset++; + if (timeSpentIsolationReset > 40) { //Timeout, if command takes more than 10s to complete + if (countIsolationReset < 4) { + countIsolationReset++; + IsolationResetStatemachine = 0; //Reset state machine to start over + } else { + datalayer_extended.stellantisECMP.UserRequestIsolationReset = false; + IsolationResetStatemachine = COMPLETED_STATE; + timeSpentIsolationReset = COMPLETED_STATE; + countIsolationReset = 0; + } + } + + } else { //Normal PID polling goes here + + if (datalayer.battery.status.bms_status != FAULT) { //Stop PID polling if battery is in FAULT mode + + switch (poll_state) { + case PID_WELD_CHECK: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_WELD_CHECK & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_WELD_CHECK & 0x00FF); + poll_state = PID_CONT_REASON_OPEN; + break; + case PID_CONT_REASON_OPEN: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CONT_REASON_OPEN & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CONT_REASON_OPEN & 0x00FF); + poll_state = PID_CONTACTOR_STATUS; + break; + case PID_CONTACTOR_STATUS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CONTACTOR_STATUS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CONTACTOR_STATUS & 0x00FF); + poll_state = PID_NEG_CONT_CONTROL; + break; + case PID_NEG_CONT_CONTROL: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_NEG_CONT_CONTROL & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_NEG_CONT_CONTROL & 0x00FF); + poll_state = PID_NEG_CONT_STATUS; + break; + case PID_NEG_CONT_STATUS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_NEG_CONT_STATUS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_NEG_CONT_STATUS & 0x00FF); + poll_state = PID_POS_CONT_CONTROL; + break; + case PID_POS_CONT_CONTROL: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_POS_CONT_CONTROL & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_POS_CONT_CONTROL & 0x00FF); + poll_state = PID_POS_CONT_STATUS; + break; + case PID_POS_CONT_STATUS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_POS_CONT_STATUS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_POS_CONT_STATUS & 0x00FF); + poll_state = PID_CONTACTOR_NEGATIVE; + break; + case PID_CONTACTOR_NEGATIVE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CONTACTOR_NEGATIVE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CONTACTOR_NEGATIVE & 0x00FF); + poll_state = PID_CONTACTOR_POSITIVE; + break; + case PID_CONTACTOR_POSITIVE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CONTACTOR_POSITIVE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CONTACTOR_POSITIVE & 0x00FF); + poll_state = PID_PRECHARGE_RELAY_CONTROL; + break; + case PID_PRECHARGE_RELAY_CONTROL: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_PRECHARGE_RELAY_CONTROL & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_PRECHARGE_RELAY_CONTROL & 0x00FF); + poll_state = PID_PRECHARGE_RELAY_STATUS; + break; + case PID_PRECHARGE_RELAY_STATUS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_PRECHARGE_RELAY_STATUS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_PRECHARGE_RELAY_STATUS & 0x00FF); + poll_state = PID_RECHARGE_STATUS; + break; + case PID_RECHARGE_STATUS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_RECHARGE_STATUS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_RECHARGE_STATUS & 0x00FF); + poll_state = PID_DELTA_TEMPERATURE; + break; + case PID_DELTA_TEMPERATURE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_DELTA_TEMPERATURE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_DELTA_TEMPERATURE & 0x00FF); + poll_state = PID_COLDEST_MODULE; + break; + case PID_COLDEST_MODULE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_COLDEST_MODULE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_COLDEST_MODULE & 0x00FF); + poll_state = PID_LOWEST_TEMPERATURE; + break; + case PID_LOWEST_TEMPERATURE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_LOWEST_TEMPERATURE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_LOWEST_TEMPERATURE & 0x00FF); + poll_state = PID_AVERAGE_TEMPERATURE; + break; + case PID_AVERAGE_TEMPERATURE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_AVERAGE_TEMPERATURE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_AVERAGE_TEMPERATURE & 0x00FF); + poll_state = PID_HIGHEST_TEMPERATURE; + break; + case PID_HIGHEST_TEMPERATURE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HIGHEST_TEMPERATURE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HIGHEST_TEMPERATURE & 0x00FF); + poll_state = PID_HOTTEST_MODULE; + break; + case PID_HOTTEST_MODULE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HOTTEST_MODULE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HOTTEST_MODULE & 0x00FF); + poll_state = PID_AVG_CELL_VOLTAGE; + break; + case PID_AVG_CELL_VOLTAGE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_AVG_CELL_VOLTAGE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_AVG_CELL_VOLTAGE & 0x00FF); + poll_state = PID_CURRENT; + break; + case PID_CURRENT: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CURRENT & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CURRENT & 0x00FF); + poll_state = PID_INSULATION_NEG; + break; + case PID_INSULATION_NEG: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_INSULATION_NEG & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_INSULATION_NEG & 0x00FF); + poll_state = PID_INSULATION_POS; + break; + case PID_INSULATION_POS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_INSULATION_POS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_INSULATION_POS & 0x00FF); + poll_state = PID_MAX_CURRENT_10S; + break; + case PID_MAX_CURRENT_10S: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_MAX_CURRENT_10S & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_MAX_CURRENT_10S & 0x00FF); + poll_state = PID_MAX_DISCHARGE_10S; + break; + case PID_MAX_DISCHARGE_10S: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_MAX_DISCHARGE_10S & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_MAX_DISCHARGE_10S & 0x00FF); + poll_state = PID_MAX_DISCHARGE_30S; + break; + case PID_MAX_DISCHARGE_30S: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_MAX_DISCHARGE_30S & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_MAX_DISCHARGE_30S & 0x00FF); + poll_state = PID_MAX_CHARGE_10S; + break; + case PID_MAX_CHARGE_10S: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_MAX_CHARGE_10S & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_MAX_CHARGE_10S & 0x00FF); + poll_state = PID_MAX_CHARGE_30S; + break; + case PID_MAX_CHARGE_30S: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_MAX_CHARGE_30S & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_MAX_CHARGE_30S & 0x00FF); + poll_state = PID_ENERGY_CAPACITY; + break; + case PID_ENERGY_CAPACITY: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_ENERGY_CAPACITY & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_ENERGY_CAPACITY & 0x00FF); + poll_state = PID_HIGH_CELL_NUM; + break; + case PID_HIGH_CELL_NUM: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HIGH_CELL_NUM & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HIGH_CELL_NUM & 0x00FF); + poll_state = PID_LOW_CELL_NUM; + break; + case PID_LOW_CELL_NUM: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_LOW_CELL_NUM & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_LOW_CELL_NUM & 0x00FF); + poll_state = PID_SUM_OF_CELLS; + break; + case PID_SUM_OF_CELLS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_SUM_OF_CELLS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_SUM_OF_CELLS & 0x00FF); + poll_state = PID_CELL_MIN_CAPACITY; + break; + case PID_CELL_MIN_CAPACITY: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CELL_MIN_CAPACITY & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CELL_MIN_CAPACITY & 0x00FF); + poll_state = PID_CELL_VOLTAGE_MEAS_STATUS; + break; + case PID_CELL_VOLTAGE_MEAS_STATUS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CELL_VOLTAGE_MEAS_STATUS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CELL_VOLTAGE_MEAS_STATUS & 0x00FF); + poll_state = PID_INSULATION_RES; + break; + case PID_INSULATION_RES: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_INSULATION_RES & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_INSULATION_RES & 0x00FF); + poll_state = PID_PACK_VOLTAGE; + break; + case PID_PACK_VOLTAGE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_PACK_VOLTAGE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_PACK_VOLTAGE & 0x00FF); + poll_state = PID_HIGH_CELL_VOLTAGE; + break; + case PID_HIGH_CELL_VOLTAGE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HIGH_CELL_VOLTAGE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HIGH_CELL_VOLTAGE & 0x00FF); + poll_state = PID_ALL_CELL_VOLTAGES; + break; + case PID_ALL_CELL_VOLTAGES: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_ALL_CELL_VOLTAGES & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_ALL_CELL_VOLTAGES & 0x00FF); + poll_state = PID_LOW_CELL_VOLTAGE; + break; + case PID_LOW_CELL_VOLTAGE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_LOW_CELL_VOLTAGE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_LOW_CELL_VOLTAGE & 0x00FF); + poll_state = PID_BATTERY_ENERGY; + break; + case PID_BATTERY_ENERGY: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_BATTERY_ENERGY & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_BATTERY_ENERGY & 0x00FF); + poll_state = PID_CELLBALANCE_STATUS; + break; + case PID_CELLBALANCE_STATUS: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CELLBALANCE_STATUS & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CELLBALANCE_STATUS & 0x00FF); + poll_state = PID_CELLBALANCE_HWERR_MASK; + break; + case PID_CELLBALANCE_HWERR_MASK: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CELLBALANCE_HWERR_MASK & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CELLBALANCE_HWERR_MASK & 0x00FF); + poll_state = PID_CRASH_COUNTER; + break; + case PID_CRASH_COUNTER: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CRASH_COUNTER & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CRASH_COUNTER & 0x00FF); + poll_state = PID_WIRE_CRASH; + break; + case PID_WIRE_CRASH: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_WIRE_CRASH & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_WIRE_CRASH & 0x00FF); + poll_state = PID_CAN_CRASH; + break; + case PID_CAN_CRASH: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CAN_CRASH & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CAN_CRASH & 0x00FF); + poll_state = PID_HISTORY_DATA; + break; + case PID_HISTORY_DATA: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HISTORY_DATA & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HISTORY_DATA & 0x00FF); + poll_state = PID_LOWSOC_COUNTER; + break; + case PID_LOWSOC_COUNTER: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_LOWSOC_COUNTER & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_LOWSOC_COUNTER & 0x00FF); + poll_state = PID_LAST_CAN_FAILURE_DETAIL; + break; + case PID_LAST_CAN_FAILURE_DETAIL: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_LAST_CAN_FAILURE_DETAIL & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_LAST_CAN_FAILURE_DETAIL & 0x00FF); + poll_state = PID_HW_VERSION_NUM; + break; + case PID_HW_VERSION_NUM: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HW_VERSION_NUM & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HW_VERSION_NUM & 0x00FF); + poll_state = PID_SW_VERSION_NUM; + break; + case PID_SW_VERSION_NUM: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_SW_VERSION_NUM & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_SW_VERSION_NUM & 0x00FF); + poll_state = PID_FACTORY_MODE_CONTROL; + break; + case PID_FACTORY_MODE_CONTROL: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_FACTORY_MODE_CONTROL & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_FACTORY_MODE_CONTROL & 0x00FF); + poll_state = PID_BATTERY_SERIAL; + break; + case PID_BATTERY_SERIAL: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_BATTERY_SERIAL & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_BATTERY_SERIAL & 0x00FF); + poll_state = PID_AUX_FUSE_STATE; + break; + case PID_AUX_FUSE_STATE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_AUX_FUSE_STATE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_AUX_FUSE_STATE & 0x00FF); + poll_state = PID_BATTERY_STATE; + break; + case PID_BATTERY_STATE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_BATTERY_STATE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_BATTERY_STATE & 0x00FF); + poll_state = PID_PRECHARGE_SHORT_CIRCUIT; + break; + case PID_PRECHARGE_SHORT_CIRCUIT: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_PRECHARGE_SHORT_CIRCUIT & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_PRECHARGE_SHORT_CIRCUIT & 0x00FF); + poll_state = PID_ESERVICE_PLUG_STATE; + break; + case PID_ESERVICE_PLUG_STATE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_ESERVICE_PLUG_STATE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_ESERVICE_PLUG_STATE & 0x00FF); + poll_state = PID_MAINFUSE_STATE; + break; + case PID_MAINFUSE_STATE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_MAINFUSE_STATE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_MAINFUSE_STATE & 0x00FF); + poll_state = PID_MOST_CRITICAL_FAULT; + break; + case PID_MOST_CRITICAL_FAULT: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_MOST_CRITICAL_FAULT & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_MOST_CRITICAL_FAULT & 0x00FF); + poll_state = PID_CURRENT_TIME; + break; + case PID_CURRENT_TIME: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CURRENT_TIME & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CURRENT_TIME & 0x00FF); + poll_state = PID_TIME_SENT_BY_CAR; + break; + case PID_TIME_SENT_BY_CAR: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_TIME_SENT_BY_CAR & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_TIME_SENT_BY_CAR & 0x00FF); + poll_state = PID_12V; + break; + case PID_12V: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_12V & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_12V & 0x00FF); + poll_state = PID_12V_ABNORMAL; + break; + case PID_12V_ABNORMAL: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_12V_ABNORMAL & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_12V_ABNORMAL & 0x00FF); + poll_state = PID_HVIL_IN_VOLTAGE; + break; + case PID_HVIL_IN_VOLTAGE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HVIL_IN_VOLTAGE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HVIL_IN_VOLTAGE & 0x00FF); + poll_state = PID_HVIL_OUT_VOLTAGE; + break; + case PID_HVIL_OUT_VOLTAGE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HVIL_OUT_VOLTAGE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HVIL_OUT_VOLTAGE & 0x00FF); + poll_state = PID_HVIL_STATE; + break; + case PID_HVIL_STATE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_HVIL_STATE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_HVIL_STATE & 0x00FF); + poll_state = PID_BMS_STATE; + break; + case PID_BMS_STATE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_BMS_STATE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_BMS_STATE & 0x00FF); + poll_state = PID_VEHICLE_SPEED; + break; + case PID_VEHICLE_SPEED: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_VEHICLE_SPEED & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_VEHICLE_SPEED & 0x00FF); + poll_state = PID_TIME_SPENT_OVER_55C; + break; + case PID_TIME_SPENT_OVER_55C: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_TIME_SPENT_OVER_55C & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_TIME_SPENT_OVER_55C & 0x00FF); + poll_state = PID_CONTACTOR_CLOSING_COUNTER; + break; + case PID_CONTACTOR_CLOSING_COUNTER: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_CONTACTOR_CLOSING_COUNTER & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_CONTACTOR_CLOSING_COUNTER & 0x00FF); + poll_state = PID_DATE_OF_MANUFACTURE; + break; + case PID_DATE_OF_MANUFACTURE: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_DATE_OF_MANUFACTURE & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_DATE_OF_MANUFACTURE & 0x00FF); + poll_state = PID_WELD_CHECK; // Loop back to beginning + break; + default: + //We should not end up here. Reset poll_state to first poll + poll_state = PID_WELD_CHECK; + break; + } + transmit_can_frame(&ECMP_POLL, can_config.battery); + } + } + } + + // Send 10ms periodic CAN Message simulating the car still being attached + if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { + previousMillis10 = currentMillis; + + counter_10ms = (counter_10ms + 1) % 16; + + if (datalayer.battery.status.bms_status == FAULT) { + //Make vehicle appear as in idle HV state. Useful for clearing DTCs + ECMP_0F2.data = {0x7D, 0x00, 0x4E, 0x20, 0x00, 0x00, 0x60, 0x0D}; + ECMP_17B.data = {0x00, 0x00, 0x00, 0x7E, 0x78, 0x00, 0x00, 0x0F}; + ECMP_110.data.u8[6] = 0x87; + ECMP_110.data.u8[7] = 0x05; + } else { + //Normal operation for contactor closing + ECMP_0F2.data = {0x7D, 0x00, 0x4E, 0x20, 0x00, 0x00, 0x90, 0x0D}; + ECMP_110.data.u8[6] = 0x4E; + ECMP_110.data.u8[7] = 0x20; + ECMP_17B.data = {0x00, 0x00, 0x00, 0x7F, 0x98, 0x00, 0x00, 0x0F}; + } + + ECMP_0F2.data.u8[7] = counter_10ms << 4 | checksum_calc(counter_10ms, ECMP_0F2); + ECMP_17B.data.u8[7] = counter_10ms << 4 | checksum_calc(counter_10ms, ECMP_17B); + ECMP_112.data.u8[7] = counter_10ms << 4 | checksum_calc(counter_10ms, ECMP_112); + + transmit_can_frame(&ECMP_112, can_config.battery); //MCU1_112 + transmit_can_frame(&ECMP_0C5, can_config.battery); //DC2_0C5 + transmit_can_frame(&ECMP_17B, can_config.battery); //VCU_PCANInfo_17B + transmit_can_frame(&ECMP_0F2, can_config.battery); //CtrlMCU1_0F2 + transmit_can_frame(&ECMP_111, can_config.battery); + transmit_can_frame(&ECMP_110, can_config.battery); + transmit_can_frame(&ECMP_114, can_config.battery); + } + + // Send 20ms periodic CAN Message simulating the car still being attached if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { previousMillis20 = currentMillis; - counter_20ms = (counter_20ms + 1) % 16; - if (datalayer.battery.status.bms_status == FAULT) { //Open contactors! ECMP_0F0.data.u8[1] = 0x00; - ECMP_0F0.data.u8[7] = data_0F0_00[counter_20ms]; } else { // Not in faulted mode, Close contactors! ECMP_0F0.data.u8[1] = 0x20; - ECMP_0F0.data.u8[7] = data_0F0_20[counter_20ms]; } - transmit_can_frame(&ECMP_0F0, can_config.battery); //Common! + counter_20ms = (counter_20ms + 1) % 16; + + ECMP_0F0.data.u8[7] = counter_20ms << 4 | checksum_calc(counter_20ms, ECMP_0F0); + + transmit_can_frame(&ECMP_0F0, can_config.battery); //VCU2_0F0 } - // Send 100ms CAN Message + // Send 50ms periodic CAN Message simulating the car still being attached + if (currentMillis - previousMillis50 >= INTERVAL_50_MS) { + previousMillis50 = currentMillis; + + if (datalayer.battery.status.bms_status == FAULT) { + //Make vehicle appear as in idle HV state. Useful for clearing DTCs + ECMP_27A.data = {0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + } else { + //Normal operation for contactor closing + ECMP_27A.data = {0x4F, 0x58, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00}; + } + transmit_can_frame(&ECMP_230, can_config.battery); //OBC3_230 + transmit_can_frame(&ECMP_27A, can_config.battery); //PSA specific VCU message (VCU_BSI_Wakeup_27A) + } + // Send 100ms periodic CAN Message simulating the car still being attached if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; - transmit_can_frame(&ECMP_382, can_config.battery); //PSA Specific! + counter_100ms = (counter_100ms + 1) % 16; + counter_010 = (counter_010 + 1) % 8; + + if (datalayer.battery.status.bms_status == FAULT) { + //Make vehicle appear as in idle HV state. Useful for clearing DTCs + ECMP_31E.data.u8[0] = 0x48; + ECMP_345.data = {0x45, 0x57, 0x00, 0x04, 0x00, 0x00, 0x06, 0x31}; + ECMP_351.data = {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0E}; + ECMP_372.data = {0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + ECMP_383.data.u8[0] = 0x00; + ECMP_3A2.data = {0x03, 0xE8, 0x00, 0x00, 0x81, 0x00, 0x08, 0x02}; + ECMP_3A3.data = {0x4A, 0x4A, 0x40, 0x00, 0x00, 0x08, 0x00, 0x0F}; + data_345_content[0] = 0x04; // Allows for DTCs to clear + data_345_content[1] = 0xF5; + data_345_content[2] = 0xE6; + data_345_content[3] = 0xD7; + data_345_content[4] = 0xC8; + data_345_content[5] = 0xB9; + data_345_content[6] = 0xAA; + data_345_content[7] = 0x9B; + data_345_content[8] = 0x8C; + data_345_content[9] = 0x7D; + data_345_content[10] = 0x6E; + data_345_content[11] = 0x5F; + data_345_content[12] = 0x40; + data_345_content[13] = 0x31; + data_345_content[14] = 0x22; + data_345_content[15] = 0x13; + data_3A2_CRC[0] = 0x0C; + data_3A2_CRC[1] = 0x1B; + data_3A2_CRC[2] = 0x2A; + data_3A2_CRC[3] = 0x39; + data_3A2_CRC[4] = 0x48; + data_3A2_CRC[5] = 0x57; + data_3A2_CRC[6] = 0x66; + data_3A2_CRC[7] = 0x75; + data_3A2_CRC[8] = 0x84; + data_3A2_CRC[9] = 0x93; + data_3A2_CRC[10] = 0xA2; + data_3A2_CRC[11] = 0xB1; + data_3A2_CRC[12] = 0xC0; + data_3A2_CRC[13] = 0xDF; + data_3A2_CRC[14] = 0xEE; + data_3A2_CRC[15] = 0xFD; + transmit_can_frame(&ECMP_3D0, can_config.battery); //Not in logs, but makes speed go to 0km/h + } else { + //Normal operation for contactor closing + ECMP_31E.data.u8[0] = 0x50; + ECMP_345.data = {0x45, 0x52, 0x00, 0x04, 0xDD, 0x00, 0x02, 0x30}; + ECMP_351.data = {0x00, 0x00, 0x00, 0x00, 0x0E, 0xA0, 0x00, 0xE0}; + ECMP_372.data = {0x9A, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + ECMP_383.data.u8[0] = 0x40; + ECMP_3A2.data = {0x01, 0x68, 0x00, 0x00, 0x81, 0x00, 0x08, 0x02}; + ECMP_3A3.data = {0x49, 0x49, 0x40, 0x00, 0xDD, 0x08, 0x00, 0x0F}; + data_345_content[0] = 0x00; // Allows for contactor closing + data_345_content[1] = 0xF1; + data_345_content[2] = 0xE2; + data_345_content[3] = 0xD3; + data_345_content[4] = 0xC4; + data_345_content[5] = 0xB5; + data_345_content[6] = 0xA6; + data_345_content[7] = 0x97; + data_345_content[8] = 0x88; + data_345_content[9] = 0x79; + data_345_content[10] = 0x6A; + data_345_content[11] = 0x5B; + data_345_content[12] = 0x4C; + data_345_content[13] = 0x3D; + data_345_content[14] = 0x2E; + data_345_content[15] = 0x1F; + data_3A2_CRC[0] = 0x06; // Allows for contactor closing + data_3A2_CRC[1] = 0x15; + data_3A2_CRC[2] = 0x24; + data_3A2_CRC[3] = 0x33; + data_3A2_CRC[4] = 0x42; + data_3A2_CRC[5] = 0x51; + data_3A2_CRC[6] = 0x60; + data_3A2_CRC[7] = 0x7F; + data_3A2_CRC[8] = 0x8E; + data_3A2_CRC[9] = 0x9D; + data_3A2_CRC[10] = 0xAC; + data_3A2_CRC[11] = 0xBB; + data_3A2_CRC[12] = 0xCA; + data_3A2_CRC[13] = 0xD9; + data_3A2_CRC[14] = 0xE8; + data_3A2_CRC[15] = 0xF7; + } + + ECMP_31E.data.u8[7] = counter_100ms << 4 | checksum_calc(counter_100ms, ECMP_31E); + ECMP_3A2.data.u8[6] = data_3A2_CRC[counter_100ms]; + ECMP_3A3.data.u8[7] = counter_100ms << 4 | checksum_calc(counter_100ms, ECMP_3A3); + ECMP_010.data.u8[0] = data_010_CRC[counter_010]; + ECMP_345.data.u8[3] = (uint8_t)((data_345_content[counter_100ms] & 0XF0) | 0x4); + ECMP_345.data.u8[7] = (uint8_t)(0x3 << 4 | (data_345_content[counter_100ms] & 0X0F)); + ECMP_351.data.u8[7] = counter_100ms << 4 | checksum_calc(counter_100ms, ECMP_351); + ECMP_31D.data.u8[7] = counter_100ms << 4 | checksum_calc(counter_100ms, ECMP_31D); + ECMP_3D0.data.u8[7] = counter_100ms << 4 | checksum_calc(counter_100ms, ECMP_3D0); + + transmit_can_frame(&ECMP_382, can_config.battery); //PSA Specific VCU (BSIInfo_382) + transmit_can_frame(&ECMP_345, can_config.battery); //DC1_345 + transmit_can_frame(&ECMP_3A2, can_config.battery); //OBC2_3A2 + transmit_can_frame(&ECMP_3A3, can_config.battery); //OBC1_3A3 + transmit_can_frame(&ECMP_31E, can_config.battery); + transmit_can_frame(&ECMP_383, can_config.battery); + transmit_can_frame(&ECMP_010, can_config.battery); + transmit_can_frame(&ECMP_0A6, can_config.battery); //Not in all logs + transmit_can_frame(&ECMP_37F, can_config.battery); //Seems to be temperatures of some sort + transmit_can_frame(&ECMP_372, can_config.battery); + transmit_can_frame(&ECMP_351, can_config.battery); + transmit_can_frame(&ECMP_31D, can_config.battery); + } + // Send 500ms periodic CAN Message simulating the car still being attached + if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { + previousMillis500 = currentMillis; + + transmit_can_frame(&ECMP_0AE, can_config.battery); + } + // Send 1s CAN Message + if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { + previousMillis1000 = currentMillis; + + if (datalayer.battery.status.bms_status == FAULT) { + //Make vehicle appear as in idle HV state. Useful for clearing DTCs + ECMP_486.data.u8[0] = 0x80; + ECMP_794.data.u8[0] = 0xB8; //Not sure if needed, could be static? + } else { + //Normal operation for contactor closing + ECMP_486.data.u8[0] = 0x00; + ECMP_794.data.u8[0] = 0x38; //Not sure if needed, could be static? + } + + //552 seems to be tracking time in byte 0-3 , distance in km in byte 4-6, temporal reset counter in byte 7 + ticks_552 = (ticks_552 + 10); + ECMP_552.data.u8[0] = ((ticks_552 & 0xFF000000) >> 24); + ECMP_552.data.u8[1] = ((ticks_552 & 0x00FF0000) >> 16); + ECMP_552.data.u8[2] = ((ticks_552 & 0x0000FF00) >> 8); + ECMP_552.data.u8[3] = (ticks_552 & 0x000000FF); + + transmit_can_frame(&ECMP_439, can_config.battery); //PSA Specific? Not in all logs + transmit_can_frame(&ECMP_486, can_config.battery); //Not in all logs + transmit_can_frame(&ECMP_041, can_config.battery); //Not in all logs + transmit_can_frame(&ECMP_786, can_config.battery); //Not in all logs + transmit_can_frame(&ECMP_591, can_config.battery); //Not in all logs + transmit_can_frame(&ECMP_552, can_config.battery); //VCU_552 timetracking + transmit_can_frame(&ECMP_794, can_config.battery); //Not in all logs + } + // Send 5s periodic CAN Message simulating the car still being attached + if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { + previousMillis5000 = currentMillis; + + transmit_can_frame(&ECMP_55F, can_config.battery); } } diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h index ad3fb041..c2065587 100644 --- a/Software/src/battery/ECMP-BATTERY.h +++ b/Software/src/battery/ECMP-BATTERY.h @@ -16,6 +16,18 @@ class EcmpBattery : public CanBattery { virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + bool supports_clear_isolation() { return true; } + void clear_isolation() { datalayer_extended.stellantisECMP.UserRequestIsolationReset = true; } + + bool supports_factory_mode_method() { return true; } + void set_factory_mode() { datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring = true; } + + bool supports_reset_crash() { return true; } + void reset_crash() { datalayer_extended.stellantisECMP.UserRequestCollisionReset = true; } + + bool supports_contactor_reset() { return true; } + void reset_contactor() { datalayer_extended.stellantisECMP.UserRequestContactorReset = true; } + BatteryHtmlRenderer& get_status_renderer() { return renderer; } private: @@ -25,9 +37,25 @@ class EcmpBattery : public CanBattery { static const int MAX_CELL_DEVIATION_MV = 100; static const int MAX_CELL_VOLTAGE_MV = 4250; static const int MIN_CELL_VOLTAGE_MV = 2700; - +#define NOT_SAMPLED_YET 255 +#define COMPLETED_STATE 0 bool battery_RelayOpenRequest = false; + bool battery_InterlockOpen = false; + uint8_t ContactorResetStatemachine = 0; + uint8_t CollisionResetStatemachine = 0; + uint8_t IsolationResetStatemachine = 0; + uint8_t DisableIsoMonitoringStatemachine = 0; + uint8_t timeSpentDisableIsoMonitoring = 0; + uint8_t timeSpentContactorReset = 0; + uint8_t timeSpentCollisionReset = 0; + uint8_t timeSpentIsolationReset = 0; + uint8_t countIsolationReset = 0; + uint8_t counter_10ms = 0; uint8_t counter_20ms = 0; + uint8_t counter_50ms = 0; + uint8_t counter_100ms = 0; + uint8_t counter_010 = 0; + uint32_t ticks_552 = 0x0BC8CFC6; uint8_t battery_MainConnectorState = 0; int16_t battery_current = 0; uint16_t battery_voltage = 370; @@ -36,27 +64,368 @@ class EcmpBattery : public CanBattery { uint16_t battery_AllowedMaxChargeCurrent = 0; uint16_t battery_AllowedMaxDischargeCurrent = 0; uint16_t battery_insulationResistanceKOhm = 0; + uint8_t battery_insulation_failure_diag = 0; int16_t battery_highestTemperature = 0; int16_t battery_lowestTemperature = 0; + uint8_t pid_welding_detection = NOT_SAMPLED_YET; + uint8_t pid_reason_open = NOT_SAMPLED_YET; + uint8_t pid_contactor_status = NOT_SAMPLED_YET; + uint8_t pid_negative_contactor_control = NOT_SAMPLED_YET; + uint8_t pid_negative_contactor_status = NOT_SAMPLED_YET; + uint8_t pid_positive_contactor_control = NOT_SAMPLED_YET; + uint8_t pid_positive_contactor_status = NOT_SAMPLED_YET; + uint8_t pid_contactor_negative = NOT_SAMPLED_YET; + uint8_t pid_contactor_positive = NOT_SAMPLED_YET; + uint8_t pid_precharge_relay_control = NOT_SAMPLED_YET; + uint8_t pid_precharge_relay_status = NOT_SAMPLED_YET; + uint8_t pid_recharge_status = NOT_SAMPLED_YET; + uint8_t pid_delta_temperature = NOT_SAMPLED_YET; + uint8_t pid_coldest_module = NOT_SAMPLED_YET; + uint8_t pid_lowest_temperature = NOT_SAMPLED_YET; + uint8_t pid_average_temperature = NOT_SAMPLED_YET; + uint8_t pid_highest_temperature = NOT_SAMPLED_YET; + uint8_t pid_hottest_module = NOT_SAMPLED_YET; + uint16_t pid_avg_cell_voltage = NOT_SAMPLED_YET; + int32_t pid_current = NOT_SAMPLED_YET; + uint32_t pid_insulation_res_neg = NOT_SAMPLED_YET; + uint32_t pid_insulation_res_pos = NOT_SAMPLED_YET; + uint32_t pid_max_current_10s = NOT_SAMPLED_YET; + uint32_t pid_max_discharge_10s = NOT_SAMPLED_YET; + uint32_t pid_max_discharge_30s = NOT_SAMPLED_YET; + uint32_t pid_max_charge_10s = NOT_SAMPLED_YET; + uint32_t pid_max_charge_30s = NOT_SAMPLED_YET; + uint32_t pid_energy_capacity = NOT_SAMPLED_YET; + uint8_t pid_highest_cell_voltage_num = NOT_SAMPLED_YET; + uint8_t pid_lowest_cell_voltage_num = NOT_SAMPLED_YET; + uint16_t pid_sum_of_cells = NOT_SAMPLED_YET; + uint16_t pid_cell_min_capacity = NOT_SAMPLED_YET; + uint8_t pid_cell_voltage_measurement_status = NOT_SAMPLED_YET; + uint32_t pid_insulation_res = NOT_SAMPLED_YET; + uint16_t pid_pack_voltage = NOT_SAMPLED_YET; + uint16_t pid_high_cell_voltage = NOT_SAMPLED_YET; + uint16_t pid_low_cell_voltage = NOT_SAMPLED_YET; + uint8_t pid_battery_energy = NOT_SAMPLED_YET; + uint32_t pid_crash_counter = NOT_SAMPLED_YET; + uint8_t pid_wire_crash = NOT_SAMPLED_YET; + uint8_t pid_CAN_crash = NOT_SAMPLED_YET; + uint32_t pid_history_data = NOT_SAMPLED_YET; + uint32_t pid_lowsoc_counter = NOT_SAMPLED_YET; + uint32_t pid_last_can_failure_detail = NOT_SAMPLED_YET; + uint32_t pid_hw_version_num = NOT_SAMPLED_YET; + uint32_t pid_sw_version_num = NOT_SAMPLED_YET; + uint32_t pid_factory_mode_control = NOT_SAMPLED_YET; + uint8_t pid_battery_serial[13] = {0}; + uint32_t pid_aux_fuse_state = NOT_SAMPLED_YET; + uint32_t pid_battery_state = NOT_SAMPLED_YET; + uint32_t pid_precharge_short_circuit = NOT_SAMPLED_YET; + uint32_t pid_eservice_plug_state = NOT_SAMPLED_YET; + uint32_t pid_mainfuse_state = NOT_SAMPLED_YET; + uint32_t pid_most_critical_fault = NOT_SAMPLED_YET; + uint32_t pid_current_time = NOT_SAMPLED_YET; + uint32_t pid_time_sent_by_car = NOT_SAMPLED_YET; + uint32_t pid_12v = 12345; //Initialized to over 12V to not trigger low 12V event + uint32_t pid_12v_abnormal = NOT_SAMPLED_YET; + uint32_t pid_hvil_in_voltage = NOT_SAMPLED_YET; + uint32_t pid_hvil_out_voltage = NOT_SAMPLED_YET; + uint32_t pid_hvil_state = NOT_SAMPLED_YET; + uint32_t pid_bms_state = NOT_SAMPLED_YET; + uint32_t pid_vehicle_speed = NOT_SAMPLED_YET; + uint32_t pid_time_spent_over_55c = NOT_SAMPLED_YET; + uint32_t pid_contactor_closing_counter = NOT_SAMPLED_YET; + uint32_t pid_date_of_manufacture = NOT_SAMPLED_YET; - unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was sent - unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent + unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent + unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was sent + unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was sent + unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent + unsigned long previousMillis250 = 0; // will store last time a 250ms CAN Message was sent + unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was sent + unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was sent + unsigned long previousMillis5000 = 0; // will store last time a 1000ms CAN Message was sent +#define PID_WELD_CHECK 0xD814 +#define PID_CONT_REASON_OPEN 0xD812 +#define PID_CONTACTOR_STATUS 0xD813 +#define PID_NEG_CONT_CONTROL 0xD44F +#define PID_NEG_CONT_STATUS 0xD453 +#define PID_POS_CONT_CONTROL 0xD44E +#define PID_POS_CONT_STATUS 0xD452 +#define PID_CONTACTOR_NEGATIVE 0xD44C +#define PID_CONTACTOR_POSITIVE 0xD44D +#define PID_PRECHARGE_RELAY_CONTROL 0xD44B +#define PID_PRECHARGE_RELAY_STATUS 0xD451 +#define PID_RECHARGE_STATUS 0xD864 +#define PID_DELTA_TEMPERATURE 0xD878 +#define PID_COLDEST_MODULE 0xD446 +#define PID_LOWEST_TEMPERATURE 0xD87D +#define PID_AVERAGE_TEMPERATURE 0xD877 +#define PID_HIGHEST_TEMPERATURE 0xD817 +#define PID_HOTTEST_MODULE 0xD445 +#define PID_AVG_CELL_VOLTAGE 0xD43D +#define PID_CURRENT 0xD816 +#define PID_INSULATION_NEG 0xD87C +#define PID_INSULATION_POS 0xD87B +#define PID_MAX_CURRENT_10S 0xD876 +#define PID_MAX_DISCHARGE_10S 0xD873 +#define PID_MAX_DISCHARGE_30S 0xD874 +#define PID_MAX_CHARGE_10S 0xD871 +#define PID_MAX_CHARGE_30S 0xD872 +#define PID_ENERGY_CAPACITY 0xD860 +#define PID_HIGH_CELL_NUM 0xD43B +#define PID_LOW_CELL_NUM 0xD43C +#define PID_SUM_OF_CELLS 0xD438 +#define PID_CELL_MIN_CAPACITY 0xD413 +#define PID_CELL_VOLTAGE_MEAS_STATUS 0xD48A +#define PID_INSULATION_RES 0xD47A +#define PID_PACK_VOLTAGE 0xD815 +#define PID_HIGH_CELL_VOLTAGE 0xD870 +#define PID_ALL_CELL_VOLTAGES 0xD440 //Multi-frame +#define PID_LOW_CELL_VOLTAGE 0xD86F +#define PID_BATTERY_ENERGY 0xD865 +#define PID_BATTERY_ENERGY 0xD865 +#define PID_CELLBALANCE_STATUS 0xD46F //Multi-frame? +#define PID_CELLBALANCE_HWERR_MASK 0xD470 //Multi-frame +#define PID_CRASH_COUNTER 0xD42F +#define PID_WIRE_CRASH 0xD87F +#define PID_CAN_CRASH 0xD48D +#define PID_HISTORY_DATA 0xD465 +#define PID_LOWSOC_COUNTER 0xD492 //Not supported on all batteris +#define PID_LAST_CAN_FAILURE_DETAIL 0xD89E //Not supported on all batteris +#define PID_HW_VERSION_NUM 0xF193 //Not supported on all batteris +#define PID_SW_VERSION_NUM 0xF195 //Not supported on all batteris +#define PID_FACTORY_MODE_CONTROL 0xD900 +#define PID_BATTERY_SERIAL 0xD901 +#define PID_ALL_CELL_SOH 0xD4B5 //Very long message reply, too much data for this integration +#define PID_AUX_FUSE_STATE 0xD86C +#define PID_BATTERY_STATE 0xD811 +#define PID_PRECHARGE_SHORT_CIRCUIT 0xD4D8 +#define PID_ESERVICE_PLUG_STATE 0xD86A +#define PID_MAINFUSE_STATE 0xD86B +#define PID_MOST_CRITICAL_FAULT 0xD481 +#define PID_CURRENT_TIME 0xD47F +#define PID_TIME_SENT_BY_CAR 0xD4CA +#define PID_12V 0xD822 +#define PID_12V_ABNORMAL 0xD42B +#define PID_HVIL_IN_VOLTAGE 0xD46B +#define PID_HVIL_OUT_VOLTAGE 0xD46A +#define PID_HVIL_STATE 0xD869 +#define PID_BMS_STATE 0xD45A +#define PID_VEHICLE_SPEED 0xD802 +#define PID_TIME_SPENT_OVER_55C 0xE082 +#define PID_CONTACTOR_CLOSING_COUNTER 0xD416 +#define PID_DATE_OF_MANUFACTURE 0xF18B - CAN_frame ECMP_382 = { - .FD = false, //BSI_Info (VCU) PSA specific - .ext_ID = false, - .DLC = 8, - .ID = 0x382, - .data = {0x09, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //09 20 on AC charge. 0A 20 on DC charge - CAN_frame ECMP_0F0 = {.FD = false, //VCU (Common) + uint16_t poll_state = PID_WELD_CHECK; + uint16_t incoming_poll = 0; + + CAN_frame ECMP_010 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x010, .data = {0xB4}}; + CAN_frame ECMP_041 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x041, .data = {0x00}}; + CAN_frame ECMP_0A6 = {.FD = false, + .ext_ID = false, + .DLC = 2, + .ID = 0x0A6, + .data = {0x02, 0x00}}; //Content changes after 12minutes of runtime (not emulated) + CAN_frame ECMP_0F0 = {.FD = false, //VCU2_0F0 (Common) 20ms periodic (Perfectly emulated in Battery-Emulator) .ext_ID = false, .DLC = 8, .ID = 0x0F0, .data = {0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}}; - uint8_t data_0F0_20[16] = {0xFF, 0x0E, 0x1D, 0x2C, 0x3B, 0x4A, 0x59, 0x68, - 0x77, 0x86, 0x95, 0xA4, 0xB3, 0xC2, 0xD1, 0xE0}; - uint8_t data_0F0_00[16] = {0xF1, 0x00, 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, - 0x79, 0x88, 0x97, 0xA6, 0xB5, 0xC4, 0xD3, 0xE2}; + CAN_frame ECMP_0F2 = {.FD = false, //CtrlMCU1_0F2 10ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x0F2, + .data = {0x7D, 0x00, 0x4E, 0x20, 0x00, 0x00, 0x60, 0x0D}}; + CAN_frame ECMP_0AE = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x0AE, .data = {0x04, 0x77, 0x7A, 0x5E, 0xDF}}; + CAN_frame ECMP_110 = {.FD = false, //??? 10ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x110, + .data = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x87, 0x05}}; + CAN_frame ECMP_111 = {.FD = false, //??? 10ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, //Same content always, fully static + .DLC = 8, + .ID = 0x111, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame ECMP_112 = {.FD = false, //MCU1_112 10ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, //Same content always, only CRC changes at end + .DLC = 8, + .ID = 0x112, + .data = {0x4E, 0x20, 0x00, 0x0F, 0xA0, 0x7D, 0x00, 0x0A}}; + CAN_frame ECMP_114 = {.FD = false, //??? 10ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, //Same content always, fully static + .DLC = 8, + .ID = 0x114, + .data = {0x00, 0x00, 0x00, 0x7D, 0x07, 0xD0, 0x7D, 0x00}}; + CAN_frame ECMP_0C5 = {.FD = false, //DC2_0C5 10ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, //Same content always, fully static + .DLC = 8, + .ID = 0x0C5, + .data = {0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame ECMP_17B = {.FD = false, //VCU_PCANInfo_17B 10ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x17B, + .data = {0x00, 0x00, 0x00, 0x7E, 0x78, 0x00, 0x00, 0x0F}}; // NOTE. Changes on BMS state + CAN_frame ECMP_230 = {.FD = false, //OBC3_230 50ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, //Same content always, fully static + .DLC = 8, + .ID = 0x230, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame ECMP_27A = { + .FD = false, //VCU_BSI_Wakeup_27A message 50ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, //Contains SEV main state, position of the BSI shunt park, ACC status + .ID = 0x27A, // electric network state, powetrain status, Wakeups, diagmux, APC activation + .data = {0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame ECMP_31E = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x31E, + .data = {0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08}}; + CAN_frame ECMP_31D = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, //Same content always, fully static + .DLC = 8, + .ID = 0x31D, + .data = {0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42}}; + CAN_frame ECMP_3D0 = {.FD = false, //Not in logs, but makes speed go to 0km/h in diag tool when we send this + .ext_ID = false, //Only sent in idle state + .DLC = 8, + .ID = 0x3D0, + .data = {0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame ECMP_345 = {.FD = false, //DC1_345 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x345, + .data = {0x45, 0x57, 0x00, 0x04, 0x00, 0x00, 0x06, 0x31}}; + CAN_frame ECMP_351 = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x351, + .data = {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0E}}; + CAN_frame ECMP_372 = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x372, + .data = {0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // NOTE. Changes on BMS state + CAN_frame ECMP_37F = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // Seems to be a bunch of temperature measurements? Static for now + .DLC = 8, + .ID = 0x37F, + .data = {0x45, 0x49, 0x51, 0x45, 0x45, 0x00, 0x45, 0x45}}; + CAN_frame ECMP_382 = { + //BSIInfo_382 (VCU) PSA specific 100ms periodic (Perfectly emulated in Battery-Emulator) + .FD = false, //Same content always, fully static + .ext_ID = false, + .DLC = 8, + .ID = 0x382, //Frame1 has rollerbenchmode request, frame2 has generic powertrain cycle sync status + .data = {0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame ECMP_383 = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x383, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame ECMP_3A2 = {.FD = false, //OBC2_3A2 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x3A2, + .data = {0x03, 0xE8, 0x00, 0x00, 0x81, 0x00, 0x08, 0x02}}; + CAN_frame ECMP_3A3 = {.FD = false, //OBC1_3A3 100ms periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x3A3, + .data = {0x4A, 0x4A, 0x40, 0x00, 0x00, 0x08, 0x00, 0x0F}}; + CAN_frame ECMP_439 = {.FD = false, //??? 1s periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, //Same content always, fully static + .DLC = 8, + .ID = 0x439, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame ECMP_486 = {.FD = false, //??? 1s periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, // NOTE. Changes on BMS state + .DLC = 8, + .ID = 0x486, + .data = {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + CAN_frame ECMP_552 = {.FD = false, //VCU_552 1s periodic (Perfectly handled in Battery-Emulator) + .ext_ID = false, + .DLC = 8, //552 seems to be tracking time in byte 0-3 + .ID = 0x552, // distance in km in byte 4-6, temporal reset counter in byte 7 + .data = {0x00, 0x02, 0x95, 0x6D, 0x00, 0xD7, 0xB5, 0xFE}}; + CAN_frame ECMP_55F = {.FD = false, //5s periodic (Perfectly emulated in Battery-Emulator) + .ext_ID = false, //Same content always, fully static + .DLC = 1, + .ID = 0x55F, + .data = {0x82}}; + CAN_frame ECMP_591 = {.FD = false, //1s periodic + .ext_ID = false, //Always static in HV mode + .DLC = 8, + .ID = 0x591, + .data = {0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + CAN_frame ECMP_786 = {.FD = false, //1s periodic + .ext_ID = false, //Always static in HV mode + .DLC = 8, + .ID = 0x786, + .data = {0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + CAN_frame ECMP_794 = {.FD = false, //Unsure who sends this. Could it be BMU? + .ext_ID = false, + .DLC = 8, + .ID = 0x794, + .data = {0xB8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; // NOTE. Changes on BMS state + CAN_frame ECMP_POLL = {.FD = false, .ext_ID = false, .DLC = 4, .ID = 0x6B4, .data = {0x03, 0x22, 0xD8, 0x66}}; + CAN_frame ECMP_ACK = {.FD = false, //Ack frame + .ext_ID = false, + .DLC = 3, + .ID = 0x6B4, + .data = {0x30, 0x00, 0x00}}; + CAN_frame ECMP_DIAG_START = {.FD = false, .ext_ID = false, .DLC = 3, .ID = 0x6B4, .data = {0x02, 0x10, 0x03}}; + //Start diagnostic session (extended diagnostic session, mode 0x10 with sub-mode 0x03) + CAN_frame ECMP_CONTACTOR_RESET_START = {.FD = false, + .ext_ID = false, + .DLC = 5, + .ID = 0x6B4, + .data = {0x04, 0x31, 0x01, 0xDD, 0x35}}; + CAN_frame ECMP_CONTACTOR_RESET_PROGRESS = {.FD = false, + .ext_ID = false, + .DLC = 5, + .ID = 0x6B4, + .data = {0x04, 0x31, 0x03, 0xDD, 0x35}}; + CAN_frame ECMP_COLLISION_RESET_START = {.FD = false, + .ext_ID = false, + .DLC = 5, + .ID = 0x6B4, + .data = {0x04, 0x31, 0x01, 0xDF, 0x60}}; + CAN_frame ECMP_COLLISION_RESET_PROGRESS = {.FD = false, + .ext_ID = false, + .DLC = 5, + .ID = 0x6B4, + .data = {0x04, 0x31, 0x03, 0xDF, 0x60}}; + CAN_frame ECMP_ISOLATION_RESET_START = {.FD = false, + .ext_ID = false, + .DLC = 5, + .ID = 0x6B4, + .data = {0x04, 0x31, 0x01, 0xDF, 0x46}}; + CAN_frame ECMP_ISOLATION_RESET_PROGRESS = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x6B4, + .data = {0x04, 0x31, 0x03, 0xDF, 0x46}}; + CAN_frame ECMP_RESET_DONE = {.FD = false, .ext_ID = false, .DLC = 3, .ID = 0x6B4, .data = {0x02, 0x3E, 0x00}}; + CAN_frame ECMP_FACTORY_MODE_ACTIVATION = {.FD = false, + .ext_ID = false, + .DLC = 5, + .ID = 0x6B4, + .data = {0x04, 0x2E, 0xD9, 0x00, 0x01}}; + CAN_frame ECMP_FACTORY_MODE_ACTIVATION_NEW = {.FD = false, + .ext_ID = false, + .DLC = 4, + .ID = 0x6B4, + .data = {0x04, 0x2E, 0x19, 0x01}}; + CAN_frame ECMP_DISABLE_ISOLATION_REQ = {.FD = false, + .ext_ID = false, + .DLC = 5, + .ID = 0x6B4, + .data = {0x04, 0x31, 0x02, 0xDF, 0xE1}}; + uint8_t data_010_CRC[8] = {0xB4, 0x96, 0x78, 0x5A, 0x3C, 0x1E, 0xF0, 0xD2}; + uint8_t data_3A2_CRC[16] = {0x0C, 0x1B, 0x2A, 0x39, 0x48, 0x57, + 0x66, 0x75, 0x84, 0x93, 0xA2, 0xB1}; // NOTE. Changes on BMS state + uint8_t data_345_content[16] = {0x04, 0xF5, 0xE6, 0xD7, 0xC8, 0xB9, 0xAA, 0x9B, // NOTE. Changes on BMS state + 0x8C, 0x7D, 0x6E, 0x5F, 0x40, 0x31, 0x22, 0x13}; }; - #endif diff --git a/Software/src/battery/ECMP-HTML.h b/Software/src/battery/ECMP-HTML.h index aa09aa54..7a98a42a 100644 --- a/Software/src/battery/ECMP-HTML.h +++ b/Software/src/battery/ECMP-HTML.h @@ -1,5 +1,5 @@ -#ifndef _ECMP_HTML_H -#define _ECMP_HTML_H +#ifndef _ECMP_BATTERY_HTML_H +#define _ECMP_BATTERT_HTML_H #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" @@ -9,7 +9,6 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer { public: String get_status_html() { String content; - content += "

Main Connector State: "; if (datalayer_extended.stellantisECMP.MainConnectorState == 0) { content += "Contactors open

"; @@ -20,6 +19,363 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer { } content += "

Insulation Resistance: " + String(datalayer_extended.stellantisECMP.InsulationResistance) + "kOhm

"; + content += "

Interlock: "; + if (datalayer_extended.stellantisECMP.InterlockOpen == true) { + content += "BROKEN!

"; + } else { + content += "Seated OK"; + } + content += "

Insulation Diag: "; + if (datalayer_extended.stellantisECMP.InsulationDiag == 0) { + content += "No failure

"; + } else if (datalayer_extended.stellantisECMP.InsulationDiag == 1) { + content += "Symmetric failure"; + } else { //4 Invalid, 5-7 illegal, wrap em under one text + content += "N/A"; + } + content += "

Contactor weld check: "; + if (datalayer_extended.stellantisECMP.pid_welding_detection == 0) { + content += "OK

"; + } else if (datalayer_extended.stellantisECMP.pid_welding_detection == 255) { + content += "N/A"; + } else { //Problem + content += "WELDED!" + String(datalayer_extended.stellantisECMP.pid_welding_detection) + ""; + } + + content += "

Contactor opening reason: "; + if (datalayer_extended.stellantisECMP.pid_reason_open == 7) { + content += "Invalid Status

"; + } else if (datalayer_extended.stellantisECMP.pid_reason_open == 255) { + content += "N/A"; + } else { //Problem (Also status 0 might be OK?) + content += "Unknown" + String(datalayer_extended.stellantisECMP.pid_reason_open) + ""; + } + + content += "

Status of power switch: " + + (datalayer_extended.stellantisECMP.pid_contactor_status == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_contactor_status)) + + "

"; + content += "

Negative power switch control: " + + (datalayer_extended.stellantisECMP.pid_negative_contactor_control == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_negative_contactor_control)) + + "

"; + content += "

Negative power switch status: " + + (datalayer_extended.stellantisECMP.pid_negative_contactor_status == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_negative_contactor_status)) + + "

"; + content += "

Positive power switch control: " + + (datalayer_extended.stellantisECMP.pid_positive_contactor_control == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_positive_contactor_control)) + + "

"; + content += "

Positive power switch status: " + + (datalayer_extended.stellantisECMP.pid_positive_contactor_status == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_positive_contactor_status)) + + "

"; + content += "

Contactor negative: " + + (datalayer_extended.stellantisECMP.pid_contactor_negative == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_contactor_negative)) + + "

"; + content += "

Contactor positive: " + + (datalayer_extended.stellantisECMP.pid_contactor_positive == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_contactor_positive)) + + "

"; + content += "

Precharge control: " + + (datalayer_extended.stellantisECMP.pid_precharge_relay_control == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_precharge_relay_control)) + + "

"; + content += "

Precharge status: " + + (datalayer_extended.stellantisECMP.pid_precharge_relay_status == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_precharge_relay_status)) + + "

"; + content += "

Recharge Status: " + + (datalayer_extended.stellantisECMP.pid_recharge_status == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_recharge_status)) + + "

"; + content += "

Delta temperature: " + + (datalayer_extended.stellantisECMP.pid_delta_temperature == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_delta_temperature)) + + "°C

"; + content += "

Lowest temperature: " + + (datalayer_extended.stellantisECMP.pid_lowest_temperature == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_lowest_temperature)) + + "°C

"; + content += "

Average temperature: " + + (datalayer_extended.stellantisECMP.pid_average_temperature == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_average_temperature)) + + "°C

"; + content += "

Highest temperature: " + + (datalayer_extended.stellantisECMP.pid_highest_temperature == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_highest_temperature)) + + "°C

"; + content += "

Coldest module: " + + (datalayer_extended.stellantisECMP.pid_coldest_module == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_coldest_module)) + + "

"; + content += "

Hottest module: " + + (datalayer_extended.stellantisECMP.pid_hottest_module == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_hottest_module)) + + "

"; + content += "

Average cell voltage: " + + (datalayer_extended.stellantisECMP.pid_avg_cell_voltage == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_avg_cell_voltage)) + + " mV

"; + content += + "

High precision current: " + + (datalayer_extended.stellantisECMP.pid_current == 255 ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_current)) + + " mA

"; + content += "

Insulation resistance neg-gnd: " + + (datalayer_extended.stellantisECMP.pid_insulation_res_neg == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_insulation_res_neg)) + + " kOhm

"; + content += "

Insulation resistance pos-gnd: " + + (datalayer_extended.stellantisECMP.pid_insulation_res_pos == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_insulation_res_pos)) + + " kOhm

"; + content += "

Max current 10s: " + + (datalayer_extended.stellantisECMP.pid_max_current_10s == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_max_current_10s)) + + "

"; + content += "

Max discharge power 10s: " + + (datalayer_extended.stellantisECMP.pid_max_discharge_10s == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_max_discharge_10s)) + + "

"; + content += "

Max discharge power 30s: " + + (datalayer_extended.stellantisECMP.pid_max_discharge_30s == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_max_discharge_30s)) + + "

"; + content += "

Max charge power 10s: " + + (datalayer_extended.stellantisECMP.pid_max_charge_10s == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_max_charge_10s)) + + "

"; + content += "

Max charge power 30s: " + + (datalayer_extended.stellantisECMP.pid_max_charge_30s == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_max_charge_30s)) + + "

"; + content += "

Energy capacity: " + + (datalayer_extended.stellantisECMP.pid_energy_capacity == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_energy_capacity)) + + "

"; + content += "

Highest cell number: " + + (datalayer_extended.stellantisECMP.pid_highest_cell_voltage_num == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_highest_cell_voltage_num)) + + "

"; + content += "

Lowest cell voltage number: " + + (datalayer_extended.stellantisECMP.pid_lowest_cell_voltage_num == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_lowest_cell_voltage_num)) + + "

"; + content += "

Sum of all cell voltages: " + + (datalayer_extended.stellantisECMP.pid_sum_of_cells == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_sum_of_cells)) + + " dV

"; + content += "

Cell min capacity: " + + (datalayer_extended.stellantisECMP.pid_cell_min_capacity == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_cell_min_capacity)) + + "

"; + content += "

Cell voltage measurement status: " + + (datalayer_extended.stellantisECMP.pid_cell_voltage_measurement_status == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_cell_voltage_measurement_status)) + + "

"; + content += "

Battery Insulation Resistance: " + + (datalayer_extended.stellantisECMP.pid_insulation_res == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_insulation_res)) + + " kOhm

"; + content += "

Pack voltage: " + + (datalayer_extended.stellantisECMP.pid_pack_voltage == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_pack_voltage)) + + " dV

"; + content += "

Highest cell voltage: " + + (datalayer_extended.stellantisECMP.pid_high_cell_voltage == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_high_cell_voltage)) + + " mV

"; + content += "

Lowest cell voltage: " + + (datalayer_extended.stellantisECMP.pid_low_cell_voltage == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_low_cell_voltage)) + + " mV

"; + content += "

Battery Energy: " + + (datalayer_extended.stellantisECMP.pid_battery_energy == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_battery_energy)) + + "

"; + content += "

Collision information Counter: " + + (datalayer_extended.stellantisECMP.pid_crash_counter == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_crash_counter)) + + "

"; + content += "

Collision Counter recieved by Wire: " + + (datalayer_extended.stellantisECMP.pid_wire_crash == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_wire_crash)) + + "

"; + content += "

Collision data sent from car to battery: " + + (datalayer_extended.stellantisECMP.pid_CAN_crash == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_CAN_crash)) + + "

"; + content += "

History data: " + + (datalayer_extended.stellantisECMP.pid_history_data == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_history_data)) + + "

"; + content += "

Low SOC counter: " + + (datalayer_extended.stellantisECMP.pid_lowsoc_counter == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_lowsoc_counter)) + + "

"; + content += "

Last CAN failure detail: " + + (datalayer_extended.stellantisECMP.pid_last_can_failure_detail == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_last_can_failure_detail)) + + "

"; + content += "

HW version number: " + + (datalayer_extended.stellantisECMP.pid_hw_version_num == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_hw_version_num)) + + "

"; + content += "

SW version number: " + + (datalayer_extended.stellantisECMP.pid_sw_version_num == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_sw_version_num)) + + "

"; + content += "

Factory mode: " + + (datalayer_extended.stellantisECMP.pid_factory_mode_control == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_factory_mode_control)) + + "

"; + char readableSerialNumber[14]; // One extra space for null terminator + memcpy(readableSerialNumber, datalayer_extended.stellantisECMP.pid_battery_serial, + sizeof(datalayer_extended.stellantisECMP.pid_battery_serial)); + readableSerialNumber[13] = '\0'; // Null terminate the string + content += "

Battery serial: " + String(readableSerialNumber) + "

"; + uint8_t day = (datalayer_extended.stellantisECMP.pid_date_of_manufacture >> 16) & 0xFF; + uint8_t month = (datalayer_extended.stellantisECMP.pid_date_of_manufacture >> 8) & 0xFF; + uint8_t year = datalayer_extended.stellantisECMP.pid_date_of_manufacture & 0xFF; + content += "

Date of manufacture: " + String(day) + "/" + String(month) + "/" + String(year) + "

"; + content += "

Aux fuse state: " + + (datalayer_extended.stellantisECMP.pid_aux_fuse_state == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_aux_fuse_state)) + + "

"; + content += "

Battery state: " + + (datalayer_extended.stellantisECMP.pid_battery_state == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_battery_state)) + + "

"; + content += "

Precharge short circuit: " + + (datalayer_extended.stellantisECMP.pid_precharge_short_circuit == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_precharge_short_circuit)) + + "

"; + content += "

Service plug state: " + + (datalayer_extended.stellantisECMP.pid_eservice_plug_state == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_eservice_plug_state)) + + "

"; + content += "

Main fuse state: " + + (datalayer_extended.stellantisECMP.pid_mainfuse_state == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_mainfuse_state)) + + "

"; + content += "

Most critical fault: " + + (datalayer_extended.stellantisECMP.pid_most_critical_fault == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_most_critical_fault)) + + "

"; + content += "

Current time: " + + (datalayer_extended.stellantisECMP.pid_current_time == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_current_time)) + + " ticks

"; + content += "

Time sent by car: " + + (datalayer_extended.stellantisECMP.pid_time_sent_by_car == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_time_sent_by_car)) + + " ticks

"; + content += + "

12V: " + + (datalayer_extended.stellantisECMP.pid_12v == 255 ? "N/A" : String(datalayer_extended.stellantisECMP.pid_12v)) + + "

"; + content += "

12V abnormal: "; + if (datalayer_extended.stellantisECMP.pid_12v_abnormal == 255) { + content += "N/A

"; + } else if (datalayer_extended.stellantisECMP.pid_12v_abnormal == 0) { + content += "No"; + } else { + content += "Yes"; + } + content += "

HVIL IN Voltage: " + + (datalayer_extended.stellantisECMP.pid_hvil_in_voltage == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_hvil_in_voltage)) + + "mV

"; + content += "

HVIL Out Voltage: " + + (datalayer_extended.stellantisECMP.pid_hvil_out_voltage == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_hvil_out_voltage)) + + "mV

"; + content += "

HVIL State: " + + (datalayer_extended.stellantisECMP.pid_hvil_state == 255 + ? "N/A" + : (datalayer_extended.stellantisECMP.pid_hvil_state == 0 + ? "OK" + : String(datalayer_extended.stellantisECMP.pid_hvil_state))) + + "

"; + content += "

BMS State: " + + (datalayer_extended.stellantisECMP.pid_bms_state == 255 + ? "N/A" + : (datalayer_extended.stellantisECMP.pid_bms_state == 0 + ? "OK" + : String(datalayer_extended.stellantisECMP.pid_bms_state))) + + "

"; + content += "

Vehicle speed: " + + (datalayer_extended.stellantisECMP.pid_vehicle_speed == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_vehicle_speed)) + + " km/h

"; + content += "

Time spent over 55c: " + + (datalayer_extended.stellantisECMP.pid_time_spent_over_55c == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_time_spent_over_55c)) + + " minutes

"; + content += "

Contactor lifetime closing counter: " + + (datalayer_extended.stellantisECMP.pid_contactor_closing_counter == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_contactor_closing_counter)) + + " cycles

"; return content; } diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 0ada9d70..26b48c5c 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -297,6 +297,78 @@ typedef struct { typedef struct { uint8_t MainConnectorState = 0; uint16_t InsulationResistance = 0; + uint8_t InsulationDiag = 0; + bool InterlockOpen = false; + bool UserRequestContactorReset = false; + bool UserRequestCollisionReset = false; + bool UserRequestIsolationReset = false; + bool UserRequestDisableIsoMonitoring = false; + uint8_t pid_welding_detection = 0; + uint8_t pid_reason_open = 0; + uint8_t pid_contactor_status = 0; + uint8_t pid_negative_contactor_control = 0; + uint8_t pid_negative_contactor_status = 0; + uint8_t pid_positive_contactor_control = 0; + uint8_t pid_positive_contactor_status = 0; + uint8_t pid_contactor_negative = 0; + uint8_t pid_contactor_positive = 0; + uint8_t pid_precharge_relay_control = 0; + uint8_t pid_precharge_relay_status = 0; + uint8_t pid_recharge_status = 0; + uint8_t pid_delta_temperature = 0; + uint8_t pid_coldest_module = 0; + uint8_t pid_lowest_temperature = 0; + uint8_t pid_average_temperature = 0; + uint8_t pid_highest_temperature = 0; + uint8_t pid_hottest_module = 0; + uint16_t pid_avg_cell_voltage = 0; + int32_t pid_current = 0; + uint32_t pid_insulation_res_neg = 0; + uint32_t pid_insulation_res_pos = 0; + uint32_t pid_max_current_10s = 0; + uint32_t pid_max_discharge_10s = 0; + uint32_t pid_max_discharge_30s = 0; + uint32_t pid_max_charge_10s = 0; + uint32_t pid_max_charge_30s = 0; + uint32_t pid_energy_capacity = 0; + uint8_t pid_highest_cell_voltage_num = 0; + uint8_t pid_lowest_cell_voltage_num = 0; + uint16_t pid_sum_of_cells = 0; + uint16_t pid_cell_min_capacity = 0; + uint8_t pid_cell_voltage_measurement_status = 0; + uint32_t pid_insulation_res = 0; + uint16_t pid_pack_voltage = 0; + uint16_t pid_high_cell_voltage = 0; + uint16_t pid_low_cell_voltage = 0; + uint8_t pid_battery_energy = 0; + uint32_t pid_crash_counter = 0; + uint8_t pid_wire_crash = 0; + uint8_t pid_CAN_crash = 0; + uint32_t pid_history_data = 0; + uint32_t pid_lowsoc_counter = 0; + uint32_t pid_last_can_failure_detail = 0; + uint32_t pid_hw_version_num = 0; + uint32_t pid_sw_version_num = 0; + uint32_t pid_factory_mode_control = 0; + uint8_t pid_battery_serial[13] = {0}; + uint32_t pid_aux_fuse_state = 0; + uint32_t pid_battery_state = 0; + uint32_t pid_precharge_short_circuit = 0; + uint32_t pid_eservice_plug_state = 0; + uint32_t pid_mainfuse_state = 0; + uint32_t pid_most_critical_fault = 0; + uint32_t pid_current_time = 0; + uint32_t pid_time_sent_by_car = 0; + uint32_t pid_12v = 0; + uint32_t pid_12v_abnormal = 0; + uint32_t pid_hvil_in_voltage = 0; + uint32_t pid_hvil_out_voltage = 0; + uint32_t pid_hvil_state = 0; + uint32_t pid_bms_state = 0; + uint32_t pid_vehicle_speed = 0; + uint32_t pid_time_spent_over_55c = 0; + uint32_t pid_contactor_closing_counter = 0; + uint32_t pid_date_of_manufacture = 0; } DATALAYER_INFO_ECMP; typedef struct { diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index fab882b6..40eb4970 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -28,6 +28,11 @@ std::vector battery_commands = { [](Battery* b) { b->reset_NVROL(); }}, + {"resetContactor", "Perform contactor reset", "reset contactors?", + [](Battery* b) { return b && b->supports_contactor_reset(); }, + [](Battery* b) { + b->reset_contactor(); + }}, {"resetDTC", "Erase DTC", "erase DTCs?", [](Battery* b) { return b && b->supports_reset_DTC(); }, [](Battery* b) { b->reset_DTC(); @@ -56,6 +61,11 @@ std::vector battery_commands = { [](Battery* b) { b->reset_SOH(); }}, + {"setFactoryMode", "Set Factory Mode", "set factory mode and disable isolation measurement?", + [](Battery* b) { return b && b->supports_factory_mode_method(); }, + [](Battery* b) { + b->set_factory_mode(); + }}, {"toggleSOC", "Toggle SOC method", "toggle SOC method? This will toggle between ESTIMATED and MEASURED SOC methods.", [](Battery* b) { return b && b->supports_toggle_SOC_method(); }, diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 0cbc0838..6c55a316 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -480,7 +480,7 @@ void init_webserver() { if (request->hasParam("stop")) { String valueStr = request->getParam("stop")->value(); if (valueStr == "true" || valueStr == "1") { - setBatteryPause(true, false, true); + setBatteryPause(true, false, true); //Pause battery, do not pause CAN, equipment stop on (store to flash) } else { setBatteryPause(false, false, false); } @@ -1444,7 +1444,7 @@ String processor(const String& var) { content += "


"; else @@ -1452,7 +1452,8 @@ String processor(const String& var) { "


"; content += "