From 95ee6ff9ae6f6db0dd9c6ed73a7633c02c1ded4c Mon Sep 17 00:00:00 2001 From: James Brookes Date: Thu, 25 Sep 2025 19:03:54 +0100 Subject: [PATCH 1/5] Add events for BMS_a145_SW_SOC_Change, BMS reset and SOC reset --- Software/src/battery/TESLA-BATTERY.cpp | 64 ++++++++++++++++++-------- Software/src/devboard/utils/events.cpp | 13 +++++- Software/src/devboard/utils/events.h | 5 ++ 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 7700e685..bc7b3761 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -483,11 +483,17 @@ void TeslaBattery:: } else { clear_event(EVENT_BATTERY_FUSE); } + // Raise any informational Tesla BMS events in BE + if (BMS_a145_SW_SOC_Change == true) { // BMS has recalibrated pack SOC + set_event(EVENT_BATTERY_SOC_RECALIBRATION, 0); + } else { + clear_event(EVENT_BATTERY_SOC_RECALIBRATION); + } if (user_selected_tesla_GTW_chassisType > 1) { //{{0, "Model S"}, {1, "Model X"}, {2, "Model 3"}, {3, "Model Y"}}; - // Autodetect algoritm for chemistry on 3/Y packs. + // Autodetect algorithm for chemistry on 3/Y packs. // NCM/A batteries have 96s, LFP has 102-108s - // Drawback with this check is that it takes 3-5minutes before all cells have been counted! + // Drawback with this check is that it takes 3-5 minutes before all cells have been counted! if (datalayer.battery.info.number_of_cells > 101) { datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; } @@ -528,23 +534,28 @@ void TeslaBattery:: //Start the BMS ECU reset statemachine, only if contactors are OPEN and BMS ECU allows it stateMachineBMSReset = 0; datalayer.battery.settings.user_requests_tesla_bms_reset = false; - logging.println("BMS reset requested"); + logging.println("INFO: BMS reset requested"); } else { logging.println("ERROR: BMS reset failed due to contactors not being open, or BMS ECU not allowing it"); stateMachineBMSReset = 0xFF; datalayer.battery.settings.user_requests_tesla_bms_reset = false; + set_event(EVENT_BMS_RESET_REQ_FAIL, 0); + clear_event(EVENT_BMS_RESET_REQ_FAIL); } } if (datalayer.battery.settings.user_requests_tesla_soc_reset) { - if (datalayer.battery.status.real_soc < 1500 || datalayer.battery.status.real_soc > 9000) { - //Start the SOC reset statemachine, only if SOC < 15% or > 90% + if ((datalayer.battery.status.real_soc < 1500 || datalayer.battery.status.real_soc > 9000) && + battery_contactor == 1) { + //Start the SOC reset statemachine, only if SOC less than 15% or greater than 90%, and contactors open stateMachineSOCReset = 0; datalayer.battery.settings.user_requests_tesla_soc_reset = false; - logging.println("SOC reset requested"); + logging.println("INFO: SOC reset requested"); } else { - logging.println("ERROR: SOC reset failed due to SOC not being less than 15 or greater than 90"); + logging.println("ERROR: SOC reset failed, SOC not < 15 or > 90"); stateMachineSOCReset = 0xFF; datalayer.battery.settings.user_requests_tesla_soc_reset = false; + set_event(EVENT_BATTERY_SOC_RESET_FAIL, 0); + clear_event(EVENT_BATTERY_SOC_RESET_FAIL); } } @@ -779,7 +790,7 @@ void TeslaBattery:: datalayer_extended.tesla.HVP_shuntBarTempStatus = HVP_shuntBarTempStatus; datalayer_extended.tesla.HVP_shuntAsicTempStatus = HVP_shuntAsicTempStatus; - //Safety checks for CAN message sesnding + //Safety checks for CAN message sending if ((datalayer.system.status.inverter_allows_contactor_closing == true) && (datalayer.battery.status.bms_status != FAULT) && (!datalayer.system.settings.equipment_stop_active)) { // Carry on: 0x221 DRIVE state & reset power down timer @@ -1667,10 +1678,10 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) { } */ break; - case 0x612: // CAN UDSs for BMS + case 0x612: // CAN UDS responses for BMS datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //BMS Query - if (stateMachineBMSQuery != 0xFF && stateMachineBMSReset == 0xFF) { + if (stateMachineBMSQuery != 0xFF && stateMachineBMSReset == 0xFF && stateMachineSOCReset == 0xFF) { if (memcmp(rx_frame.data.u8, "\x02\x50\x03\xAA\xAA\xAA\xAA\xAA", 8) == 0) { //Received initial response, proceed to actual query logging.println("CAN UDS: Received BMS query initial handshake reply"); @@ -1713,15 +1724,28 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) { break; } } - //BMS Reset - if (stateMachineBMSQuery == 0xFF) { // Make sure this is reset request not query - if (memcmp(rx_frame.data.u8, "\x02\x67\x06\xAA\xAA\xAA\xAA\xAA", 8) == 0) { - logging.println("CAN UDS: ECU unlocked"); - } else if (memcmp(rx_frame.data.u8, "\x03\x7F\x11\x78\xAA\xAA\xAA\xAA", 8) == 0) { - logging.println("CAN UDS: ECU reset request successful but ECU busy, response pending"); - } else if (memcmp(rx_frame.data.u8, "\x02\x51\x01\xAA\xAA\xAA\xAA\xAA", 8) == 0) { - logging.println("CAN UDS: ECU reset positive response, 1 second downtime"); - } + //BMS ECU responses + if (memcmp(rx_frame.data.u8, "\x02\x67\x06\xAA\xAA\xAA\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS ECU unlocked"); + } + if (memcmp(rx_frame.data.u8, "\x03\x7F\x11\x78\xAA\xAA\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS ECU reset request successful but ECU busy, response pending"); + } + if (memcmp(rx_frame.data.u8, "\x02\x51\x01\xAA\xAA\xAA\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS ECU reset positive response, 1 second downtime"); + set_event(EVENT_BMS_RESET_REQ_SUCCESS, 0); + clear_event(EVENT_BMS_RESET_REQ_SUCCESS); + } + if (memcmp(rx_frame.data.u8, "\x05\x71\x01\x04\x07\x01\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS SOC reset accepted, resetting BMS ECU"); + set_event(EVENT_BATTERY_SOC_RESET_SUCCESS, 0); + clear_event(EVENT_BATTERY_SOC_RESET_SUCCESS); + stateMachineBMSReset = 6; // BMS ECU already unlocked etc. so we jump straight to reset + } + if (memcmp(rx_frame.data.u8, "\x05\x71\x01\x04\x07\x00\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS SOC reset failed"); + set_event(EVENT_BATTERY_SOC_RESET_FAIL, 0); + clear_event(EVENT_BATTERY_SOC_RESET_FAIL); } break; default: @@ -2308,7 +2332,7 @@ void TeslaBattery::printFaultCodesIfActive() { printDebugIfActive(BMS_a139_SW_DC_Link_V_Irrational, "ERROR: BMS_a139_SW_DC_Link_V_Irrational"); printDebugIfActive(BMS_a141_SW_BMB_Status_Warning, "ERROR: BMS_a141_SW_BMB_Status_Warning"); printDebugIfActive(BMS_a144_Hvp_Config_Mismatch, "ERROR: BMS_a144_Hvp_Config_Mismatch"); - printDebugIfActive(BMS_a145_SW_SOC_Change, "ERROR: BMS_a145_SW_SOC_Change"); + printDebugIfActive(BMS_a145_SW_SOC_Change, "INFO: BMS_a145_SW_SOC_Change"); printDebugIfActive(BMS_a146_SW_Brick_Overdischarged, "ERROR: BMS_a146_SW_Brick_Overdischarged"); printDebugIfActive(BMS_a149_SW_Missing_Config_Block, "ERROR: BMS_a149_SW_Missing_Config_Block"); printDebugIfActive(BMS_a151_SW_external_isolation, "ERROR: BMS_a151_SW_external_isolation"); diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index d6875aab..6af46dcf 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -67,6 +67,9 @@ void init_events(void) { events.entries[EVENT_BATTERY_UNDERVOLTAGE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_BATTERY_VALUE_UNAVAILABLE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_BATTERY_ISOLATION].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_BATTERY_SOC_RECALIBRATION].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BATTERY_SOC_RESET_SUCCESS].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BATTERY_SOC_RESET_FAIL].level = EVENT_LEVEL_INFO; events.entries[EVENT_VOLTAGE_DIFFERENCE].level = EVENT_LEVEL_INFO; events.entries[EVENT_SOH_DIFFERENCE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_SOH_LOW].level = EVENT_LEVEL_ERROR; @@ -124,6 +127,8 @@ void init_events(void) { events.entries[EVENT_EQUIPMENT_STOP].level = EVENT_LEVEL_ERROR; events.entries[EVENT_SD_INIT_FAILED].level = EVENT_LEVEL_WARNING; events.entries[EVENT_PERIODIC_BMS_RESET].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BMS_RESET_REQ_SUCCESS].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BMS_RESET_REQ_FAIL].level = EVENT_LEVEL_INFO; events.entries[EVENT_BATTERY_TEMP_DEVIATION_HIGH].level = EVENT_LEVEL_WARNING; events.entries[EVENT_GPIO_CONFLICT].level = EVENT_LEVEL_ERROR; events.entries[EVENT_GPIO_NOT_DEFINED].level = EVENT_LEVEL_ERROR; @@ -244,6 +249,8 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { return "Battery measurement unavailable. Check 12V power supply and battery wiring!"; case EVENT_BATTERY_ISOLATION: return "Battery reports isolation error. High voltage might be leaking to ground. Check battery!"; + case EVENT_BATTERY_SOC_RECALIBRATION: + return "The BMS updated the HV battery State of Charge (SOC) by more than 3% based on SocByOcv."; case EVENT_VOLTAGE_DIFFERENCE: return "Too large voltage diff between the batteries. Second battery cannot join the DC-link"; case EVENT_SOH_DIFFERENCE: @@ -361,7 +368,11 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { case EVENT_SD_INIT_FAILED: return "SD card initialization failed, check hardware. Power must be removed to reset the SD card."; case EVENT_PERIODIC_BMS_RESET: - return "BMS Reset Event Completed."; + return "BMS reset event completed."; + case EVENT_BMS_RESET_REQ_SUCCESS: + return "BMS reset request completed successfully."; + case EVENT_BMS_RESET_REQ_FAIL: + return "BMS reset request failed - check contactors are open."; case EVENT_GPIO_CONFLICT: return "GPIO Pin Conflict: The pin used by '" + esp32hal->failed_allocator() + "' is already allocated by '" + esp32hal->conflicting_allocator() + "'. Please check your configuration and assign different pins."; diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 8f85b13b..3f4090be 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -49,6 +49,9 @@ XX(EVENT_BATTERY_ISOLATION) \ XX(EVENT_BATTERY_REQUESTS_HEAT) \ XX(EVENT_BATTERY_WARMED_UP) \ + XX(EVENT_BATTERY_SOC_RECALIBRATION) \ + XX(EVENT_BATTERY_SOC_RESET_SUCCESS) \ + XX(EVENT_BATTERY_SOC_RESET_FAIL) \ XX(EVENT_VOLTAGE_DIFFERENCE) \ XX(EVENT_SOH_DIFFERENCE) \ XX(EVENT_SOH_LOW) \ @@ -107,6 +110,8 @@ XX(EVENT_AUTOMATIC_PRECHARGE_FAILURE) \ XX(EVENT_SD_INIT_FAILED) \ XX(EVENT_PERIODIC_BMS_RESET) \ + XX(EVENT_BMS_RESET_REQ_SUCCESS) \ + XX(EVENT_BMS_RESET_REQ_FAIL) \ XX(EVENT_BATTERY_TEMP_DEVIATION_HIGH) \ XX(EVENT_GPIO_NOT_DEFINED) \ XX(EVENT_GPIO_CONFLICT) \ From c6b7ff82c06fec675fd40aed516643d83ee26d37 Mon Sep 17 00:00:00 2001 From: James Brookes Date: Thu, 25 Sep 2025 19:09:46 +0100 Subject: [PATCH 2/5] Alter BMS_a145_SW_SOC_Change event to once only --- Software/src/battery/TESLA-BATTERY.cpp | 6 ++++-- Software/src/battery/TESLA-BATTERY.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index bc7b3761..56a152b1 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -484,10 +484,12 @@ void TeslaBattery:: clear_event(EVENT_BATTERY_FUSE); } // Raise any informational Tesla BMS events in BE - if (BMS_a145_SW_SOC_Change == true) { // BMS has recalibrated pack SOC + if (BMS_a145_SW_SOC_Change == true && !BMS_SW_SOC_Change_Latch) { // BMS has newly recalibrated pack SOC + BMS_SW_SOC_Change_Latch = true; // Only set event once, BMS_a145 can be active for a while set_event(EVENT_BATTERY_SOC_RECALIBRATION, 0); - } else { clear_event(EVENT_BATTERY_SOC_RECALIBRATION); + } else if (BMS_a145_SW_SOC_Change == false) { + BMS_SW_SOC_Change_Latch = false; } if (user_selected_tesla_GTW_chassisType > 1) { //{{0, "Model S"}, {1, "Model X"}, {2, "Model 3"}, {3, "Model Y"}}; diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 9d599eba..8abc15db 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -877,6 +877,7 @@ class TeslaBattery : public CanBattery { bool BMS_a141_SW_BMB_Status_Warning = false; bool BMS_a144_Hvp_Config_Mismatch = false; bool BMS_a145_SW_SOC_Change = false; + bool BMS_SW_SOC_Change_Latch = false; bool BMS_a146_SW_Brick_Overdischarged = false; bool BMS_a149_SW_Missing_Config_Block = false; bool BMS_a151_SW_external_isolation = false; From 04d9a362925eb51cf4b2cd15459bd91e725b25d0 Mon Sep 17 00:00:00 2001 From: James Brookes Date: Fri, 26 Sep 2025 10:38:56 +0100 Subject: [PATCH 3/5] Add event and logging text for SOC Reset --- Software/src/devboard/utils/events.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 6af46dcf..57882def 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -251,6 +251,10 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { return "Battery reports isolation error. High voltage might be leaking to ground. Check battery!"; case EVENT_BATTERY_SOC_RECALIBRATION: return "The BMS updated the HV battery State of Charge (SOC) by more than 3% based on SocByOcv."; + case EVENT_BATTERY_SOC_RESET_SUCCESS: + return "SOC reset routine was successful."; + case EVENT_BATTERY_SOC_RESET_FAIL: + return "SOC reset routine failed - check SOC is < 15 or > 90, and contactors are open."; case EVENT_VOLTAGE_DIFFERENCE: return "Too large voltage diff between the batteries. Second battery cannot join the DC-link"; case EVENT_SOH_DIFFERENCE: From 706b4a7cea568e9ee81a2cf5df7297b58dd3a899 Mon Sep 17 00:00:00 2001 From: James Brookes Date: Sat, 27 Sep 2025 18:03:56 +0100 Subject: [PATCH 4/5] Add contactor weld warning event, change events to native latch type --- Software/src/battery/TESLA-BATTERY.cpp | 19 ++++++++++++------- Software/src/battery/TESLA-BATTERY.h | 1 - 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 56a152b1..76465228 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -483,13 +483,18 @@ void TeslaBattery:: } else { clear_event(EVENT_BATTERY_FUSE); } - // Raise any informational Tesla BMS events in BE - if (BMS_a145_SW_SOC_Change == true && !BMS_SW_SOC_Change_Latch) { // BMS has newly recalibrated pack SOC - BMS_SW_SOC_Change_Latch = true; // Only set event once, BMS_a145 can be active for a while - set_event(EVENT_BATTERY_SOC_RECALIBRATION, 0); + // Raise any Tesla BMS events in BE + // Events: Informational + if (BMS_a145_SW_SOC_Change) { // BMS has newly recalibrated pack SOC + set_event_latched(EVENT_BATTERY_SOC_RECALIBRATION, 0); // Latcched as BMS_a145 can be active for a while + } else if (!BMS_a145_SW_SOC_Change) { clear_event(EVENT_BATTERY_SOC_RECALIBRATION); - } else if (BMS_a145_SW_SOC_Change == false) { - BMS_SW_SOC_Change_Latch = false; + } + // Events: Warning + if (BMS_contactorState == 5) { // BMS has detected welded contactor(s) + set_event_latched(EVENT_CONTACTOR_WELDED, 0); + } else if (BMS_contactorState != 5) { + clear_event(EVENT_CONTACTOR_WELDED); } if (user_selected_tesla_GTW_chassisType > 1) { //{{0, "Model S"}, {1, "Model X"}, {2, "Model 3"}, {3, "Model Y"}}; @@ -553,7 +558,7 @@ void TeslaBattery:: datalayer.battery.settings.user_requests_tesla_soc_reset = false; logging.println("INFO: SOC reset requested"); } else { - logging.println("ERROR: SOC reset failed, SOC not < 15 or > 90"); + logging.println("ERROR: SOC reset failed, SOC not < 15 or > 90, or contactors not open"); stateMachineSOCReset = 0xFF; datalayer.battery.settings.user_requests_tesla_soc_reset = false; set_event(EVENT_BATTERY_SOC_RESET_FAIL, 0); diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 8abc15db..9d599eba 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -877,7 +877,6 @@ class TeslaBattery : public CanBattery { bool BMS_a141_SW_BMB_Status_Warning = false; bool BMS_a144_Hvp_Config_Mismatch = false; bool BMS_a145_SW_SOC_Change = false; - bool BMS_SW_SOC_Change_Latch = false; bool BMS_a146_SW_Brick_Overdischarged = false; bool BMS_a149_SW_Missing_Config_Block = false; bool BMS_a151_SW_external_isolation = false; From b26c451eafca6915ffea3c924a5ba41025caf11f Mon Sep 17 00:00:00 2001 From: James Brookes Date: Sat, 27 Sep 2025 19:27:15 +0100 Subject: [PATCH 5/5] Fix % in SOC_RECALIBRATION string --- Software/src/devboard/utils/events.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 57882def..513426e5 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -250,7 +250,7 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { case EVENT_BATTERY_ISOLATION: return "Battery reports isolation error. High voltage might be leaking to ground. Check battery!"; case EVENT_BATTERY_SOC_RECALIBRATION: - return "The BMS updated the HV battery State of Charge (SOC) by more than 3% based on SocByOcv."; + return "The BMS updated the HV battery State of Charge (SOC) by more than 3pct based on SocByOcv."; case EVENT_BATTERY_SOC_RESET_SUCCESS: return "SOC reset routine was successful."; case EVENT_BATTERY_SOC_RESET_FAIL: