From 118169a952237e2cd4b8a26862d17650a717a7e7 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Thu, 30 Oct 2025 18:14:57 -0700 Subject: [PATCH 01/18] replaced magic numbers from charging request can message with enum. --- lib/interfaces/include/CCUInterface.h | 6 +++++- lib/interfaces/src/CCUInterface.cpp | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/interfaces/include/CCUInterface.h b/lib/interfaces/include/CCUInterface.h index 357b155d..be9f0afa 100644 --- a/lib/interfaces/include/CCUInterface.h +++ b/lib/interfaces/include/CCUInterface.h @@ -16,7 +16,11 @@ constexpr const size_t NUM_CELLS = 126; constexpr const size_t NUM_CELLTEMPS = 48; constexpr const size_t NUM_CHIPS = 12; - +enum ChargingCommand_e +{ + CHARGE = 2, + DISCHARGE = 1 +}; struct CCUCANInterfaceData_s { unsigned long last_time_charging_requested; diff --git a/lib/interfaces/src/CCUInterface.cpp b/lib/interfaces/src/CCUInterface.cpp index 5d809ee9..c415c8f0 100644 --- a/lib/interfaces/src/CCUInterface.cpp +++ b/lib/interfaces/src/CCUInterface.cpp @@ -16,9 +16,9 @@ void CCUInterface::receive_CCU_status_message(const CAN_message_t& msg, unsigned void CCUInterface::handle_enqueue_acu_status_CAN_message() { BMS_STATUS_t msg = {}; if (_curr_data.charging_requested) { - msg.state = 2; // charging + msg.state = ChargingCommand_e::CHARGE; } else { - msg.state = 1; // discharging + msg.state = ChargingCommand_e::DISCHARGE; } CAN_util::enqueue_msg(&msg, &Pack_BMS_STATUS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); From 1e0d8e21c25274bf782efbb51114ee66adcd7ecd Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Thu, 30 Oct 2025 23:05:26 -0700 Subject: [PATCH 02/18] changed handshake names to be more accurate and removed extra value --- lib/interfaces/include/CCUInterface.h | 35 ++++++++------ lib/interfaces/src/CCUInterface.cpp | 70 +++++++++++++-------------- platformio.ini | 2 +- 3 files changed, 55 insertions(+), 52 deletions(-) diff --git a/lib/interfaces/include/CCUInterface.h b/lib/interfaces/include/CCUInterface.h index be9f0afa..9dd1ec5e 100644 --- a/lib/interfaces/include/CCUInterface.h +++ b/lib/interfaces/include/CCUInterface.h @@ -16,10 +16,13 @@ constexpr const size_t NUM_CELLS = 126; constexpr const size_t NUM_CELLTEMPS = 48; constexpr const size_t NUM_CHIPS = 12; +constexpr const size_t CELLS_PER_GROUP = 3; +constexpr const size_t GROUPS_PER_IC_EVEN = 4; +constexpr const size_t GROUPS_PER_IC_ODD = 3; enum ChargingCommand_e { - CHARGE = 2, - DISCHARGE = 1 + CHARGE = 0, + IDLE = 1, }; struct CCUCANInterfaceData_s { @@ -27,13 +30,13 @@ struct CCUCANInterfaceData_s unsigned long prev_ccu_msg_recv_ms; bool charging_requested; bool is_connected_to_CCU; - size_t detailed_voltages_ic_id; - size_t detailed_voltages_group_id; - size_t detailed_voltages_cell_id; - size_t detailed_temps_ic_id; - size_t detailed_temps_group_id; - size_t detailed_temps_cell_id; - size_t detailed_temps_board_id; + size_t current_voltage_group_chip_id; + size_t current_voltage_cell_group_id; + size_t current_voltage_cell_id; + size_t current_temp_group_chip_id; + size_t current_temp_group_id; + size_t current_temp_cell_id; + size_t current_temp_board_id; }; class CCUInterface @@ -47,13 +50,13 @@ class CCUInterface _curr_data.prev_ccu_msg_recv_ms = 0; _curr_data.charging_requested = false; _curr_data.is_connected_to_CCU = false; - _curr_data.detailed_voltages_group_id = 0; - _curr_data.detailed_voltages_ic_id = 0; - _curr_data.detailed_voltages_cell_id = 0; - _curr_data.detailed_temps_group_id = 0; - _curr_data.detailed_temps_ic_id = 0; - _curr_data.detailed_temps_cell_id = 0; - _curr_data.detailed_temps_board_id = 0; + _curr_data.current_voltage_cell_group_id = 0; + _curr_data.current_voltage_group_chip_id = 0; + _curr_data.current_voltage_cell_id = 0; + _curr_data.current_temp_group_id = 0; + _curr_data.current_temp_group_chip_id = 0; + _curr_data.current_temp_cell_id = 0; + _curr_data.current_temp_board_id = 0; }; bool is_charging_requested() { return _curr_data.charging_requested; } diff --git a/lib/interfaces/src/CCUInterface.cpp b/lib/interfaces/src/CCUInterface.cpp index c415c8f0..8cb2d1f0 100644 --- a/lib/interfaces/src/CCUInterface.cpp +++ b/lib/interfaces/src/CCUInterface.cpp @@ -16,9 +16,9 @@ void CCUInterface::receive_CCU_status_message(const CAN_message_t& msg, unsigned void CCUInterface::handle_enqueue_acu_status_CAN_message() { BMS_STATUS_t msg = {}; if (_curr_data.charging_requested) { - msg.state = ChargingCommand_e::CHARGE; + msg.charging_state = ChargingCommand_e::CHARGE; } else { - msg.state = ChargingCommand_e::DISCHARGE; + msg.charging_state = ChargingCommand_e::IDLE; } CAN_util::enqueue_msg(&msg, &Pack_BMS_STATUS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); @@ -26,60 +26,60 @@ void CCUInterface::handle_enqueue_acu_status_CAN_message() { void CCUInterface::handle_enqueue_acu_core_voltages_CAN_message() { BMS_VOLTAGES_t msg = {}; - msg.high_voltage_ro = HYTECH_high_voltage_ro_toS(_acu_core_data.max_cell_voltage); - msg.low_voltage_ro = HYTECH_low_voltage_ro_toS(_acu_core_data.min_cell_voltage); + msg.max_cell_voltage_ro = HYTECH_max_cell_voltage_ro_toS(_acu_core_data.max_cell_voltage); + msg.min_cell_voltage_ro = HYTECH_min_cell_voltage_ro_toS(_acu_core_data.min_cell_voltage); msg.total_voltage_ro = HYTECH_total_voltage_ro_toS(_acu_core_data.pack_voltage); msg.average_voltage_ro = HYTECH_average_voltage_ro_toS(_acu_core_data.avg_cell_voltage); CAN_util::enqueue_msg(&msg, &Pack_BMS_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } void CCUInterface::handle_enqueue_acu_voltages_CAN_message() { - BMS_DETAILED_VOLTAGES_t detailed_msg = {}; - detailed_msg.ic_id = static_cast(_curr_data.detailed_voltages_ic_id); - detailed_msg.group_id = static_cast(_curr_data.detailed_voltages_group_id); - detailed_msg.voltage_0_ro = HYTECH_voltage_0_ro_toS(_acu_all_data.cell_voltages[_curr_data.detailed_voltages_cell_id]); - detailed_msg.voltage_1_ro = HYTECH_voltage_1_ro_toS(_acu_all_data.cell_voltages[_curr_data.detailed_voltages_cell_id+1]); - detailed_msg.voltage_2_ro = HYTECH_voltage_2_ro_toS(_acu_all_data.cell_voltages[_curr_data.detailed_voltages_cell_id+2]); + BMS_CELL_VOLTAGES_t msg = {}; + msg.chip_id = static_cast(_curr_data.current_voltage_group_chip_id); + msg.cell_group_id = static_cast(_curr_data.current_voltage_cell_group_id); + msg.cell_group_voltage_0_ro = HYTECH_cell_group_voltage_0_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id]); + msg.cell_group_voltage_1_ro = HYTECH_cell_group_voltage_1_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id+1]); + msg.cell_group_voltage_2_ro = HYTECH_cell_group_voltage_2_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id+2]); - if (_curr_data.detailed_voltages_ic_id % 2 == 0) { - _curr_data.detailed_voltages_group_id = (_curr_data.detailed_voltages_group_id == 3) ? 0 : _curr_data.detailed_voltages_group_id+1; + if (_curr_data.current_voltage_group_chip_id % 2 == 0) { + _curr_data.current_voltage_cell_group_id = (_curr_data.current_voltage_cell_group_id == GROUPS_PER_IC_EVEN - 1) ? 0 : _curr_data.current_voltage_cell_group_id+1; } else { - _curr_data.detailed_voltages_group_id = (_curr_data.detailed_voltages_group_id == 2) ? 0 : _curr_data.detailed_voltages_group_id+1; + _curr_data.current_voltage_cell_group_id = (_curr_data.current_voltage_cell_group_id == GROUPS_PER_IC_ODD - 1) ? 0 : _curr_data.current_voltage_cell_group_id+1; } - if (_curr_data.detailed_voltages_group_id == 0) { - _curr_data.detailed_voltages_ic_id = (_curr_data.detailed_voltages_ic_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.detailed_voltages_ic_id+1; + if (_curr_data.current_voltage_cell_group_id == 0) { + _curr_data.current_voltage_group_chip_id = (_curr_data.current_voltage_group_chip_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.current_voltage_group_chip_id+1; } - _curr_data.detailed_voltages_cell_id = (_curr_data.detailed_voltages_cell_id == NUM_CELLS - 3) ? 0 : _curr_data.detailed_voltages_cell_id+3; + _curr_data.current_voltage_cell_id= (_curr_data.current_voltage_cell_id == NUM_CELLS - CELLS_PER_GROUP) ? 0 : _curr_data.current_voltage_cell_id+CELLS_PER_GROUP; - CAN_util::enqueue_msg(&detailed_msg, &Pack_BMS_DETAILED_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); + CAN_util::enqueue_msg(&msg, &Pack_BMS_CELL_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } void CCUInterface::handle_enqueue_acu_temps_CAN_message() { - BMS_DETAILED_TEMPS_t detailed_msg = {}; - detailed_msg.ic_id = static_cast(_curr_data.detailed_temps_ic_id); - detailed_msg.group_id = static_cast(_curr_data.detailed_temps_group_id); - detailed_msg.thermistor_id_0_ro = HYTECH_thermistor_id_0_ro_toS(_acu_all_data.cell_temps[_curr_data.detailed_temps_cell_id]); - detailed_msg.thermistor_id_1_ro = HYTECH_thermistor_id_1_ro_toS(_acu_all_data.cell_temps[_curr_data.detailed_temps_cell_id+1]); - detailed_msg.thermistor_id_2_ro = HYTECH_thermistor_id_2_ro_toS(_acu_all_data.cell_temps[_curr_data.detailed_temps_cell_id+2]); + BMS_CHIP_TEMPS_t chip_temps_msg = {}; + chip_temps_msg.chip_id = static_cast(_curr_data.current_temp_group_chip_id); + chip_temps_msg.thermistor_group_id = static_cast(_curr_data.current_temp_group_id); + chip_temps_msg.thermistor_group_temp_0_ro = HYTECH_thermistor_group_temp_0_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id]); + chip_temps_msg.thermistor_group_temp_1_ro = HYTECH_thermistor_group_temp_1_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+1]); + chip_temps_msg.thermistor_group_temp_2_ro = HYTECH_thermistor_group_temp_2_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+2]); - _curr_data.detailed_temps_group_id = (_curr_data.detailed_temps_group_id == 1) ? 0 : _curr_data.detailed_temps_group_id+1; - if (_curr_data.detailed_temps_group_id == 0) { - _curr_data.detailed_temps_ic_id = (_curr_data.detailed_temps_ic_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.detailed_temps_ic_id+1; + _curr_data.current_temp_group_id = (_curr_data.current_temp_group_id == 1) ? 0 : _curr_data.current_temp_group_id+1; + if (_curr_data.current_temp_group_id == 0) { + _curr_data.current_temp_group_chip_id = (_curr_data.current_temp_group_chip_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.current_temp_group_chip_id+1; } - _curr_data.detailed_temps_cell_id = (_curr_data.detailed_temps_cell_id == (NUM_CELLTEMPS - 3)) ? 0 : _curr_data.detailed_temps_cell_id+3; - CAN_util::enqueue_msg(&detailed_msg, &Pack_BMS_DETAILED_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); + _curr_data.current_temp_cell_id = (_curr_data.current_temp_cell_id == (NUM_CELLTEMPS - CELLS_PER_GROUP)) ? 0 : _curr_data.current_temp_cell_id+CELLS_PER_GROUP; + CAN_util::enqueue_msg(&chip_temps_msg, &Pack_BMS_CHIP_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); BMS_ONBOARD_TEMPS_t board_temp_msg = {}; board_temp_msg.max_board_temp_ro = HYTECH_max_board_temp_ro_toS(_acu_all_data.core_data.max_board_temp); - board_temp_msg.high_cell_temp_ro = HYTECH_high_cell_temp_ro_toS(_acu_all_data.core_data.max_cell_temp); - board_temp_msg.low_cell_temp_ro = HYTECH_low_cell_temp_ro_toS(_acu_all_data.core_data.min_cell_temp); + board_temp_msg.max_cell_temp_ro = HYTECH_max_cell_temp_ro_toS(_acu_all_data.core_data.max_cell_temp); + board_temp_msg.min_cell_temp_ro = HYTECH_min_cell_temp_ro_toS(_acu_all_data.core_data.min_cell_temp); CAN_util::enqueue_msg(&board_temp_msg, &Pack_BMS_ONBOARD_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); - BMS_ONBOARD_DETAILED_TEMPS_t detailed_board_temp_msg = {}; - detailed_board_temp_msg.ic_id = _curr_data.detailed_temps_board_id; - detailed_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(_acu_all_data.board_temps[_curr_data.detailed_temps_board_id]); - _curr_data.detailed_temps_board_id = (_curr_data.detailed_temps_board_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.detailed_temps_board_id+1; - CAN_util::enqueue_msg(&detailed_board_temp_msg, &Pack_BMS_ONBOARD_DETAILED_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); + BMS_ONBOARD_CURRENT_TEMP_t current_board_temp_msg = {}; + current_board_temp_msg.chip_id = _curr_data.current_temp_board_id; + current_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(_acu_all_data.board_temps[_curr_data.current_temp_board_id]); + _curr_data.current_temp_board_id = (_curr_data.current_temp_board_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.current_temp_board_id+1; + CAN_util::enqueue_msg(¤t_board_temp_msg, &Pack_BMS_ONBOARD_CURRENT_TEMP_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } void CCUInterface::set_system_latch_state(unsigned long curr_millis, bool is_latched) { diff --git a/platformio.ini b/platformio.ini index 9fda7486..ad54cd80 100644 --- a/platformio.ini +++ b/platformio.ini @@ -73,7 +73,7 @@ test_ignore = lib_deps= ${common.lib_deps_shared} https://github.com/ssilverman/QNEthernet#v0.26.0 - https://github.com/hytech-racing/HT_CAN/releases/download/192/can_lib.tar.gz + https://github.com/hytech-racing/HT_CAN/releases/download/204/can_lib.tar.gz https://github.com/hytech-racing/HT_SCHED.git https://github.com/hytech-racing/HT_proto/releases/download/2025-08-27T15_34_50/hytech_msgs_pb_lib.tar.gz https://github.com/hytech-racing/shared_firmware_interfaces.git From b9dacca59fc5978e665619f34e1459d8f815e939 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Sun, 2 Nov 2025 11:17:09 -0800 Subject: [PATCH 03/18] added loop function to generalize id looping functionality of CCUInterface --- lib/interfaces/include/CCUInterface.h | 17 +++++++++++++++-- lib/interfaces/src/CCUInterface.cpp | 24 ++++++++++-------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/interfaces/include/CCUInterface.h b/lib/interfaces/include/CCUInterface.h index 9dd1ec5e..0b1fe3d2 100644 --- a/lib/interfaces/include/CCUInterface.h +++ b/lib/interfaces/include/CCUInterface.h @@ -17,8 +17,9 @@ constexpr const size_t NUM_CELLS = 126; constexpr const size_t NUM_CELLTEMPS = 48; constexpr const size_t NUM_CHIPS = 12; constexpr const size_t CELLS_PER_GROUP = 3; -constexpr const size_t GROUPS_PER_IC_EVEN = 4; -constexpr const size_t GROUPS_PER_IC_ODD = 3; +constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_EVEN = 4; +constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_ODD = 3; +constexpr const size_t TEMP_CELL_GROUPS_PER_IC = 2; enum ChargingCommand_e { CHARGE = 0, @@ -103,6 +104,18 @@ class CCUInterface ACUAllData_s _acu_all_data; unsigned long _min_charging_enable_threshold; + + bool increment_and_loop_id(size_t id, size_t max_id, size_t increment = 1) + { + if (id == max_id - increment) { + id = 0; + return true; + } + else { + id += increment; + return false; + } + } }; using CCUInterfaceInstance = etl::singleton; diff --git a/lib/interfaces/src/CCUInterface.cpp b/lib/interfaces/src/CCUInterface.cpp index 8cb2d1f0..06676142 100644 --- a/lib/interfaces/src/CCUInterface.cpp +++ b/lib/interfaces/src/CCUInterface.cpp @@ -40,17 +40,14 @@ void CCUInterface::handle_enqueue_acu_voltages_CAN_message() { msg.cell_group_voltage_0_ro = HYTECH_cell_group_voltage_0_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id]); msg.cell_group_voltage_1_ro = HYTECH_cell_group_voltage_1_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id+1]); msg.cell_group_voltage_2_ro = HYTECH_cell_group_voltage_2_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id+2]); - + bool voltage_cell_group_cycle_loop_completed; if (_curr_data.current_voltage_group_chip_id % 2 == 0) { - _curr_data.current_voltage_cell_group_id = (_curr_data.current_voltage_cell_group_id == GROUPS_PER_IC_EVEN - 1) ? 0 : _curr_data.current_voltage_cell_group_id+1; + voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, VOLTAGE_CELL_GROUPS_PER_IC_EVEN); } else { - _curr_data.current_voltage_cell_group_id = (_curr_data.current_voltage_cell_group_id == GROUPS_PER_IC_ODD - 1) ? 0 : _curr_data.current_voltage_cell_group_id+1; - } - if (_curr_data.current_voltage_cell_group_id == 0) { - _curr_data.current_voltage_group_chip_id = (_curr_data.current_voltage_group_chip_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.current_voltage_group_chip_id+1; + voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, VOLTAGE_CELL_GROUPS_PER_IC_ODD); } - _curr_data.current_voltage_cell_id= (_curr_data.current_voltage_cell_id == NUM_CELLS - CELLS_PER_GROUP) ? 0 : _curr_data.current_voltage_cell_id+CELLS_PER_GROUP; - + if (voltage_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_voltage_group_chip_id, NUM_CHIPS); + increment_and_loop_id(_curr_data.current_voltage_cell_id, NUM_CELLS, CELLS_PER_GROUP); CAN_util::enqueue_msg(&msg, &Pack_BMS_CELL_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } @@ -62,11 +59,10 @@ void CCUInterface::handle_enqueue_acu_temps_CAN_message() { chip_temps_msg.thermistor_group_temp_1_ro = HYTECH_thermistor_group_temp_1_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+1]); chip_temps_msg.thermistor_group_temp_2_ro = HYTECH_thermistor_group_temp_2_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+2]); - _curr_data.current_temp_group_id = (_curr_data.current_temp_group_id == 1) ? 0 : _curr_data.current_temp_group_id+1; - if (_curr_data.current_temp_group_id == 0) { - _curr_data.current_temp_group_chip_id = (_curr_data.current_temp_group_chip_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.current_temp_group_chip_id+1; - } - _curr_data.current_temp_cell_id = (_curr_data.current_temp_cell_id == (NUM_CELLTEMPS - CELLS_PER_GROUP)) ? 0 : _curr_data.current_temp_cell_id+CELLS_PER_GROUP; + bool temp_cell_group_cycle_loop_completed; + temp_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_temp_group_id, TEMP_CELL_GROUPS_PER_IC); + if (temp_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_temp_group_chip_id, NUM_CHIPS); + increment_and_loop_id(_curr_data.current_temp_cell_id, NUM_CELLTEMPS, CELLS_PER_GROUP); CAN_util::enqueue_msg(&chip_temps_msg, &Pack_BMS_CHIP_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); BMS_ONBOARD_TEMPS_t board_temp_msg = {}; @@ -78,7 +74,7 @@ void CCUInterface::handle_enqueue_acu_temps_CAN_message() { BMS_ONBOARD_CURRENT_TEMP_t current_board_temp_msg = {}; current_board_temp_msg.chip_id = _curr_data.current_temp_board_id; current_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(_acu_all_data.board_temps[_curr_data.current_temp_board_id]); - _curr_data.current_temp_board_id = (_curr_data.current_temp_board_id == (NUM_CHIPS - 1)) ? 0 : _curr_data.current_temp_board_id+1; + increment_and_loop_id(_curr_data.current_temp_board_id, NUM_CHIPS); CAN_util::enqueue_msg(¤t_board_temp_msg, &Pack_BMS_ONBOARD_CURRENT_TEMP_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } From 43ca9ddc6774511ac255831c2ab5fa6be90625a1 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Sun, 2 Nov 2025 13:08:31 -0800 Subject: [PATCH 04/18] merge clenaup --- lib/interfaces/include/CCUInterface.h | 47 ++++++++++++++------------- lib/interfaces/src/CCUInterface.cpp | 16 ++++----- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/lib/interfaces/include/CCUInterface.h b/lib/interfaces/include/CCUInterface.h index 2bbbe6f8..1e17eb2f 100644 --- a/lib/interfaces/include/CCUInterface.h +++ b/lib/interfaces/include/CCUInterface.h @@ -13,20 +13,31 @@ #include "SharedFirmwareTypes.h" #include "shared_types.h" + +enum ChargingCommand_e +{ + CHARGE = 0, + IDLE = 1, +}; namespace ccu_interface_defaults{ constexpr const uint16_t MIN_CHARGING_ENABLE_THRESHOLD_MS = 1000; constexpr const size_t NUM_CELLS = 126; constexpr const size_t NUM_CELLTEMPS = 48; constexpr const size_t NUM_CHIPS = 12; + constexpr const size_t CELLS_PER_GROUP = 3; + constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_EVEN = 4; + constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_ODD = 3; + constexpr const size_t TEMP_CELL_GROUPS_PER_IC = 2; }; -constexpr const size_t CELLS_PER_GROUP = 3; -constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_EVEN = 4; -constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_ODD = 3; -constexpr const size_t TEMP_CELL_GROUPS_PER_IC = 2; -enum ChargingCommand_e -{ - CHARGE = 0, - IDLE = 1, +struct CCUInterfaceParams_s { + unsigned long min_charging_enable_threshold; + size_t num_cells; + size_t num_celltemps; + size_t num_chips; + size_t voltage_cell_groups_per_ic_even; + size_t voltage_cell_groups_per_ic_odd; + size_t temp_cell_groups_per_ic; + size_t cells_per_group; }; struct CCUCANInterfaceData_s { @@ -43,20 +54,6 @@ struct CCUCANInterfaceData_s size_t current_temp_board_id; }; -struct CCUInterfaceParams_s { - unsigned long min_charging_enable_threshold; - size_t num_cells; - size_t num_celltemps; - size_t num_chips; -}; - -struct CCUInterfaceParams_s { - unsigned long min_charging_enable_threshold; - size_t num_cells; - size_t num_celltemps; - size_t num_chips; -}; - class CCUInterface { public: @@ -67,7 +64,11 @@ class CCUInterface .min_charging_enable_threshold = ccu_interface_defaults::MIN_CHARGING_ENABLE_THRESHOLD_MS, .num_cells = ccu_interface_defaults::NUM_CELLS, .num_celltemps = ccu_interface_defaults::NUM_CELLTEMPS, - .num_chips = ccu_interface_defaults::NUM_CHIPS + .num_chips = ccu_interface_defaults::NUM_CHIPS, + .voltage_cell_groups_per_ic_even = ccu_interface_defaults::VOLTAGE_CELL_GROUPS_PER_IC_EVEN, + .voltage_cell_groups_per_ic_odd = ccu_interface_defaults::VOLTAGE_CELL_GROUPS_PER_IC_ODD, + .temp_cell_groups_per_ic = ccu_interface_defaults::TEMP_CELL_GROUPS_PER_IC, + .cells_per_group = ccu_interface_defaults::CELLS_PER_GROUP } ) : _ccu_params{params} { diff --git a/lib/interfaces/src/CCUInterface.cpp b/lib/interfaces/src/CCUInterface.cpp index 1830653a..3972fbf6 100644 --- a/lib/interfaces/src/CCUInterface.cpp +++ b/lib/interfaces/src/CCUInterface.cpp @@ -42,12 +42,12 @@ void CCUInterface::handle_enqueue_acu_voltages_CAN_message() { msg.cell_group_voltage_2_ro = HYTECH_cell_group_voltage_2_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id+2]); bool voltage_cell_group_cycle_loop_completed; if (_curr_data.current_voltage_group_chip_id % 2 == 0) { - voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, VOLTAGE_CELL_GROUPS_PER_IC_EVEN); + voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_even); } else { - voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, VOLTAGE_CELL_GROUPS_PER_IC_ODD); + voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_odd); } - if (voltage_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_voltage_group_chip_id, NUM_CHIPS); - increment_and_loop_id(_curr_data.current_voltage_cell_id, NUM_CELLS, CELLS_PER_GROUP); + if (voltage_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_voltage_group_chip_id, _ccu_params.num_chips); + increment_and_loop_id(_curr_data.current_voltage_cell_id, _ccu_params.num_cells, _ccu_params.cells_per_group); CAN_util::enqueue_msg(&msg, &Pack_BMS_CELL_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } @@ -60,9 +60,9 @@ void CCUInterface::handle_enqueue_acu_temps_CAN_message() { chip_temps_msg.thermistor_group_temp_2_ro = HYTECH_thermistor_group_temp_2_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+2]); bool temp_cell_group_cycle_loop_completed; - temp_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_temp_group_id, TEMP_CELL_GROUPS_PER_IC); - if (temp_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_temp_group_chip_id, NUM_CHIPS); - increment_and_loop_id(_curr_data.current_temp_cell_id, NUM_CELLTEMPS, CELLS_PER_GROUP); + temp_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_temp_group_id, _ccu_params.temp_cell_groups_per_ic); + if (temp_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_temp_group_chip_id, _ccu_params.num_chips); + increment_and_loop_id(_curr_data.current_temp_cell_id, _ccu_params.num_celltemps, _ccu_params.cells_per_group); CAN_util::enqueue_msg(&chip_temps_msg, &Pack_BMS_CHIP_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); BMS_ONBOARD_TEMPS_t board_temp_msg = {}; @@ -74,7 +74,7 @@ void CCUInterface::handle_enqueue_acu_temps_CAN_message() { BMS_ONBOARD_CURRENT_TEMP_t current_board_temp_msg = {}; current_board_temp_msg.chip_id = _curr_data.current_temp_board_id; current_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(_acu_all_data.board_temps[_curr_data.current_temp_board_id]); - increment_and_loop_id(_curr_data.current_temp_board_id, NUM_CHIPS); + increment_and_loop_id(_curr_data.current_temp_board_id, _ccu_params.num_chips); CAN_util::enqueue_msg(¤t_board_temp_msg, &Pack_BMS_ONBOARD_CURRENT_TEMP_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } From 8911749a81a23eb3b74123ffedb1909b6f29a069 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Sun, 2 Nov 2025 14:59:02 -0800 Subject: [PATCH 05/18] fixed cell temp logic to send 2 groups of 2 temps per chip instead of 2 groups of 3 temps which is 2 more than needed --- lib/interfaces/include/CCUInterface.h | 9 ++++++--- lib/interfaces/src/CCUInterface.cpp | 9 ++++----- platformio.ini | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/interfaces/include/CCUInterface.h b/lib/interfaces/include/CCUInterface.h index 1e17eb2f..3cacfda5 100644 --- a/lib/interfaces/include/CCUInterface.h +++ b/lib/interfaces/include/CCUInterface.h @@ -24,10 +24,11 @@ namespace ccu_interface_defaults{ constexpr const size_t NUM_CELLS = 126; constexpr const size_t NUM_CELLTEMPS = 48; constexpr const size_t NUM_CHIPS = 12; - constexpr const size_t CELLS_PER_GROUP = 3; + constexpr const size_t VOLTAGE_CELLS_PER_GROUP = 3; constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_EVEN = 4; constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_ODD = 3; constexpr const size_t TEMP_CELL_GROUPS_PER_IC = 2; + constexpr const size_t TEMP_CELLS_PER_GROUP = 2; }; struct CCUInterfaceParams_s { unsigned long min_charging_enable_threshold; @@ -37,7 +38,8 @@ struct CCUInterfaceParams_s { size_t voltage_cell_groups_per_ic_even; size_t voltage_cell_groups_per_ic_odd; size_t temp_cell_groups_per_ic; - size_t cells_per_group; + size_t voltage_cells_per_group; + size_t temp_cells_per_group; }; struct CCUCANInterfaceData_s { @@ -68,7 +70,8 @@ class CCUInterface .voltage_cell_groups_per_ic_even = ccu_interface_defaults::VOLTAGE_CELL_GROUPS_PER_IC_EVEN, .voltage_cell_groups_per_ic_odd = ccu_interface_defaults::VOLTAGE_CELL_GROUPS_PER_IC_ODD, .temp_cell_groups_per_ic = ccu_interface_defaults::TEMP_CELL_GROUPS_PER_IC, - .cells_per_group = ccu_interface_defaults::CELLS_PER_GROUP + .voltage_cells_per_group = ccu_interface_defaults::VOLTAGE_CELLS_PER_GROUP, + .temp_cells_per_group = ccu_interface_defaults::TEMP_CELLS_PER_GROUP } ) : _ccu_params{params} { diff --git a/lib/interfaces/src/CCUInterface.cpp b/lib/interfaces/src/CCUInterface.cpp index 3972fbf6..eab7cc09 100644 --- a/lib/interfaces/src/CCUInterface.cpp +++ b/lib/interfaces/src/CCUInterface.cpp @@ -47,7 +47,7 @@ void CCUInterface::handle_enqueue_acu_voltages_CAN_message() { voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_odd); } if (voltage_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_voltage_group_chip_id, _ccu_params.num_chips); - increment_and_loop_id(_curr_data.current_voltage_cell_id, _ccu_params.num_cells, _ccu_params.cells_per_group); + increment_and_loop_id(_curr_data.current_voltage_cell_id, _ccu_params.num_cells, _ccu_params.voltage_cells_per_group); CAN_util::enqueue_msg(&msg, &Pack_BMS_CELL_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } @@ -55,14 +55,13 @@ void CCUInterface::handle_enqueue_acu_temps_CAN_message() { BMS_CHIP_TEMPS_t chip_temps_msg = {}; chip_temps_msg.chip_id = static_cast(_curr_data.current_temp_group_chip_id); chip_temps_msg.thermistor_group_id = static_cast(_curr_data.current_temp_group_id); - chip_temps_msg.thermistor_group_temp_0_ro = HYTECH_thermistor_group_temp_0_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id]); - chip_temps_msg.thermistor_group_temp_1_ro = HYTECH_thermistor_group_temp_1_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+1]); - chip_temps_msg.thermistor_group_temp_2_ro = HYTECH_thermistor_group_temp_2_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+2]); + chip_temps_msg.thermistor_cell_group_temp_0_ro = HYTECH_thermistor_cell_group_temp_0_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id]); + chip_temps_msg.thermistor_cell_group_temp_1_ro = HYTECH_thermistor_cell_group_temp_1_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+1]); bool temp_cell_group_cycle_loop_completed; temp_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_temp_group_id, _ccu_params.temp_cell_groups_per_ic); if (temp_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_temp_group_chip_id, _ccu_params.num_chips); - increment_and_loop_id(_curr_data.current_temp_cell_id, _ccu_params.num_celltemps, _ccu_params.cells_per_group); + increment_and_loop_id(_curr_data.current_temp_cell_id, _ccu_params.num_celltemps, _ccu_params.temp_cells_per_group); CAN_util::enqueue_msg(&chip_temps_msg, &Pack_BMS_CHIP_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); BMS_ONBOARD_TEMPS_t board_temp_msg = {}; diff --git a/platformio.ini b/platformio.ini index 417c4531..d8c3d55a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -75,10 +75,10 @@ test_ignore = lib_deps= ${common.lib_deps_shared} https://github.com/ssilverman/QNEthernet#v0.26.0 - https://github.com/hytech-racing/HT_CAN/releases/download/204/can_lib.tar.gz + https://github.com/hytech-racing/HT_CAN/releases/download/209/can_lib.tar.gz https://github.com/hytech-racing/HT_SCHED.git https://github.com/hytech-racing/HT_proto/releases/download/2025-08-27T15_34_50/hytech_msgs_pb_lib.tar.gz - https://github.com/hytech-racing/shared_firmware_interfaces.git + https://github.com/hytech-racing/shared_firmware_interfaces.git#5baf17a0f6d83d0a9d571d6bf56f409d2c8ad98a https://github.com/KSU-MS/pio-git-hash-gen#7998b5b3f8a2464209b0e73338717998bcf511ee Nanopb arkhipenko/TaskScheduler@^3.8.5 @@ -113,7 +113,7 @@ test_ignore = lib_deps= ${common.lib_deps_shared} https://github.com/ssilverman/QNEthernet#v0.26.0 - https://github.com/hytech-racing/HT_CAN/releases/download/192/can_lib.tar.gz + https://github.com/hytech-racing/HT_CAN/releases/download/209/can_lib.tar.gz https://github.com/hytech-racing/HT_SCHED.git https://github.com/hytech-racing/HT_proto/releases/download/2025-08-27T15_34_50/hytech_msgs_pb_lib.tar.gz https://github.com/hytech-racing/shared_firmware_interfaces.git From f3bbd895f5623def75e594830febff6480792224 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Tue, 4 Nov 2025 12:25:27 -0800 Subject: [PATCH 06/18] updated CCUINterface to a be a template --- include/ACU_InterfaceTasks.h | 14 ++- include/ACU_SystemTasks.h | 2 +- lib/interfaces/include/ACUCANBuffers.h | 18 ++++ lib/interfaces/include/ACUCANInterface.h | 62 +++++++++++ lib/interfaces/include/ACUCANInterface.tpp | 24 +++++ lib/interfaces/include/ACUCANInterfaceImpl.h | 56 ---------- lib/interfaces/include/CCUInterface.h | 90 ++++++---------- lib/interfaces/include/CCUInterface.tpp | 107 +++++++++++++++++++ lib/interfaces/include/SystemTimeInterface.h | 3 + lib/interfaces/src/ACUCANBuffers.cpp | 7 ++ lib/interfaces/src/ACUCANInterface.cpp | 41 +++++++ lib/interfaces/src/ACUCANInterfaceImpl.cpp | 53 --------- lib/interfaces/src/CCUInterface.cpp | 87 --------------- lib/interfaces/src/EMInterface.cpp | 2 +- lib/interfaces/src/SystemTimeInterface.cpp | 10 ++ lib/interfaces/src/VCRInterface.cpp | 5 +- src/ACU_InterfaceTasks.cpp | 87 ++++++++------- src/ACU_SystemTasks.cpp | 2 +- src/main.cpp | 9 +- 19 files changed, 372 insertions(+), 307 deletions(-) create mode 100644 lib/interfaces/include/ACUCANBuffers.h create mode 100644 lib/interfaces/include/ACUCANInterface.h create mode 100644 lib/interfaces/include/ACUCANInterface.tpp delete mode 100644 lib/interfaces/include/ACUCANInterfaceImpl.h create mode 100644 lib/interfaces/include/CCUInterface.tpp create mode 100644 lib/interfaces/src/ACUCANBuffers.cpp create mode 100644 lib/interfaces/src/ACUCANInterface.cpp delete mode 100644 lib/interfaces/src/ACUCANInterfaceImpl.cpp delete mode 100644 lib/interfaces/src/CCUInterface.cpp diff --git a/include/ACU_InterfaceTasks.h b/include/ACU_InterfaceTasks.h index b048cbc8..4b7ac237 100644 --- a/include/ACU_InterfaceTasks.h +++ b/include/ACU_InterfaceTasks.h @@ -11,10 +11,12 @@ #include "WatchdogInterface.h" #include "WatchdogMetrics.h" #include "ACUEthernetInterface.h" -#include "ACUCANInterfaceImpl.h" +#include "ACUCANInterface.h" +#include "CCUInterface.h" #include "ADCInterface.h" #include "FaultLatchManager.h" #include "SystemTimeInterface.h" +#include "ACUCANBuffers.h" /* For Debugging */ #include "ACUStateMachine.h" @@ -22,10 +24,12 @@ #include using chip_type = LTC6811_Type_e; -using BMSDriver_t = BMSDriverInstance; -using BMSFaultDataManager_t = BMSFaultDataManagerInstance; -using ACUController_t = ACUControllerInstance; - +using BMSDriverInstance_t = BMSDriverInstance; +using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; +using ACUControllerInstance_t = ACUControllerInstance; +using CCUInterfaceInstance_t = CCUInterfaceInstance; +using CANInterfacesInstance_t = CANInterfacesInstance; +using CANInterfaces_t = CANInterfaces_s; /** * Init Functions - to be called in setup */ diff --git a/include/ACU_SystemTasks.h b/include/ACU_SystemTasks.h index cb226451..6b896f07 100644 --- a/include/ACU_SystemTasks.h +++ b/include/ACU_SystemTasks.h @@ -20,7 +20,7 @@ using chip_type = LTC6811_Type_e; using ACUControllerInstance_t = ACUControllerInstance; using BMSDriverInstance_t = BMSDriverInstance; - +using CCUInterfaceInstance_t = CCUInterfaceInstance; bool initialize_all_systems(); /* Delegate Functions */ diff --git a/lib/interfaces/include/ACUCANBuffers.h b/lib/interfaces/include/ACUCANBuffers.h new file mode 100644 index 00000000..484a26e2 --- /dev/null +++ b/lib/interfaces/include/ACUCANBuffers.h @@ -0,0 +1,18 @@ +#ifndef ACU_CAN_BUFFERS_H +#define ACU_CAN_BUFFERS_H + +#include +#include "FlexCAN_T4.h" +#include "CANInterface.h" + +const size_t CAN_MSG_SIZE = sizeof(CAN_message_t); +using CANRXBuffer_t = Circular_Buffer; +using CANTXBuffer_t = Circular_Buffer; + +namespace ACUCANBuffers { + extern CANRXBuffer_t ccu_can_rx_buffer; + extern CANRXBuffer_t em_can_rx_buffer; + extern CANTXBuffer_t ccu_can_tx_buffer; +} + +#endif // CAN_BUFFERS_H diff --git a/lib/interfaces/include/ACUCANInterface.h b/lib/interfaces/include/ACUCANInterface.h new file mode 100644 index 00000000..dd56c596 --- /dev/null +++ b/lib/interfaces/include/ACUCANInterface.h @@ -0,0 +1,62 @@ +#ifndef ACUCANINTERFACE_H +#define ACUCANINTERFACE_H + +#include +#include +#include + +#include "etl/delegate.h" +#include "etl/singleton.h" + +#include "FlexCAN_T4.h" +#include "CANInterface.h" +#include "SharedFirmwareTypes.h" +#include "shared_types.h" +#include "hytech.h" // generated CAN library + +#include "ACUCANBuffers.h" +#include "ACUController.h" +#include "VCRInterface.h" +#include "EMInterface.h" +#include "CCUInterface.h" + +/* FlexCAN type alias */ +template using FlexCAN_t = FlexCAN_T4; + +/* CANInterfaces struct - holds references to all CAN-connected interfaces */ +template +struct CANInterfaces_s { + explicit CANInterfaces_s(CCUInterface &ccu_int, EMInterface &em_int) : + ccu_interface(ccu_int), + em_interface(em_int) {} + + CCUInterface & ccu_interface; + EMInterface & em_interface; +}; + +template +using CANInterfacesInstance = etl::singleton>; + +/* ACUCANInterface namespace - Main CAN interface handler functions */ +namespace ACUCANInterface { + // CAN hardware instances + extern FlexCAN_t CCU_CAN; + extern FlexCAN_t EM_CAN; + + // CAN receive callbacks + void on_ccu_can_receive(const CAN_message_t &msg); + void on_em_can_receive(const CAN_message_t &msg); + + // Main CAN message handler (templated free function) + template + void acu_CAN_recv(CANInterfaces_s &interfaces, + const CAN_message_t &msg, + unsigned long millis); + + // Send all queued CAN messages + void send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface); +} + +#include "ACUCANInterface.tpp" + +#endif diff --git a/lib/interfaces/include/ACUCANInterface.tpp b/lib/interfaces/include/ACUCANInterface.tpp new file mode 100644 index 00000000..9faaab60 --- /dev/null +++ b/lib/interfaces/include/ACUCANInterface.tpp @@ -0,0 +1,24 @@ +template +void ACUCANInterface::acu_CAN_recv( + CANInterfaces_s &interfaces, + const CAN_message_t &msg, + unsigned long millis) +{ + switch (msg.id) + { + case CCU_STATUS_CANID: + { + interfaces.ccu_interface.receive_CCU_status_message(msg, millis); + break; + } + case EM_MEASUREMENT_CANID: + { + interfaces.em_interface.receive_EM_measurement_message(msg, millis); + break; + } + default: + { + break; + } + } +} diff --git a/lib/interfaces/include/ACUCANInterfaceImpl.h b/lib/interfaces/include/ACUCANInterfaceImpl.h deleted file mode 100644 index b06540d6..00000000 --- a/lib/interfaces/include/ACUCANInterfaceImpl.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef ACUCANINTERFACEIMPL_H -#define ACUCANINTERFACEIMPL_H - -#include -#include -#include - -#include "etl/delegate.h" -#include "etl/singleton.h" - -#include "FlexCAN_T4.h" -#include "CANInterface.h" -#include "SharedFirmwareTypes.h" -#include "shared_types.h" -#include "hytech.h" // generated CAN library - -#include "ACUController.h" -#include "CCUInterface.h" -#include "VCRInterface.h" -#include "EMInterface.h" - -const size_t CAN_MSG_SIZE = sizeof(CAN_message_t); -using CANRXBuffer_t = Circular_Buffer; -using CANTXBuffer_t = Circular_Buffer; - -/* RX buffers for CAN extern declarations*/ -template using FlexCAN_t = FlexCAN_T4; - -struct CANInterfaces_s { - explicit CANInterfaces_s(CCUInterface &ccu_int, EMInterface &em_int) : - ccu_interface(ccu_int), - em_interface(em_int) {} - - CCUInterface & ccu_interface; - EMInterface & em_interface; -}; - -using CANInterfacesInstance = etl::singleton; -namespace ACUCANInterfaceImpl { - extern CANRXBuffer_t ccu_can_rx_buffer; - extern CANRXBuffer_t em_can_rx_buffer; - extern CANTXBuffer_t ccu_can_tx_buffer; - - extern FlexCAN_t CCU_CAN; - extern FlexCAN_t EM_CAN; - - void on_ccu_can_receive(const CAN_message_t &msg); - void on_em_can_receive(const CAN_message_t &msg); - - void acu_CAN_recv(CANInterfaces_s &interfaces, const CAN_message_t &msg, unsigned long millis); - - void send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface); - -}; // namespace ACUCANInterfaceImpl - -#endif // ACUCANINTERFACEIMPL_H diff --git a/lib/interfaces/include/CCUInterface.h b/lib/interfaces/include/CCUInterface.h index 3cacfda5..ccdc34a2 100644 --- a/lib/interfaces/include/CCUInterface.h +++ b/lib/interfaces/include/CCUInterface.h @@ -12,29 +12,24 @@ #include "FlexCAN_T4.h" #include "SharedFirmwareTypes.h" #include "shared_types.h" +#include "ACUCANBuffers.h" // NEW: Include shared buffer declarations - -enum ChargingCommand_e +enum ACUChargingState_e { - CHARGE = 0, - IDLE = 1, + CHARGING = 1, + NOT_CHARGING = 0, }; namespace ccu_interface_defaults{ constexpr const uint16_t MIN_CHARGING_ENABLE_THRESHOLD_MS = 1000; - constexpr const size_t NUM_CELLS = 126; - constexpr const size_t NUM_CELLTEMPS = 48; - constexpr const size_t NUM_CHIPS = 12; constexpr const size_t VOLTAGE_CELLS_PER_GROUP = 3; constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_EVEN = 4; constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_ODD = 3; constexpr const size_t TEMP_CELL_GROUPS_PER_IC = 2; constexpr const size_t TEMP_CELLS_PER_GROUP = 2; }; + struct CCUInterfaceParams_s { unsigned long min_charging_enable_threshold; - size_t num_cells; - size_t num_celltemps; - size_t num_chips; size_t voltage_cell_groups_per_ic_even; size_t voltage_cell_groups_per_ic_odd; size_t temp_cell_groups_per_ic; @@ -43,19 +38,21 @@ struct CCUInterfaceParams_s { }; struct CCUCANInterfaceData_s { - unsigned long last_time_charging_requested; + unsigned long last_time_charging_with_balancing_requested; unsigned long prev_ccu_msg_recv_ms; - bool charging_requested; - bool is_connected_to_CCU; + size_t current_voltage_group_chip_id; size_t current_voltage_cell_group_id; size_t current_voltage_cell_id; + size_t current_temp_group_chip_id; size_t current_temp_group_id; size_t current_temp_cell_id; + size_t current_temp_board_id; }; +template class CCUInterface { public: @@ -64,9 +61,6 @@ class CCUInterface CCUInterface(unsigned long init_millis, CCUInterfaceParams_s params = { .min_charging_enable_threshold = ccu_interface_defaults::MIN_CHARGING_ENABLE_THRESHOLD_MS, - .num_cells = ccu_interface_defaults::NUM_CELLS, - .num_celltemps = ccu_interface_defaults::NUM_CELLTEMPS, - .num_chips = ccu_interface_defaults::NUM_CHIPS, .voltage_cell_groups_per_ic_even = ccu_interface_defaults::VOLTAGE_CELL_GROUPS_PER_IC_EVEN, .voltage_cell_groups_per_ic_odd = ccu_interface_defaults::VOLTAGE_CELL_GROUPS_PER_IC_ODD, .temp_cell_groups_per_ic = ccu_interface_defaults::TEMP_CELL_GROUPS_PER_IC, @@ -75,65 +69,43 @@ class CCUInterface } ) : _ccu_params{params} { - _curr_data.last_time_charging_requested = 0; + + _curr_data.last_time_charging_with_balancing_requested = 0; _curr_data.prev_ccu_msg_recv_ms = 0; - _curr_data.charging_requested = false; - _curr_data.is_connected_to_CCU = false; + _curr_data.current_voltage_cell_group_id = 0; _curr_data.current_voltage_group_chip_id = 0; _curr_data.current_voltage_cell_id = 0; + _curr_data.current_temp_group_id = 0; _curr_data.current_temp_group_chip_id = 0; _curr_data.current_temp_cell_id = 0; + + _curr_data.current_temp_board_id = 0; }; - bool is_charging_requested() { return _curr_data.charging_requested; } + bool is_connected_to_CCU(unsigned long curr_millis) {return (curr_millis - _curr_data.prev_ccu_msg_recv_ms) < _ccu_params.min_charging_enable_threshold; } - bool is_connected_to_CCU() {return _curr_data.is_connected_to_CCU; } + bool is_charging_with_balancing_requested(unsigned long curr_millis) {return (curr_millis - _curr_data.last_time_charging_with_balancing_requested) < _ccu_params.min_charging_enable_threshold; } void receive_CCU_status_message(const CAN_message_t &msg, unsigned long curr_millis); - void set_system_latch_state(unsigned long curr_millis, bool is_latched); - - CCUCANInterfaceData_s get_latest_data(unsigned long curr_millis); + void handle_enqueue_acu_status_CAN_message(bool charging_enabled); - template - void set_ACU_data(ACUAllData_s input) - { - _acu_core_data.avg_cell_voltage = input.core_data.avg_cell_voltage; - _acu_core_data.max_cell_voltage = input.core_data.max_cell_voltage; - _acu_core_data.min_cell_voltage = input.core_data.min_cell_voltage; - _acu_core_data.pack_voltage = input.core_data.pack_voltage; - for (size_t c = 0; c < num_cells; c++) - { - _acu_all_data.cell_voltages[c] = input.cell_voltages[c]; - } - for (size_t temp = 0; temp < num_celltemps; temp++) - { - _acu_all_data.cell_temps[temp] = input.cell_temps[temp]; - } - for (size_t board = 0; board < num_chips; board++) { - _acu_all_data.board_temps[board] = input.board_temps[board]; - } - _acu_all_data.core_data.max_board_temp = input.core_data.max_board_temp; - _acu_all_data.core_data.min_cell_temp = input.core_data.min_cell_temp; - _acu_all_data.core_data.max_cell_temp = input.core_data.max_cell_temp; - } + void handle_enqueue_acu_voltage_statistics_CAN_message(float max_cell_voltage, float min_cell_voltage, float pack_voltage, float avg_cell_voltage); + void handle_enqueue_acu_cell_voltages_CAN_message(const std::array& cell_voltages); + + void handle_enqueue_acu_temp_statistics_CAN_message(celsius max_board_temp, celsius max_cell_temp, celsius min_cell_temp, const std::array& board_temp); + void handle_enqueue_acu_cell_temps_CAN_message(const std::array& cell_temps); - void handle_enqueue_acu_status_CAN_message(); - void handle_enqueue_acu_core_voltages_CAN_message(); - void handle_enqueue_acu_voltages_CAN_message(); - void handle_enqueue_acu_temps_CAN_message(); + CCUCANInterfaceData_s get_latest_data(); private: CCUCANInterfaceData_s _curr_data; - ACUCoreData_s _acu_core_data; - ACUAllData_s _acu_all_data; - - unsigned long _min_charging_enable_threshold; + CCUInterfaceParams_s _ccu_params; - bool increment_and_loop_id(size_t id, size_t max_id, size_t increment = 1) + bool _increment_and_loop_id(size_t &id, size_t max_id, size_t increment = 1) { if (id == max_id - increment) { id = 0; @@ -144,9 +116,13 @@ class CCUInterface return false; } } - CCUInterfaceParams_s _ccu_params; + + }; -using CCUInterfaceInstance = etl::singleton; +template +using CCUInterfaceInstance = etl::singleton>; + +#include "CCUInterface.tpp" #endif // CCU_INTERFACE_H \ No newline at end of file diff --git a/lib/interfaces/include/CCUInterface.tpp b/lib/interfaces/include/CCUInterface.tpp new file mode 100644 index 00000000..e4ccb7e3 --- /dev/null +++ b/lib/interfaces/include/CCUInterface.tpp @@ -0,0 +1,107 @@ +#include "hytech.h" + +template +void CCUInterface::receive_CCU_status_message(const CAN_message_t& msg, unsigned long curr_millis) { + CCU_STATUS_t ccu_msg; + Unpack_CCU_STATUS_hytech(&ccu_msg, &msg.buf[0], msg.len); + + if (ccu_msg.charger_enabled) _curr_data.last_time_charging_with_balancing_requested = curr_millis; + _curr_data.prev_ccu_msg_recv_ms = curr_millis; +} + +template +void CCUInterface::handle_enqueue_acu_status_CAN_message(bool charging_enabled) { + BMS_STATUS_t msg = {}; + if (charging_enabled) { + msg.charging_state = ACUChargingState_e::CHARGING; + } else { + msg.charging_state = ACUChargingState_e::NOT_CHARGING; + } + + CAN_util::enqueue_msg(&msg, &Pack_BMS_STATUS_hytech, ACUCANBuffers::ccu_can_tx_buffer); +} + +template +void CCUInterface::handle_enqueue_acu_voltage_statistics_CAN_message( + float max_cell_voltage, float min_cell_voltage, float pack_voltage, float avg_cell_voltage +) { + BMS_VOLTAGES_t msg = {}; + msg.max_cell_voltage_ro = HYTECH_max_cell_voltage_ro_toS(max_cell_voltage); + msg.min_cell_voltage_ro = HYTECH_min_cell_voltage_ro_toS(min_cell_voltage); + msg.total_voltage_ro = HYTECH_total_voltage_ro_toS(pack_voltage); + msg.average_voltage_ro = HYTECH_average_voltage_ro_toS(avg_cell_voltage); + CAN_util::enqueue_msg(&msg, &Pack_BMS_VOLTAGES_hytech, ACUCANBuffers::ccu_can_tx_buffer); +} + +template +void CCUInterface::handle_enqueue_acu_cell_voltages_CAN_message( + const std::array& cell_voltages +) { + BMS_CELL_VOLTAGES_t msg = {}; + msg.chip_id = static_cast(_curr_data.current_voltage_group_chip_id); + msg.cell_group_id = static_cast(_curr_data.current_voltage_cell_group_id); + + msg.cell_group_voltage_0_ro = HYTECH_cell_group_voltage_0_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id]); + msg.cell_group_voltage_1_ro = HYTECH_cell_group_voltage_1_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id + 1]); + msg.cell_group_voltage_2_ro = HYTECH_cell_group_voltage_2_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id + 2]); + + bool voltage_cell_group_cycle_loop_completed; + if (_curr_data.current_voltage_group_chip_id % 2 == 0) { + voltage_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_even); + } else { + voltage_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_odd); + } + + if (voltage_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_voltage_group_chip_id, num_chips); + + _increment_and_loop_id(_curr_data.current_voltage_cell_id, num_cells, _ccu_params.voltage_cells_per_group); + + CAN_util::enqueue_msg(&msg, &Pack_BMS_CELL_VOLTAGES_hytech, ACUCANBuffers::ccu_can_tx_buffer); +} +template +void CCUInterface::handle_enqueue_acu_cell_temps_CAN_message(const std::array& cell_temps) { + BMS_CHIP_TEMPS_t chip_temps_msg = {}; + + chip_temps_msg.chip_id = static_cast(_curr_data.current_temp_group_chip_id); + chip_temps_msg.thermistor_group_id = static_cast(_curr_data.current_temp_group_id); + + chip_temps_msg.thermistor_cell_group_temp_0_ro = HYTECH_thermistor_cell_group_temp_0_ro_toS(cell_temps[_curr_data.current_temp_cell_id]); + chip_temps_msg.thermistor_cell_group_temp_1_ro = HYTECH_thermistor_cell_group_temp_1_ro_toS(cell_temps[_curr_data.current_temp_cell_id + 1]); + + bool temp_cell_group_cycle_loop_completed; + temp_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_temp_group_id, _ccu_params.temp_cell_groups_per_ic); + + if (temp_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_temp_group_chip_id, num_chips); + + _increment_and_loop_id(_curr_data.current_temp_cell_id, num_celltemps, _ccu_params.temp_cells_per_group); + + CAN_util::enqueue_msg(&chip_temps_msg, &Pack_BMS_CHIP_TEMPS_hytech, ACUCANBuffers::ccu_can_tx_buffer); + + +} + +template +void CCUInterface::handle_enqueue_acu_temp_statistics_CAN_message( + celsius max_board_temp, + celsius max_cell_temp, + celsius min_cell_temp, + const std::array& board_temps +) { + BMS_ONBOARD_TEMPS_t board_temp_msg = {}; + board_temp_msg.max_board_temp_ro = HYTECH_max_board_temp_ro_toS(max_board_temp); + board_temp_msg.max_cell_temp_ro = HYTECH_max_cell_temp_ro_toS(max_cell_temp); + board_temp_msg.min_cell_temp_ro = HYTECH_min_cell_temp_ro_toS(min_cell_temp); + CAN_util::enqueue_msg(&board_temp_msg, &Pack_BMS_ONBOARD_TEMPS_hytech, ACUCANBuffers::ccu_can_tx_buffer); + + BMS_ONBOARD_CURRENT_TEMP_t current_board_temp_msg = {}; + current_board_temp_msg.chip_id = _curr_data.current_temp_board_id; + current_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(board_temps[_curr_data.current_temp_board_id]); + _increment_and_loop_id(_curr_data.current_temp_board_id, num_chips); + CAN_util::enqueue_msg(¤t_board_temp_msg, &Pack_BMS_ONBOARD_CURRENT_TEMP_hytech, ACUCANBuffers::ccu_can_tx_buffer); +} + +template +CCUCANInterfaceData_s CCUInterface::get_latest_data() { + return _curr_data; +} + diff --git a/lib/interfaces/include/SystemTimeInterface.h b/lib/interfaces/include/SystemTimeInterface.h index 426b471c..a93fe588 100644 --- a/lib/interfaces/include/SystemTimeInterface.h +++ b/lib/interfaces/include/SystemTimeInterface.h @@ -5,6 +5,9 @@ namespace sys_time { unsigned long hal_millis(); unsigned long hal_micros(); + + unsigned long micros_to_millis(unsigned long micros); + unsigned long millis_to_micros(unsigned long millis); }; #endif // SYSTEMTIMEINTERFACE_H \ No newline at end of file diff --git a/lib/interfaces/src/ACUCANBuffers.cpp b/lib/interfaces/src/ACUCANBuffers.cpp new file mode 100644 index 00000000..ce082795 --- /dev/null +++ b/lib/interfaces/src/ACUCANBuffers.cpp @@ -0,0 +1,7 @@ +#include "ACUCANBuffers.h" + +namespace ACUCANBuffers { + CANTXBuffer_t ccu_can_tx_buffer{}; + CANRXBuffer_t ccu_can_rx_buffer{}; + CANRXBuffer_t em_can_rx_buffer{}; +} \ No newline at end of file diff --git a/lib/interfaces/src/ACUCANInterface.cpp b/lib/interfaces/src/ACUCANInterface.cpp new file mode 100644 index 00000000..5ad37442 --- /dev/null +++ b/lib/interfaces/src/ACUCANInterface.cpp @@ -0,0 +1,41 @@ +#include "ACUCANInterface.h" +#include "ACUCANBuffers.h" +#include +#include + +namespace ACUCANInterface { + +// Define CAN hardware instances +FlexCAN_t CCU_CAN; +FlexCAN_t EM_CAN; + +// CAN receive callback for CCU CAN bus +void on_ccu_can_receive(const CAN_message_t &msg) +{ + std::array buf; + std::memmove(buf.data(), &msg, sizeof(msg)); + ACUCANBuffers::ccu_can_rx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); +} + +// CAN receive callback for EM CAN bus +void on_em_can_receive(const CAN_message_t &msg) +{ + std::array buf; + std::memmove(buf.data(), &msg, sizeof(msg)); + ACUCANBuffers::em_can_rx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); +} + +// Send all queued CAN messages to the specified CAN interface +void send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface) +{ + CAN_message_t msg; + while (buffer.available()) + { + std::array buf; + buffer.pop_front(buf.data(), sizeof(CAN_message_t)); + std::memmove(&msg, buf.data(), sizeof(msg)); + can_interface->write(msg); + } +} + +} // namespace ACUCANInterface diff --git a/lib/interfaces/src/ACUCANInterfaceImpl.cpp b/lib/interfaces/src/ACUCANInterfaceImpl.cpp deleted file mode 100644 index 5d6ab7ca..00000000 --- a/lib/interfaces/src/ACUCANInterfaceImpl.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "ACUCANInterfaceImpl.h" - -CANRXBuffer_t ACUCANInterfaceImpl::ccu_can_rx_buffer; -CANRXBuffer_t ACUCANInterfaceImpl::em_can_rx_buffer; -CANTXBuffer_t ACUCANInterfaceImpl::ccu_can_tx_buffer; - -void ACUCANInterfaceImpl::on_ccu_can_receive(const CAN_message_t &msg) -{ - std::array buf; - memmove(buf.data(), &msg, sizeof(msg)); - ccu_can_rx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); -} - -void ACUCANInterfaceImpl::on_em_can_receive(const CAN_message_t &msg) -{ - std::array buf; - memmove(buf.data(), &msg, sizeof(msg)); - ccu_can_tx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); - em_can_rx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); -} - -void ACUCANInterfaceImpl::acu_CAN_recv(CANInterfaces_s &interfaces, const CAN_message_t &msg, unsigned long millis) -{ - switch (msg.id) - { - case CCU_STATUS_CANID: - { - interfaces.ccu_interface.receive_CCU_status_message(msg, millis); - break; - } - case EM_MEASUREMENT_CANID: - { - interfaces.em_interface.receive_EM_measurement_message(msg, millis); - break; - } - default: - { - break; - } - } -} - -void ACUCANInterfaceImpl::send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface) -{ - CAN_message_t msg; - while (buffer.available()) - { - std::array buf; - buffer.pop_front(buf.data(), sizeof(CAN_message_t)); - memmove(&msg, buf.data(), sizeof(msg)); - can_interface->write(msg); - } -} diff --git a/lib/interfaces/src/CCUInterface.cpp b/lib/interfaces/src/CCUInterface.cpp deleted file mode 100644 index eab7cc09..00000000 --- a/lib/interfaces/src/CCUInterface.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "CCUInterface.h" - -#include "ACUCANInterfaceImpl.h" -#include "hytech.h" - -void CCUInterface::receive_CCU_status_message(const CAN_message_t& msg, unsigned long curr_millis) { - CCU_STATUS_t ccu_msg; - Unpack_CCU_STATUS_hytech(&ccu_msg, &msg.buf[0], msg.len); - if (ccu_msg.charger_enabled == false || (_curr_data.charging_requested && ccu_msg.charger_enabled)) { - _curr_data.last_time_charging_requested = curr_millis; - } - _curr_data.is_connected_to_CCU = (curr_millis - _curr_data.prev_ccu_msg_recv_ms) < _ccu_params.min_charging_enable_threshold; - _curr_data.prev_ccu_msg_recv_ms = curr_millis; -} - -void CCUInterface::handle_enqueue_acu_status_CAN_message() { - BMS_STATUS_t msg = {}; - if (_curr_data.charging_requested) { - msg.charging_state = ChargingCommand_e::CHARGE; - } else { - msg.charging_state = ChargingCommand_e::IDLE; - } - - CAN_util::enqueue_msg(&msg, &Pack_BMS_STATUS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); -} - -void CCUInterface::handle_enqueue_acu_core_voltages_CAN_message() { - BMS_VOLTAGES_t msg = {}; - msg.max_cell_voltage_ro = HYTECH_max_cell_voltage_ro_toS(_acu_core_data.max_cell_voltage); - msg.min_cell_voltage_ro = HYTECH_min_cell_voltage_ro_toS(_acu_core_data.min_cell_voltage); - msg.total_voltage_ro = HYTECH_total_voltage_ro_toS(_acu_core_data.pack_voltage); - msg.average_voltage_ro = HYTECH_average_voltage_ro_toS(_acu_core_data.avg_cell_voltage); - CAN_util::enqueue_msg(&msg, &Pack_BMS_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); -} - -void CCUInterface::handle_enqueue_acu_voltages_CAN_message() { - BMS_CELL_VOLTAGES_t msg = {}; - msg.chip_id = static_cast(_curr_data.current_voltage_group_chip_id); - msg.cell_group_id = static_cast(_curr_data.current_voltage_cell_group_id); - msg.cell_group_voltage_0_ro = HYTECH_cell_group_voltage_0_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id]); - msg.cell_group_voltage_1_ro = HYTECH_cell_group_voltage_1_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id+1]); - msg.cell_group_voltage_2_ro = HYTECH_cell_group_voltage_2_ro_toS(_acu_all_data.cell_voltages[_curr_data.current_voltage_cell_id+2]); - bool voltage_cell_group_cycle_loop_completed; - if (_curr_data.current_voltage_group_chip_id % 2 == 0) { - voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_even); - } else { - voltage_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_odd); - } - if (voltage_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_voltage_group_chip_id, _ccu_params.num_chips); - increment_and_loop_id(_curr_data.current_voltage_cell_id, _ccu_params.num_cells, _ccu_params.voltage_cells_per_group); - CAN_util::enqueue_msg(&msg, &Pack_BMS_CELL_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); -} - -void CCUInterface::handle_enqueue_acu_temps_CAN_message() { - BMS_CHIP_TEMPS_t chip_temps_msg = {}; - chip_temps_msg.chip_id = static_cast(_curr_data.current_temp_group_chip_id); - chip_temps_msg.thermistor_group_id = static_cast(_curr_data.current_temp_group_id); - chip_temps_msg.thermistor_cell_group_temp_0_ro = HYTECH_thermistor_cell_group_temp_0_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id]); - chip_temps_msg.thermistor_cell_group_temp_1_ro = HYTECH_thermistor_cell_group_temp_1_ro_toS(_acu_all_data.cell_temps[_curr_data.current_temp_cell_id+1]); - - bool temp_cell_group_cycle_loop_completed; - temp_cell_group_cycle_loop_completed = increment_and_loop_id(_curr_data.current_temp_group_id, _ccu_params.temp_cell_groups_per_ic); - if (temp_cell_group_cycle_loop_completed) increment_and_loop_id(_curr_data.current_temp_group_chip_id, _ccu_params.num_chips); - increment_and_loop_id(_curr_data.current_temp_cell_id, _ccu_params.num_celltemps, _ccu_params.temp_cells_per_group); - CAN_util::enqueue_msg(&chip_temps_msg, &Pack_BMS_CHIP_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); - - BMS_ONBOARD_TEMPS_t board_temp_msg = {}; - board_temp_msg.max_board_temp_ro = HYTECH_max_board_temp_ro_toS(_acu_all_data.core_data.max_board_temp); - board_temp_msg.max_cell_temp_ro = HYTECH_max_cell_temp_ro_toS(_acu_all_data.core_data.max_cell_temp); - board_temp_msg.min_cell_temp_ro = HYTECH_min_cell_temp_ro_toS(_acu_all_data.core_data.min_cell_temp); - CAN_util::enqueue_msg(&board_temp_msg, &Pack_BMS_ONBOARD_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); - - BMS_ONBOARD_CURRENT_TEMP_t current_board_temp_msg = {}; - current_board_temp_msg.chip_id = _curr_data.current_temp_board_id; - current_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(_acu_all_data.board_temps[_curr_data.current_temp_board_id]); - increment_and_loop_id(_curr_data.current_temp_board_id, _ccu_params.num_chips); - CAN_util::enqueue_msg(¤t_board_temp_msg, &Pack_BMS_ONBOARD_CURRENT_TEMP_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); -} - -void CCUInterface::set_system_latch_state(unsigned long curr_millis, bool is_latched) { - _curr_data.charging_requested = is_latched && ((curr_millis - _curr_data.last_time_charging_requested) < _ccu_params.min_charging_enable_threshold); -} - -CCUCANInterfaceData_s CCUInterface::get_latest_data(unsigned long curr_millis) { - return _curr_data; -} - diff --git a/lib/interfaces/src/EMInterface.cpp b/lib/interfaces/src/EMInterface.cpp index a4100a67..76827317 100644 --- a/lib/interfaces/src/EMInterface.cpp +++ b/lib/interfaces/src/EMInterface.cpp @@ -1,5 +1,5 @@ #include "EMInterface.h" -#include "ACUCANInterfaceImpl.h" +#include "ACUCANInterface.h" void EMInterface::receive_EM_measurement_message(const CAN_message_t &msg, uint32_t curr_millis) { EM_MEASUREMENT_t em_msg; diff --git a/lib/interfaces/src/SystemTimeInterface.cpp b/lib/interfaces/src/SystemTimeInterface.cpp index 5775e599..9c278dc2 100644 --- a/lib/interfaces/src/SystemTimeInterface.cpp +++ b/lib/interfaces/src/SystemTimeInterface.cpp @@ -13,4 +13,14 @@ namespace sys_time { return micros(); } + + unsigned long micros_to_millis(unsigned long micros) + { + return micros / 1000; + } + + unsigned long millis_to_micros(unsigned long millis) + { + return millis * 1000; + } } \ No newline at end of file diff --git a/lib/interfaces/src/VCRInterface.cpp b/lib/interfaces/src/VCRInterface.cpp index a0222e85..4bb91303 100644 --- a/lib/interfaces/src/VCRInterface.cpp +++ b/lib/interfaces/src/VCRInterface.cpp @@ -1,6 +1,7 @@ #include "VCRInterface.h" -#include "ACUCANInterfaceImpl.h" +#include "ACUCANBuffers.h" +#include "ACUCANInterface.h" void VCRInterface::set_monitoring_data(bool imd_ok, bool bms_ok, bool latch_ok) { _curr_data.imd_ok = imd_ok; @@ -14,5 +15,5 @@ void VCRInterface::handle_enqueue_acu_ok_CAN_message() msg.imd_ok = _curr_data.imd_ok; msg.bms_ok = _curr_data.bms_ok; msg.latch_ok = _curr_data.latch_ok; - CAN_util::enqueue_msg(&msg, &Pack_ACU_OK_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); + CAN_util::enqueue_msg(&msg, &Pack_ACU_OK_hytech, ACUCANBuffers::ccu_can_tx_buffer); } \ No newline at end of file diff --git a/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index 3f8c653b..97810c84 100644 --- a/src/ACU_InterfaceTasks.cpp +++ b/src/ACU_InterfaceTasks.cpp @@ -7,8 +7,8 @@ static ACUAllDataType_s make_acu_all_data() { ACUAllDataType_s out{}; - auto bms = BMSDriver_t::instance().get_bms_data(); - auto fault_data = BMSFaultDataManager_t::instance().get_fault_data(); + auto bms = BMSDriverInstance_t::instance().get_bms_data(); + auto fault_data = BMSFaultDataManagerInstance_t::instance().get_fault_data(); // Copy per-cell data out.cell_voltages = bms.voltages; out.cell_temps = bms.cell_temperatures; @@ -44,7 +44,7 @@ static ACUAllDataType_s make_acu_all_data() out.core_data.min_measured_ts_out_voltage = watchdog.min_measured_ts_out_voltage; out.core_data.min_shdn_out_voltage = watchdog.min_shdn_out_voltage; // SoC/SoH placeholders (leave unchanged here) - out.SoC = ACUController_t::instance().get_status().SoC; + out.SoC = ACUControllerInstance_t::instance().get_status().SoC; return out; } @@ -67,20 +67,20 @@ void initialize_all_interfaces() FaultLatchManagerInstance::instance().set_shdn_out_latched(true); // Start shdn out latch cleared /* BMS Driver */ - BMSDriver_t::create(ACUConstants::CS, ACUConstants::CS_PER_CHIP, ACUConstants::ADDR); - BMSDriver_t::instance().init(); + BMSDriverInstance_t::create(ACUConstants::CS, ACUConstants::CS_PER_CHIP, ACUConstants::ADDR); + BMSDriverInstance_t::instance().init(); /* Get Initial Pack Voltage for SoC and SoH Approximations */ - auto data = BMSDriver_t::instance().read_data(); + auto data = BMSDriverInstance_t::instance().read_data(); - BMSFaultDataManager_t::create(); - BMSFaultDataManager_t::instance().update_from_valid_packets(data.valid_read_packets); + BMSFaultDataManagerInstance_t::create(); + BMSFaultDataManagerInstance_t::instance().update_from_valid_packets(data.valid_read_packets); /* Ethernet Interface */ ACUEthernetInterfaceInstance::create(); ACUEthernetInterfaceInstance::instance().init_ethernet_device(); /* CCU Interface */ - CCUInterfaceInstance::create(sys_time::hal_millis()); + CCUInterfaceInstance_t::create(sys_time::hal_millis()); /* VCR Interface */ VCRInterfaceInstance::create(sys_time::hal_millis()); @@ -106,7 +106,7 @@ void initialize_all_interfaces() ADCInterfaceInstance::instance().init(sys_time::hal_millis()); /* CAN Interfaces Construct */ - CANInterfacesInstance::create(CCUInterfaceInstance::instance(), EMInterfaceInstance::instance()); + CANInterfacesInstance_t::create(CCUInterfaceInstance_t::instance(), EMInterfaceInstance::instance()); } HT_TASK::TaskResponse run_kick_watchdog(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) @@ -117,8 +117,8 @@ HT_TASK::TaskResponse run_kick_watchdog(const unsigned long &sysMicros, const HT HT_TASK::TaskResponse sample_bms_data(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - auto data = BMSDriver_t::instance().read_data(); - BMSFaultDataManager_t::instance().update_from_valid_packets(data.valid_read_packets); + auto data = BMSDriverInstance_t::instance().read_data(); + BMSFaultDataManagerInstance_t::instance().update_from_valid_packets(data.valid_read_packets); // print_bms_data(data); /* Store into ACUCoreDataInstance */ @@ -127,7 +127,7 @@ HT_TASK::TaskResponse sample_bms_data(const unsigned long &sysMicros, const HT_T HT_TASK::TaskResponse write_cell_balancing_config(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - BMSDriver_t::instance().write_configuration(ACUController_t::instance().get_status().cell_balancing_statuses); + BMSDriverInstance_t::instance().write_configuration(ACUControllerInstance_t::instance().get_status().cell_balancing_statuses); return HT_TASK::TaskResponse::YIELD; } @@ -154,14 +154,13 @@ HT_TASK::TaskResponse handle_send_ACU_all_ethernet_data(const unsigned long &sys HT_TASK::TaskResponse handle_send_all_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - CCUInterfaceInstance::instance().set_system_latch_state(sys_time::hal_millis(), ADCInterfaceInstance::instance().read_shdn_out()); - ACUCANInterfaceImpl::send_all_CAN_msgs(ACUCANInterfaceImpl::ccu_can_tx_buffer, &ACUCANInterfaceImpl::CCU_CAN); + ACUCANInterface::send_all_CAN_msgs(ACUCANBuffers::ccu_can_tx_buffer, &ACUCANInterface::CCU_CAN); return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse enqueue_ACU_ok_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { FaultLatchManagerInstance::instance().clear_if_not_faulted(ACUStateMachineInstance::instance().get_state() == ACUState_e::FAULTED); - FaultLatchManagerInstance::instance().update_imd_and_bms_latches(ACUController_t::instance().get_status().bms_ok, ADCInterfaceInstance::instance().read_imd_ok(sys_time::hal_millis())); + FaultLatchManagerInstance::instance().update_imd_and_bms_latches(ACUControllerInstance_t::instance().get_status().bms_ok, ADCInterfaceInstance::instance().read_imd_ok(sys_time::hal_millis())); //TODO: Where should I get veh_shdn_out_latched from? VCRInterfaceInstance::instance().set_monitoring_data(!FaultLatchManagerInstance::instance().get_latches().imd_fault_latched, !FaultLatchManagerInstance::instance().get_latches().bms_fault_latched, FaultLatchManagerInstance::instance().get_latches().shdn_out_latched); @@ -175,32 +174,44 @@ HT_TASK::TaskResponse enqueue_ACU_ok_CAN_data(const unsigned long& sysMicros, co } HT_TASK::TaskResponse enqueue_ACU_core_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - auto data = make_acu_all_data(); - CCUInterfaceInstance::instance().set_ACU_data(data); - CCUInterfaceInstance::instance().handle_enqueue_acu_status_CAN_message(); - CCUInterfaceInstance::instance().handle_enqueue_acu_core_voltages_CAN_message(); + auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); + CCUInterfaceInstance_t::instance().handle_enqueue_acu_status_CAN_message(ACUControllerInstance_t::instance().get_status().charging_enabled); + CCUInterfaceInstance_t::instance().handle_enqueue_acu_voltage_statistics_CAN_message( + bms_data.max_cell_voltage, + bms_data.min_cell_voltage, + bms_data.total_voltage, + bms_data.avg_cell_voltage + ); + CCUInterfaceInstance_t::instance().handle_enqueue_acu_temp_statistics_CAN_message( + bms_data.max_board_temp, + bms_data.max_cell_temp, + bms_data.min_cell_temp, + bms_data.board_temperatures + ); return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse enqueue_ACU_all_voltages_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - if (CCUInterfaceInstance::instance().is_connected_to_CCU()) { - CCUInterfaceInstance::instance().handle_enqueue_acu_voltages_CAN_message(); + auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); + if (CCUInterfaceInstance_t::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { + CCUInterfaceInstance_t::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages); } return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse enqueue_ACU_all_temps_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - if (CCUInterfaceInstance::instance().is_connected_to_CCU()) { - CCUInterfaceInstance::instance().handle_enqueue_acu_temps_CAN_message(); + auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); + if (CCUInterfaceInstance_t::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { + CCUInterfaceInstance_t::instance().handle_enqueue_acu_cell_temps_CAN_message(bms_data.cell_temperatures); } return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse sample_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - etl::delegate main_can_recv = etl::delegate::create(); - process_ring_buffer(ACUCANInterfaceImpl::ccu_can_rx_buffer, CANInterfacesInstance::instance(), sys_time::hal_millis(), main_can_recv); - process_ring_buffer(ACUCANInterfaceImpl::em_can_rx_buffer, CANInterfacesInstance::instance(), sys_time::hal_millis(), main_can_recv); + etl::delegate main_can_recv = etl::delegate::create(); + process_ring_buffer(ACUCANBuffers::ccu_can_rx_buffer, CANInterfacesInstance_t::instance(), sys_time::hal_millis(), main_can_recv); + process_ring_buffer(ACUCANBuffers::em_can_rx_buffer, CANInterfacesInstance_t::instance(), sys_time::hal_millis(), main_can_recv); return HT_TASK::TaskResponse::YIELD; } @@ -282,7 +293,7 @@ void print_bms_data(bms_data data) temp_index++; } Serial.print("Number of Global Faults: "); - Serial.println(BMSFaultDataManager_t::instance().get_fault_data().max_consecutive_invalid_packet_count); + Serial.println(BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count); Serial.println("Number of Consecutive Faults Per Chip: "); for (size_t c = 0; c < ACUConstants::NUM_CHIPS; c++) { Serial.print("CHIP "); @@ -309,7 +320,7 @@ void print_bms_data(bms_data data) HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - if (ACUController_t::instance().get_status().bms_ok) + if (ACUControllerInstance_t::instance().get_status().bms_ok) { Serial.print("BMS is OK\n"); } @@ -334,36 +345,36 @@ HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK: Serial.println(); Serial.print("Pack Voltage: "); - Serial.println(BMSDriver_t::instance().get_bms_data().total_voltage, 4); + Serial.println(BMSDriverInstance_t::instance().get_bms_data().total_voltage, 4); Serial.print("Minimum Cell Voltage: "); - Serial.println(BMSDriver_t::instance().get_bms_data().min_cell_voltage, 4); + Serial.println(BMSDriverInstance_t::instance().get_bms_data().min_cell_voltage, 4); Serial.print("Maximum Cell Voltage: "); - Serial.println(BMSDriver_t::instance().get_bms_data().max_cell_voltage, 4); + Serial.println(BMSDriverInstance_t::instance().get_bms_data().max_cell_voltage, 4); Serial.print("Maximum Board Temp: "); - Serial.println(BMSDriver_t::instance().get_bms_data().max_board_temp, 4); + Serial.println(BMSDriverInstance_t::instance().get_bms_data().max_board_temp, 4); Serial.print("Maximum Cell Temp: "); - Serial.println(BMSDriver_t::instance().get_bms_data().max_cell_temp, 4); + Serial.println(BMSDriverInstance_t::instance().get_bms_data().max_cell_temp, 4); - Serial.printf("Cell Balance Statuses: %d\n", ACUController_t::instance().get_status().cell_balancing_statuses); + Serial.printf("Cell Balance Statuses: %d\n", ACUControllerInstance_t::instance().get_status().cell_balancing_statuses); Serial.print("ACU State: "); Serial.println(static_cast(ACUStateMachineInstance::instance().get_state())); Serial.print("CCU Charging Requested? : "); - Serial.println(CCUInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).charging_requested); + Serial.println(CCUInterfaceInstance_t::instance().is_charging_with_balancing_requested(sys_time::hal_millis()) ? "YES" : "NO"); Serial.print("State of Charge: "); - Serial.print(ACUController_t::instance().get_status().SoC * 100, 3); + Serial.print(ACUControllerInstance_t::instance().get_status().SoC * 100, 3); Serial.println("%"); Serial.print("Measured GLV: "); Serial.println("V"); Serial.println(); Serial.print("Number of Global Faults: "); - Serial.println(BMSFaultDataManager_t::instance().get_fault_data().max_consecutive_invalid_packet_count); + Serial.println(BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count); // Serial.println("Number of Consecutive Faults Per Chip: "); // for (size_t c = 0; c < ACUConstants::NUM_CHIPS; c++) { // Serial.print("CHIP "); diff --git a/src/ACU_SystemTasks.cpp b/src/ACU_SystemTasks.cpp index fe63bc10..e35bca3f 100644 --- a/src/ACU_SystemTasks.cpp +++ b/src/ACU_SystemTasks.cpp @@ -16,7 +16,7 @@ bool initialize_all_systems() /* Delegate Function Definitions */ etl::delegate charge_state_request = etl::delegate::create([]() -> bool - { return CCUInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).charging_requested; }); + { return CCUInterfaceInstance_t::instance().is_charging_with_balancing_requested(sys_time::hal_millis()); }); etl::delegate has_bms_fault = etl::delegate::create([]() -> bool { return !ACUControllerInstance_t::instance().get_status().bms_ok; }); diff --git a/src/main.cpp b/src/main.cpp index 48754f87..2faa4a56 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,7 @@ #include #include "BMSDriverGroup.h" #include "WatchdogInterface.h" -#include "ACUCANInterfaceImpl.h" +#include "ACUCANInterface.h" /* System Includes */ #include "ACUController.h" @@ -37,9 +37,6 @@ ::HT_TASK::Task sample_CAN_task(HT_TASK::DUMMY_FUNCTION, sample_CAN_data, ACUCon ::HT_TASK::Task idle_sample_task(HT_TASK::DUMMY_FUNCTION, idle_sample_interfaces, ACUConstants::IDLE_SAMPLE_PRIORITY, ACUConstants::IDLE_SAMPLE_PERIOD_US); ::HT_TASK::Task debug_prints_task(HT_TASK::DUMMY_FUNCTION, debug_print, ACUConstants::DEBUG_PRINT_PRIORITY, ACUConstants::DEBUG_PRINT_PERIOD_US); -FlexCAN_t ACUCANInterfaceImpl::CCU_CAN; -FlexCAN_t ACUCANInterfaceImpl::EM_CAN; - void setup() { /* Interface and System initialization */ @@ -67,8 +64,8 @@ void setup() //scheduler.schedule(debug_prints_task); - handle_CAN_setup(ACUCANInterfaceImpl::CCU_CAN, ACUConstants::Veh_CAN_baudrate, &ACUCANInterfaceImpl::on_ccu_can_receive); - handle_CAN_setup(ACUCANInterfaceImpl::EM_CAN, ACUConstants::EM_CAN_baudrate, &ACUCANInterfaceImpl::on_em_can_receive); + handle_CAN_setup(ACUCANInterface::CCU_CAN, ACUConstants::Veh_CAN_baudrate, &ACUCANInterface::on_ccu_can_receive); + handle_CAN_setup(ACUCANInterface::EM_CAN, ACUConstants::EM_CAN_baudrate, &ACUCANInterface::on_em_can_receive); } void loop() From c9aa1509a935bcaa2dc3b9c102da0aa499242928 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Tue, 4 Nov 2025 14:06:44 -0800 Subject: [PATCH 07/18] fixed magic number error --- lib/interfaces/include/SystemTimeInterface.h | 3 +++ lib/interfaces/src/SystemTimeInterface.cpp | 4 ++-- platformio.ini | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/interfaces/include/SystemTimeInterface.h b/lib/interfaces/include/SystemTimeInterface.h index a93fe588..f06b550d 100644 --- a/lib/interfaces/include/SystemTimeInterface.h +++ b/lib/interfaces/include/SystemTimeInterface.h @@ -8,6 +8,9 @@ namespace sys_time unsigned long micros_to_millis(unsigned long micros); unsigned long millis_to_micros(unsigned long millis); + + const unsigned long MILLIS_TO_MICROS_FACTOR = 1000; + const unsigned long MICROS_TO_MILLIS_FACTOR = 0.001; }; #endif // SYSTEMTIMEINTERFACE_H \ No newline at end of file diff --git a/lib/interfaces/src/SystemTimeInterface.cpp b/lib/interfaces/src/SystemTimeInterface.cpp index 9c278dc2..3a3332e3 100644 --- a/lib/interfaces/src/SystemTimeInterface.cpp +++ b/lib/interfaces/src/SystemTimeInterface.cpp @@ -16,11 +16,11 @@ namespace sys_time unsigned long micros_to_millis(unsigned long micros) { - return micros / 1000; + return micros * MICROS_TO_MILLIS_FACTOR; } unsigned long millis_to_micros(unsigned long millis) { - return millis * 1000; + return millis * MILLIS_TO_MICROS_FACTOR; } } \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index d8c3d55a..1cd64899 100644 --- a/platformio.ini +++ b/platformio.ini @@ -116,7 +116,7 @@ lib_deps= https://github.com/hytech-racing/HT_CAN/releases/download/209/can_lib.tar.gz https://github.com/hytech-racing/HT_SCHED.git https://github.com/hytech-racing/HT_proto/releases/download/2025-08-27T15_34_50/hytech_msgs_pb_lib.tar.gz - https://github.com/hytech-racing/shared_firmware_interfaces.git + https://github.com/hytech-racing/shared_firmware_interfaces.git#5baf17a0f6d83d0a9d571d6bf56f409d2c8ad98a https://github.com/KSU-MS/pio-git-hash-gen#7998b5b3f8a2464209b0e73338717998bcf511ee Nanopb arkhipenko/TaskScheduler@^3.8.5 From 7990f1f64837b15518b1aa9843235aaaf4440507 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Tue, 4 Nov 2025 16:45:09 -0800 Subject: [PATCH 08/18] removed templating for CCUInterface --- include/ACU_Constants.h | 2 + include/ACU_InterfaceTasks.h | 3 - include/ACU_SystemTasks.h | 1 - lib/interfaces/include/ACUCANInterface.h | 13 ++-- lib/interfaces/include/ACUCANInterface.tpp | 24 ------- lib/interfaces/include/CCUInterface.h | 14 ++-- lib/interfaces/src/ACUCANInterface.cpp | 25 +++++++ .../CCUInterface.tpp => src/CCUInterface.cpp} | 70 +++++++++++-------- src/ACU_InterfaceTasks.cpp | 29 ++++---- src/ACU_SystemTasks.cpp | 2 +- 10 files changed, 91 insertions(+), 92 deletions(-) delete mode 100644 lib/interfaces/include/ACUCANInterface.tpp rename lib/interfaces/{include/CCUInterface.tpp => src/CCUInterface.cpp} (62%) diff --git a/include/ACU_Constants.h b/include/ACU_Constants.h index 4d8bc384..d5fe2d5a 100644 --- a/include/ACU_Constants.h +++ b/include/ACU_Constants.h @@ -57,6 +57,8 @@ namespace ACUConstants constexpr size_t NUM_CHIPS = 12; constexpr size_t NUM_BOARD_TEMPS = 12; constexpr size_t NUM_CHIP_SELECTS = 2; + constexpr std::array CELLS_PER_CHIP = {12, 9, 12, 9, 12, 9, 12, 9, 12, 9, 12, 9}; + constexpr std::array TEMP_CELLS_PER_CHIP = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; const float VALID_SHDN_OUT_MIN_VOLTAGE_THRESHOLD = 12.0F; const uint32_t MIN_ALLOWED_INVALID_SHDN_OUT_MS = 10; // 10 ms -- requies 100 Hz samp freq. diff --git a/include/ACU_InterfaceTasks.h b/include/ACU_InterfaceTasks.h index 4b7ac237..5a6cde3e 100644 --- a/include/ACU_InterfaceTasks.h +++ b/include/ACU_InterfaceTasks.h @@ -27,9 +27,6 @@ using chip_type = LTC6811_Type_e; using BMSDriverInstance_t = BMSDriverInstance; using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; using ACUControllerInstance_t = ACUControllerInstance; -using CCUInterfaceInstance_t = CCUInterfaceInstance; -using CANInterfacesInstance_t = CANInterfacesInstance; -using CANInterfaces_t = CANInterfaces_s; /** * Init Functions - to be called in setup */ diff --git a/include/ACU_SystemTasks.h b/include/ACU_SystemTasks.h index 6b896f07..79a6f4d3 100644 --- a/include/ACU_SystemTasks.h +++ b/include/ACU_SystemTasks.h @@ -20,7 +20,6 @@ using chip_type = LTC6811_Type_e; using ACUControllerInstance_t = ACUControllerInstance; using BMSDriverInstance_t = BMSDriverInstance; -using CCUInterfaceInstance_t = CCUInterfaceInstance; bool initialize_all_systems(); /* Delegate Functions */ diff --git a/lib/interfaces/include/ACUCANInterface.h b/lib/interfaces/include/ACUCANInterface.h index dd56c596..7d2b62c6 100644 --- a/lib/interfaces/include/ACUCANInterface.h +++ b/lib/interfaces/include/ACUCANInterface.h @@ -24,18 +24,16 @@ template using FlexCAN_t = FlexCAN_T4; /* CANInterfaces struct - holds references to all CAN-connected interfaces */ -template struct CANInterfaces_s { - explicit CANInterfaces_s(CCUInterface &ccu_int, EMInterface &em_int) : + explicit CANInterfaces_s(CCUInterface &ccu_int, EMInterface &em_int) : ccu_interface(ccu_int), em_interface(em_int) {} - CCUInterface & ccu_interface; + CCUInterface& ccu_interface; EMInterface & em_interface; }; -template -using CANInterfacesInstance = etl::singleton>; +using CANInterfacesInstance = etl::singleton; /* ACUCANInterface namespace - Main CAN interface handler functions */ namespace ACUCANInterface { @@ -48,8 +46,7 @@ namespace ACUCANInterface { void on_em_can_receive(const CAN_message_t &msg); // Main CAN message handler (templated free function) - template - void acu_CAN_recv(CANInterfaces_s &interfaces, + void acu_CAN_recv(CANInterfaces_s &interfaces, const CAN_message_t &msg, unsigned long millis); @@ -57,6 +54,4 @@ namespace ACUCANInterface { void send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface); } -#include "ACUCANInterface.tpp" - #endif diff --git a/lib/interfaces/include/ACUCANInterface.tpp b/lib/interfaces/include/ACUCANInterface.tpp deleted file mode 100644 index 9faaab60..00000000 --- a/lib/interfaces/include/ACUCANInterface.tpp +++ /dev/null @@ -1,24 +0,0 @@ -template -void ACUCANInterface::acu_CAN_recv( - CANInterfaces_s &interfaces, - const CAN_message_t &msg, - unsigned long millis) -{ - switch (msg.id) - { - case CCU_STATUS_CANID: - { - interfaces.ccu_interface.receive_CCU_status_message(msg, millis); - break; - } - case EM_MEASUREMENT_CANID: - { - interfaces.em_interface.receive_EM_measurement_message(msg, millis); - break; - } - default: - { - break; - } - } -} diff --git a/lib/interfaces/include/CCUInterface.h b/lib/interfaces/include/CCUInterface.h index ccdc34a2..e304ac5e 100644 --- a/lib/interfaces/include/CCUInterface.h +++ b/lib/interfaces/include/CCUInterface.h @@ -52,7 +52,6 @@ struct CCUCANInterfaceData_s size_t current_temp_board_id; }; -template class CCUInterface { public: @@ -94,10 +93,10 @@ class CCUInterface void handle_enqueue_acu_status_CAN_message(bool charging_enabled); void handle_enqueue_acu_voltage_statistics_CAN_message(float max_cell_voltage, float min_cell_voltage, float pack_voltage, float avg_cell_voltage); - void handle_enqueue_acu_cell_voltages_CAN_message(const std::array& cell_voltages); - - void handle_enqueue_acu_temp_statistics_CAN_message(celsius max_board_temp, celsius max_cell_temp, celsius min_cell_temp, const std::array& board_temp); - void handle_enqueue_acu_cell_temps_CAN_message(const std::array& cell_temps); + void handle_enqueue_acu_cell_voltages_CAN_message(const volt* cell_voltages, const size_t* voltage_cells_per_chip, const size_t num_of_chips); + void handle_enqueue_acu_temp_statistics_CAN_message(celsius max_board_temp, celsius max_cell_temp, celsius min_cell_temp); + void handle_enqueue_acu_cell_temps_CAN_message(const celsius* cell_temps, const size_t* temp_cells_per_chip, const size_t num_of_chips); + void handle_enqueue_acu_cell_board_temps_CAN_message(const celsius* board_temps, const size_t num_of_boards); CCUCANInterfaceData_s get_latest_data(); @@ -120,9 +119,6 @@ class CCUInterface }; -template -using CCUInterfaceInstance = etl::singleton>; - -#include "CCUInterface.tpp" +using CCUInterfaceInstance = etl::singleton; #endif // CCU_INTERFACE_H \ No newline at end of file diff --git a/lib/interfaces/src/ACUCANInterface.cpp b/lib/interfaces/src/ACUCANInterface.cpp index 5ad37442..0e78e15a 100644 --- a/lib/interfaces/src/ACUCANInterface.cpp +++ b/lib/interfaces/src/ACUCANInterface.cpp @@ -38,4 +38,29 @@ void send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface) } } +void acu_CAN_recv( + CANInterfaces_s &interfaces, + const CAN_message_t &msg, + unsigned long millis) +{ + switch (msg.id) + { + case CCU_STATUS_CANID: + { + interfaces.ccu_interface.receive_CCU_status_message(msg, millis); + break; + } + case EM_MEASUREMENT_CANID: + { + interfaces.em_interface.receive_EM_measurement_message(msg, millis); + break; + } + default: + { + break; + } + } +} + + } // namespace ACUCANInterface diff --git a/lib/interfaces/include/CCUInterface.tpp b/lib/interfaces/src/CCUInterface.cpp similarity index 62% rename from lib/interfaces/include/CCUInterface.tpp rename to lib/interfaces/src/CCUInterface.cpp index e4ccb7e3..0ab3db08 100644 --- a/lib/interfaces/include/CCUInterface.tpp +++ b/lib/interfaces/src/CCUInterface.cpp @@ -1,7 +1,7 @@ #include "hytech.h" +#include "CCUInterface.h" -template -void CCUInterface::receive_CCU_status_message(const CAN_message_t& msg, unsigned long curr_millis) { +void CCUInterface::receive_CCU_status_message(const CAN_message_t& msg, unsigned long curr_millis) { CCU_STATUS_t ccu_msg; Unpack_CCU_STATUS_hytech(&ccu_msg, &msg.buf[0], msg.len); @@ -9,8 +9,7 @@ void CCUInterface::receive_CCU_status_messa _curr_data.prev_ccu_msg_recv_ms = curr_millis; } -template -void CCUInterface::handle_enqueue_acu_status_CAN_message(bool charging_enabled) { +void CCUInterface::handle_enqueue_acu_status_CAN_message(bool charging_enabled) { BMS_STATUS_t msg = {}; if (charging_enabled) { msg.charging_state = ACUChargingState_e::CHARGING; @@ -21,8 +20,7 @@ void CCUInterface::handle_enqueue_acu_statu CAN_util::enqueue_msg(&msg, &Pack_BMS_STATUS_hytech, ACUCANBuffers::ccu_can_tx_buffer); } -template -void CCUInterface::handle_enqueue_acu_voltage_statistics_CAN_message( +void CCUInterface::handle_enqueue_acu_voltage_statistics_CAN_message( float max_cell_voltage, float min_cell_voltage, float pack_voltage, float avg_cell_voltage ) { BMS_VOLTAGES_t msg = {}; @@ -33,75 +31,87 @@ void CCUInterface::handle_enqueue_acu_volta CAN_util::enqueue_msg(&msg, &Pack_BMS_VOLTAGES_hytech, ACUCANBuffers::ccu_can_tx_buffer); } -template -void CCUInterface::handle_enqueue_acu_cell_voltages_CAN_message( - const std::array& cell_voltages +void CCUInterface::handle_enqueue_acu_cell_voltages_CAN_message( + const volt* cell_voltages, + const size_t* voltage_cells_per_chip, + const size_t num_of_chips ) { BMS_CELL_VOLTAGES_t msg = {}; + size_t num_of_groups, num_of_voltage_cells; + bool voltage_cell_group_cycle_loop_completed; + msg.chip_id = static_cast(_curr_data.current_voltage_group_chip_id); msg.cell_group_id = static_cast(_curr_data.current_voltage_cell_group_id); + num_of_groups = voltage_cells_per_chip[_curr_data.current_voltage_group_chip_id] / _ccu_params.voltage_cells_per_group; + num_of_voltage_cells = std::accumulate(voltage_cells_per_chip, voltage_cells_per_chip + num_of_chips, 0); + msg.cell_group_voltage_0_ro = HYTECH_cell_group_voltage_0_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id]); msg.cell_group_voltage_1_ro = HYTECH_cell_group_voltage_1_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id + 1]); msg.cell_group_voltage_2_ro = HYTECH_cell_group_voltage_2_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id + 2]); - bool voltage_cell_group_cycle_loop_completed; - if (_curr_data.current_voltage_group_chip_id % 2 == 0) { - voltage_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_even); - } else { - voltage_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_voltage_cell_group_id, _ccu_params.voltage_cell_groups_per_ic_odd); - } + voltage_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_voltage_cell_group_id, num_of_groups); - if (voltage_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_voltage_group_chip_id, num_chips); + if (voltage_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_voltage_group_chip_id, num_of_chips); - _increment_and_loop_id(_curr_data.current_voltage_cell_id, num_cells, _ccu_params.voltage_cells_per_group); + _increment_and_loop_id(_curr_data.current_voltage_cell_id, num_of_voltage_cells, _ccu_params.voltage_cells_per_group); CAN_util::enqueue_msg(&msg, &Pack_BMS_CELL_VOLTAGES_hytech, ACUCANBuffers::ccu_can_tx_buffer); } -template -void CCUInterface::handle_enqueue_acu_cell_temps_CAN_message(const std::array& cell_temps) { +void CCUInterface::handle_enqueue_acu_cell_temps_CAN_message( + const celsius* cell_temps, + const size_t* temp_cells_per_chip, + const size_t num_of_chips +) { BMS_CHIP_TEMPS_t chip_temps_msg = {}; + size_t num_of_groups, num_of_temp_cells; + bool voltage_cell_group_cycle_loop_completed; chip_temps_msg.chip_id = static_cast(_curr_data.current_temp_group_chip_id); chip_temps_msg.thermistor_group_id = static_cast(_curr_data.current_temp_group_id); + num_of_groups = temp_cells_per_chip[_curr_data.current_temp_group_chip_id] / _ccu_params.temp_cells_per_group; + num_of_temp_cells = std::accumulate(temp_cells_per_chip, temp_cells_per_chip + num_of_chips, 0); + chip_temps_msg.thermistor_cell_group_temp_0_ro = HYTECH_thermistor_cell_group_temp_0_ro_toS(cell_temps[_curr_data.current_temp_cell_id]); chip_temps_msg.thermistor_cell_group_temp_1_ro = HYTECH_thermistor_cell_group_temp_1_ro_toS(cell_temps[_curr_data.current_temp_cell_id + 1]); bool temp_cell_group_cycle_loop_completed; - temp_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_temp_group_id, _ccu_params.temp_cell_groups_per_ic); + temp_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_temp_group_id, num_of_groups); - if (temp_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_temp_group_chip_id, num_chips); + if (temp_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_temp_group_chip_id, num_of_chips); - _increment_and_loop_id(_curr_data.current_temp_cell_id, num_celltemps, _ccu_params.temp_cells_per_group); + _increment_and_loop_id(_curr_data.current_temp_cell_id, num_of_temp_cells, _ccu_params.temp_cells_per_group); CAN_util::enqueue_msg(&chip_temps_msg, &Pack_BMS_CHIP_TEMPS_hytech, ACUCANBuffers::ccu_can_tx_buffer); } -template -void CCUInterface::handle_enqueue_acu_temp_statistics_CAN_message( +void CCUInterface::handle_enqueue_acu_temp_statistics_CAN_message( celsius max_board_temp, celsius max_cell_temp, - celsius min_cell_temp, - const std::array& board_temps + celsius min_cell_temp ) { BMS_ONBOARD_TEMPS_t board_temp_msg = {}; board_temp_msg.max_board_temp_ro = HYTECH_max_board_temp_ro_toS(max_board_temp); board_temp_msg.max_cell_temp_ro = HYTECH_max_cell_temp_ro_toS(max_cell_temp); board_temp_msg.min_cell_temp_ro = HYTECH_min_cell_temp_ro_toS(min_cell_temp); CAN_util::enqueue_msg(&board_temp_msg, &Pack_BMS_ONBOARD_TEMPS_hytech, ACUCANBuffers::ccu_can_tx_buffer); +} - BMS_ONBOARD_CURRENT_TEMP_t current_board_temp_msg = {}; +void CCUInterface::handle_enqueue_acu_cell_board_temps_CAN_message( + const celsius* board_temps, + const size_t num_of_boards +) { + BMS_ONBOARD_CURRENT_TEMP_t current_board_temp_msg = {}; current_board_temp_msg.chip_id = _curr_data.current_temp_board_id; current_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(board_temps[_curr_data.current_temp_board_id]); - _increment_and_loop_id(_curr_data.current_temp_board_id, num_chips); + _increment_and_loop_id(_curr_data.current_temp_board_id, num_of_boards); CAN_util::enqueue_msg(¤t_board_temp_msg, &Pack_BMS_ONBOARD_CURRENT_TEMP_hytech, ACUCANBuffers::ccu_can_tx_buffer); } -template -CCUCANInterfaceData_s CCUInterface::get_latest_data() { +CCUCANInterfaceData_s CCUInterface::get_latest_data() { return _curr_data; } diff --git a/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index 97810c84..7982b029 100644 --- a/src/ACU_InterfaceTasks.cpp +++ b/src/ACU_InterfaceTasks.cpp @@ -80,7 +80,7 @@ void initialize_all_interfaces() /* CCU Interface */ - CCUInterfaceInstance_t::create(sys_time::hal_millis()); + CCUInterfaceInstance::create(sys_time::hal_millis()); /* VCR Interface */ VCRInterfaceInstance::create(sys_time::hal_millis()); @@ -106,7 +106,7 @@ void initialize_all_interfaces() ADCInterfaceInstance::instance().init(sys_time::hal_millis()); /* CAN Interfaces Construct */ - CANInterfacesInstance_t::create(CCUInterfaceInstance_t::instance(), EMInterfaceInstance::instance()); + CANInterfacesInstance::create(CCUInterfaceInstance::instance(), EMInterfaceInstance::instance()); } HT_TASK::TaskResponse run_kick_watchdog(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) @@ -175,18 +175,17 @@ HT_TASK::TaskResponse enqueue_ACU_ok_CAN_data(const unsigned long& sysMicros, co HT_TASK::TaskResponse enqueue_ACU_core_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); - CCUInterfaceInstance_t::instance().handle_enqueue_acu_status_CAN_message(ACUControllerInstance_t::instance().get_status().charging_enabled); - CCUInterfaceInstance_t::instance().handle_enqueue_acu_voltage_statistics_CAN_message( + CCUInterfaceInstance::instance().handle_enqueue_acu_status_CAN_message(ACUControllerInstance_t::instance().get_status().charging_enabled); + CCUInterfaceInstance::instance().handle_enqueue_acu_voltage_statistics_CAN_message( bms_data.max_cell_voltage, bms_data.min_cell_voltage, bms_data.total_voltage, bms_data.avg_cell_voltage ); - CCUInterfaceInstance_t::instance().handle_enqueue_acu_temp_statistics_CAN_message( + CCUInterfaceInstance::instance().handle_enqueue_acu_temp_statistics_CAN_message( bms_data.max_board_temp, bms_data.max_cell_temp, - bms_data.min_cell_temp, - bms_data.board_temperatures + bms_data.min_cell_temp ); return HT_TASK::TaskResponse::YIELD; } @@ -194,24 +193,24 @@ HT_TASK::TaskResponse enqueue_ACU_core_CAN_data(const unsigned long& sysMicros, HT_TASK::TaskResponse enqueue_ACU_all_voltages_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); - if (CCUInterfaceInstance_t::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance_t::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages); + if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { + CCUInterfaceInstance::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages.data(), ACUConstants::CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIPS); } return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse enqueue_ACU_all_temps_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); - if (CCUInterfaceInstance_t::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance_t::instance().handle_enqueue_acu_cell_temps_CAN_message(bms_data.cell_temperatures); + if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { + CCUInterfaceInstance::instance().handle_enqueue_acu_cell_temps_CAN_message(bms_data.cell_temperatures.data(), ACUConstants::TEMP_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIPS); } return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse sample_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - etl::delegate main_can_recv = etl::delegate::create(); - process_ring_buffer(ACUCANBuffers::ccu_can_rx_buffer, CANInterfacesInstance_t::instance(), sys_time::hal_millis(), main_can_recv); - process_ring_buffer(ACUCANBuffers::em_can_rx_buffer, CANInterfacesInstance_t::instance(), sys_time::hal_millis(), main_can_recv); + etl::delegate main_can_recv = etl::delegate::create(); + process_ring_buffer(ACUCANBuffers::ccu_can_rx_buffer, CANInterfacesInstance::instance(), sys_time::hal_millis(), main_can_recv); + process_ring_buffer(ACUCANBuffers::em_can_rx_buffer, CANInterfacesInstance::instance(), sys_time::hal_millis(), main_can_recv); return HT_TASK::TaskResponse::YIELD; } @@ -365,7 +364,7 @@ HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK: Serial.println(static_cast(ACUStateMachineInstance::instance().get_state())); Serial.print("CCU Charging Requested? : "); - Serial.println(CCUInterfaceInstance_t::instance().is_charging_with_balancing_requested(sys_time::hal_millis()) ? "YES" : "NO"); + Serial.println(CCUInterfaceInstance::instance().is_charging_with_balancing_requested(sys_time::hal_millis()) ? "YES" : "NO"); Serial.print("State of Charge: "); Serial.print(ACUControllerInstance_t::instance().get_status().SoC * 100, 3); Serial.println("%"); diff --git a/src/ACU_SystemTasks.cpp b/src/ACU_SystemTasks.cpp index e35bca3f..6fdd9e15 100644 --- a/src/ACU_SystemTasks.cpp +++ b/src/ACU_SystemTasks.cpp @@ -16,7 +16,7 @@ bool initialize_all_systems() /* Delegate Function Definitions */ etl::delegate charge_state_request = etl::delegate::create([]() -> bool - { return CCUInterfaceInstance_t::instance().is_charging_with_balancing_requested(sys_time::hal_millis()); }); + { return CCUInterfaceInstance::instance().is_charging_with_balancing_requested(sys_time::hal_millis()); }); etl::delegate has_bms_fault = etl::delegate::create([]() -> bool { return !ACUControllerInstance_t::instance().get_status().bms_ok; }); From 6f8e86c2746529eb1da6e8338486917fa69d7299 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Tue, 4 Nov 2025 22:14:24 -0800 Subject: [PATCH 09/18] got rid of ACUController template stuff and added new tests for acucontroller structure --- include/ACU_Constants.h | 193 +++++++++++++++++- include/ACU_InterfaceTasks.h | 1 - include/ACU_SystemTasks.h | 3 +- lib/interfaces/include/BMSDriverGroup.h | 70 +------ lib/interfaces/include/BMSDriverGroup.tpp | 78 ++++--- lib/shared_types/shared_types.h | 174 +++++++++++++++- lib/systems/include/ACUController.h | 44 ++-- .../ACUController.cpp} | 62 +++--- src/ACU_InterfaceTasks.cpp | 21 +- src/ACU_SystemTasks.cpp | 17 +- test/test_systems/test_acu_controller.h | 164 +++++++-------- 11 files changed, 554 insertions(+), 273 deletions(-) rename lib/systems/{include/ACUController.tpp => src/ACUController.cpp} (70%) diff --git a/include/ACU_Constants.h b/include/ACU_Constants.h index d5fe2d5a..5eac4677 100644 --- a/include/ACU_Constants.h +++ b/include/ACU_Constants.h @@ -7,6 +7,7 @@ #include #include #include +#include "shared_types.h" using volt = float; using celsius = float; @@ -14,6 +15,7 @@ using time_ms = uint32_t; namespace ACUSystems { + constexpr const volt MIN_DISCHARGE_VOLTAGE_THRESH = 3.8F; // Minimum voltage for a cell to be discharged constexpr const volt CELL_OVERVOLTAGE_THRESH = 4.2; // Cell overvoltage threshold in Volts constexpr const volt CELL_UNDERVOLTAGE_THRESH = 3.05; // Cell undervoltage threshold in Volts constexpr const volt MIN_PACK_TOTAL_VOLTAGE = 420.0; // Volts @@ -51,18 +53,195 @@ namespace ACUInterfaces { } namespace ACUConstants -{ +{ constexpr size_t NUM_CELLS = 126; - constexpr size_t NUM_CELL_TEMPS = 48; constexpr size_t NUM_CHIPS = 12; - constexpr size_t NUM_BOARD_TEMPS = 12; constexpr size_t NUM_CHIP_SELECTS = 2; - constexpr std::array CELLS_PER_CHIP = {12, 9, 12, 9, 12, 9, 12, 9, 12, 9, 12, 9}; - constexpr std::array TEMP_CELLS_PER_CHIP = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; - + constexpr size_t NUM_CHIPS_PER_CS = 6; + constexpr size_t DATA_PER_CHIP_GROUP = 3; + + constexpr std::array TEMP_CELLS_PER_CHIP = { + 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4 + }; + constexpr std::array VOLTAGE_CELLS_PER_CHIP = { + 12, 9, 12, 9, 12, 9, + 12, 9, 12, 9, 12, 9 + }; + constexpr ChipSelectConfig BMS_CHIP_SELECTS = ChipSelectConfig{ + std::array{ + ChipSelect{ + 9, + std::array{ + Chips{0, + ReadGroupResultMap{ + {3, 3, 3, 3, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{1, + ReadGroupResultMap{ + {3, 3, 3, 0, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{2, + ReadGroupResultMap{ + {3, 3, 3, 3, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{3, + ReadGroupResultMap{ + {3, 3, 3, 0, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{4, + ReadGroupResultMap{ + {3, 3, 3, 3, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{5, + ReadGroupResultMap{ + {3, 3, 3, 0, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + } + }, + ChipSelect{ + 10, + std::array{ + Chips{6, + ReadGroupResultMap{ + {3, 3, 3, 3, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{7, + ReadGroupResultMap{ + {3, 3, 3, 0, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{8, + ReadGroupResultMap{ + {3, 3, 3, 3, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{9, + ReadGroupResultMap{ + {3, 3, 3, 0, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{10, + ReadGroupResultMap{ + {3, 3, 3, 3, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + Chips{11, + ReadGroupResultMap{ + {3, 3, 3, 0, 3, 2}, + std::array{ + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B + std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C + std::array{ ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA, ReadDataResultType_e::NO_DATA }, // D + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A + std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B + } + } + }, + } + } + } + }; + const float VALID_SHDN_OUT_MIN_VOLTAGE_THRESHOLD = 12.0F; const uint32_t MIN_ALLOWED_INVALID_SHDN_OUT_MS = 10; // 10 ms -- requies 100 Hz samp freq. - + // Initialize chip_select, chip_select_per_chip, and address constexpr std::array CS = {9, 10}; constexpr std::array CS_PER_CHIP = {9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10}; diff --git a/include/ACU_InterfaceTasks.h b/include/ACU_InterfaceTasks.h index 5a6cde3e..7fa445cf 100644 --- a/include/ACU_InterfaceTasks.h +++ b/include/ACU_InterfaceTasks.h @@ -26,7 +26,6 @@ using chip_type = LTC6811_Type_e; using BMSDriverInstance_t = BMSDriverInstance; using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; -using ACUControllerInstance_t = ACUControllerInstance; /** * Init Functions - to be called in setup */ diff --git a/include/ACU_SystemTasks.h b/include/ACU_SystemTasks.h index 79a6f4d3..5a0f5356 100644 --- a/include/ACU_SystemTasks.h +++ b/include/ACU_SystemTasks.h @@ -13,13 +13,14 @@ #include "CCUInterface.h" #include "EMInterface.h" #include "BMSDriverGroup.h" +#include "BMSFaultDataManager.h" #include "ADCInterface.h" #include "SystemTimeInterface.h" #include using chip_type = LTC6811_Type_e; -using ACUControllerInstance_t = ACUControllerInstance; using BMSDriverInstance_t = BMSDriverInstance; +using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; bool initialize_all_systems(); /* Delegate Functions */ diff --git a/lib/interfaces/include/BMSDriverGroup.h b/lib/interfaces/include/BMSDriverGroup.h index 0e0be0c9..325565fa 100644 --- a/lib/interfaces/include/BMSDriverGroup.h +++ b/lib/interfaces/include/BMSDriverGroup.h @@ -151,71 +151,16 @@ struct BMSDriverGroupConfig_s float cv_adc_lsb_voltage; }; -/** - * CurrentReadGroup_e - State machine for incremental BMS register group reading - * - * This enum defines the 6-state read cycle used to distribute voltage and GPIO readings - * across multiple read_data() calls. Instead of reading all registers at once (which takes - * significant time), each call reads ONE register group, cycling through all 6 groups. - * - * STATE MACHINE CYCLE: - * - * Call 1 → CURRENT_GROUP_A → Read cells 0-2 (CV Group A) - * Call 2 → CURRENT_GROUP_B → Read cells 3-5 (CV Group B) - * Call 3 → CURRENT_GROUP_C → Read cells 6-8 (CV Group C) - * Call 4 → CURRENT_GROUP_D → Read cells 9-11 (CV Group D) [9-cell chips: skip] - * Call 5 → CURRENT_GROUP_AUX_A → Read GPIO 0-2 (Aux Group A: thermistors 0-2) - * Call 6 → CURRENT_GROUP_AUX_B → Read GPIO 3-5 (Aux Group B: thermistors 3-4, board temp) - * [GOTO Call 1] - * - * HARDWARE MAPPING: - * - Each LTC6811 chip has 12 cell voltage registers divided into 4 groups (A-D) - * - Each group contains 3 consecutive cell readings (6 bytes = 3 × 16-bit values) - * - GPIO registers are divided into 2 groups (AUX_A, AUX_B) - * - GPIO 0-3: Cell thermistors (temperature sensors) - * - GPIO 4: Board temperature sensor (MCP9701) - * - GPIO 5: Not used (padding in AUX_B) - * - * TIMING & FREQUENCY: - * - Original (main): Read all 6 groups at 50 Hz (20ms period) - * - Optimized (this branch): Read 1 group per call at 300 Hz (3ms period) - * - Effective sampling rate per cell: 300 Hz / 6 groups = 50 Hz (same as before) - * - * CHIP ARCHITECTURE NOTES: - * - System has 12 ICs total in pairs: 6 × (12-cell + 9-cell) = 126 cells total - * - Even-indexed chips (0, 2, 4, 6, 8, 10): 12 cells each - * - Odd-indexed chips (1, 3, 5, 7, 9, 11): 9 cells each - * - For 9-cell chips, GROUP_D read is skipped (no cells 10-12) - * - * VALIDATION: - * Each group read has its own validity flag in ValidPacketData_s: - * - CURRENT_GROUP_A → valid_read_cells_1_to_3 - * - CURRENT_GROUP_B → valid_read_cells_4_to_6 - * - CURRENT_GROUP_C → valid_read_cells_7_to_9 - * - CURRENT_GROUP_D → valid_read_cells_10_to_12 - * - CURRENT_GROUP_AUX_A → valid_read_gpios_1_to_3 - * - CURRENT_GROUP_AUX_B → valid_read_gpios_4_to_6 - */ -enum CurrentReadGroup_e -{ - CV_GROUP_A = 0, - CV_GROUP_B, - CV_GROUP_C, - CV_GROUP_D, - AUX_GROUP_A, - AUX_GROUP_B, - NUM_GROUPS -}; /** * @brief Advances to the next read group in the 6-state cycle (A → B → C → D → AUX_A → AUX_B → A) * @param current The current read group state * @return The next read group, wrapping from CURRENT_GROUP_AUX_B back to CURRENT_GROUP_A */ -constexpr CurrentReadGroup_e advance_read_group(CurrentReadGroup_e current) +constexpr ReadGroup_e advance_read_group(ReadGroup_e current) { - return static_cast( - (static_cast(current) + 1) % static_cast(CurrentReadGroup_e::NUM_GROUPS) + return static_cast( + (static_cast(current) + 1) % static_cast(ReadGroup_e::NUM_GROUPS) ); } @@ -228,7 +173,6 @@ class BMSDriverGroup constexpr static size_t num_cell_temps = (num_chips * 4); constexpr static size_t num_board_temps = num_chips; - using BMSCoreData_t = BMSCoreData_s; using BMSDriverData = BMSData_s; BMSDriverGroup( @@ -264,7 +208,7 @@ class BMSDriverGroup /** * Getter function to retrieve the ACUData structure */ - BMSCoreData_t get_bms_core_data(); + BMSCoreData_s get_bms_core_data(); /** * Getter function to retrieve the BMSDriverData structure @@ -292,7 +236,7 @@ class BMSDriverGroup * @return Current read group (CURRENT_GROUP_A through CURRENT_GROUP_AUX_B) * @note Useful for verifying state machine advancement and cycle tracking */ - CurrentReadGroup_e get_current_read_group() { + ReadGroup_e get_current_read_group() { return _current_read_group; } @@ -302,7 +246,7 @@ class BMSDriverGroup * @note Useful for detecting cycle boundaries and synchronization points */ bool is_cycle_start() { - return _current_read_group == CurrentReadGroup_e::CV_GROUP_A; + return _current_read_group == ReadGroup_e::CV_GROUP_A; } /** @@ -357,7 +301,7 @@ class BMSDriverGroup private: - CurrentReadGroup_e _current_read_group = CurrentReadGroup_e::CV_GROUP_A; + ReadGroup_e _current_read_group = ReadGroup_e::CV_GROUP_A; /** * PEC: diff --git a/lib/interfaces/include/BMSDriverGroup.tpp b/lib/interfaces/include/BMSDriverGroup.tpp index f017f012..ae51af1b 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -109,19 +109,15 @@ constexpr std::array BMSDriverGroup -typename BMSDriverGroup::BMSCoreData_t -BMSDriverGroup::get_bms_core_data() +BMSCoreData_s BMSDriverGroup::get_bms_core_data() { - BMSCoreData_t out{}; + BMSCoreData_s out{}; // Basic voltages out.min_cell_voltage = _bms_data.min_cell_voltage; out.max_cell_voltage = _bms_data.max_cell_voltage; out.pack_voltage = _bms_data.total_voltage; - // Per-cell array (sizes must match) - out.voltages = _bms_data.voltages; - // Temps out.max_cell_temp = _bms_data.max_cell_temp; out.min_cell_temp = _bms_data.min_cell_temp; @@ -153,11 +149,11 @@ BMSDriverGroup::read_data() // Trigger ADC conversions at the start of each complete 6-group read cycle // This ensures all groups (A, B, C, D, AUX_A, AUX_B) read from the same timestamp - if (_current_read_group == CurrentReadGroup_e::AUX_GROUP_A) + if (_current_read_group == ReadGroup_e::AUX_GROUP_A) { _start_cell_voltage_ADC_conversion(); } - if (_current_read_group == CurrentReadGroup_e::CV_GROUP_A) + if (_current_read_group == ReadGroup_e::CV_GROUP_A) { _start_GPIO_ADC_conversion(); } @@ -180,27 +176,27 @@ BMSDriverGroup::_read_data_through_broad _start_wakeup_protocol(cs); switch (_current_read_group) { - case CurrentReadGroup_e::CV_GROUP_A: + case ReadGroup_e::CV_GROUP_A: cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, -1); // The address should never be used here spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); break; - case CurrentReadGroup_e::CV_GROUP_B: + case ReadGroup_e::CV_GROUP_B: cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, -1); spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); break; - case CurrentReadGroup_e::CV_GROUP_C: + case ReadGroup_e::CV_GROUP_C: cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_C, -1); spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); break; - case CurrentReadGroup_e::CV_GROUP_D: + case ReadGroup_e::CV_GROUP_D: cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_D, -1); spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); break; - case CurrentReadGroup_e::AUX_GROUP_A: + case ReadGroup_e::AUX_GROUP_A: cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, -1); spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); break; - case CurrentReadGroup_e::AUX_GROUP_B: + case ReadGroup_e::AUX_GROUP_B: cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B, -1); spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); break; @@ -222,32 +218,32 @@ BMSDriverGroup::_read_data_through_broad //relevant for GPIO reading bool current_group_valid = false; switch(_current_read_group) { - case CurrentReadGroup_e::CV_GROUP_A: + case ReadGroup_e::CV_GROUP_A: current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); _bms_data.valid_read_packets[chip_index].valid_read_cells_1_to_3 = current_group_valid; start_index = 0; break; - case CurrentReadGroup_e::CV_GROUP_B: + case ReadGroup_e::CV_GROUP_B: current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); _bms_data.valid_read_packets[chip_index].valid_read_cells_4_to_6 = current_group_valid; start_index = 3; break; - case CurrentReadGroup_e::CV_GROUP_C: + case ReadGroup_e::CV_GROUP_C: current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); _bms_data.valid_read_packets[chip_index].valid_read_cells_7_to_9 = current_group_valid; start_index = 6; break; - case CurrentReadGroup_e::CV_GROUP_D: + case ReadGroup_e::CV_GROUP_D: current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); _bms_data.valid_read_packets[chip_index].valid_read_cells_10_to_12 = current_group_valid; start_index = 9; break; - case CurrentReadGroup_e::AUX_GROUP_A: + case ReadGroup_e::AUX_GROUP_A: current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); _bms_data.valid_read_packets[chip_index].valid_read_gpios_1_to_3 = current_group_valid; start_index = 0; break; - case CurrentReadGroup_e::AUX_GROUP_B: + case ReadGroup_e::AUX_GROUP_B: current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); _bms_data.valid_read_packets[chip_index].valid_read_gpios_4_to_6 = current_group_valid; start_index = 3; @@ -258,18 +254,18 @@ BMSDriverGroup::_read_data_through_broad } // Skip processing if current group packet is invalid and skip cells 9-12 for group D cuz they don't exist - if (!current_group_valid || (_current_read_group == CurrentReadGroup_e::CV_GROUP_D && cells_per_chip == 9)) { + if (!current_group_valid || (_current_read_group == ReadGroup_e::CV_GROUP_D && cells_per_chip == 9)) { continue; } - if (_current_read_group == CurrentReadGroup_e::AUX_GROUP_B) { + if (_current_read_group == ReadGroup_e::AUX_GROUP_B) { std::copy_n(spi_data.begin() + (8 * chip), 4, spi_response.begin()); std::fill(spi_response.begin() + 4, spi_response.end(), 0); // padding to make it 6 bytes } else { std::copy_n(spi_data.begin() + (8 * chip), 6, spi_response.begin()); } - if (_current_read_group <= CurrentReadGroup_e::CV_GROUP_D) { + if (_current_read_group <= ReadGroup_e::CV_GROUP_D) { _load_cell_voltages(_bms_data, _max_min_reference, spi_response, chip_index, start_index); } else { _load_auxillaries(_bms_data, _max_min_reference, spi_response, chip_index, start_index); @@ -685,17 +681,17 @@ template const char* BMSDriverGroup::get_current_read_group_name() { switch (_current_read_group) { - case CurrentReadGroup_e::CV_GROUP_A: + case ReadGroup_e::CV_GROUP_A: return "GROUP_A"; - case CurrentReadGroup_e::CV_GROUP_B: + case ReadGroup_e::CV_GROUP_B: return "GROUP_B"; - case CurrentReadGroup_e::CV_GROUP_C: + case ReadGroup_e::CV_GROUP_C: return "GROUP_C"; - case CurrentReadGroup_e::CV_GROUP_D: + case ReadGroup_e::CV_GROUP_D: return "GROUP_D"; - case CurrentReadGroup_e::AUX_GROUP_A: + case ReadGroup_e::AUX_GROUP_A: return "AUX_A"; - case CurrentReadGroup_e::AUX_GROUP_B: + case ReadGroup_e::AUX_GROUP_B: return "AUX_B"; default: return "UNKNOWN"; @@ -710,23 +706,23 @@ bool BMSDriverGroup::last_read_all_valid const auto& validity = _bms_data.valid_read_packets[chip]; switch (_current_read_group) { - case CurrentReadGroup_e::CV_GROUP_A: + case ReadGroup_e::CV_GROUP_A: if (!validity.valid_read_cells_1_to_3) return false; break; - case CurrentReadGroup_e::CV_GROUP_B: + case ReadGroup_e::CV_GROUP_B: if (!validity.valid_read_cells_4_to_6) return false; break; - case CurrentReadGroup_e::CV_GROUP_C: + case ReadGroup_e::CV_GROUP_C: if (!validity.valid_read_cells_7_to_9) return false; break; - case CurrentReadGroup_e::CV_GROUP_D: + case ReadGroup_e::CV_GROUP_D: // Skip 9-cell chips (odd indices) if (chip % 2 == 0 && !validity.valid_read_cells_10_to_12) return false; break; - case CurrentReadGroup_e::AUX_GROUP_A: + case ReadGroup_e::AUX_GROUP_A: if (!validity.valid_read_gpios_1_to_3) return false; break; - case CurrentReadGroup_e::AUX_GROUP_B: + case ReadGroup_e::AUX_GROUP_B: if (!validity.valid_read_gpios_4_to_6) return false; break; default: @@ -746,23 +742,23 @@ size_t BMSDriverGroup::count_invalid_pac const auto& validity = _bms_data.valid_read_packets[chip]; switch (_current_read_group) { - case CurrentReadGroup_e::CV_GROUP_A: + case ReadGroup_e::CV_GROUP_A: if (!validity.valid_read_cells_1_to_3) invalid_count++; break; - case CurrentReadGroup_e::CV_GROUP_B: + case ReadGroup_e::CV_GROUP_B: if (!validity.valid_read_cells_4_to_6) invalid_count++; break; - case CurrentReadGroup_e::CV_GROUP_C: + case ReadGroup_e::CV_GROUP_C: if (!validity.valid_read_cells_7_to_9) invalid_count++; break; - case CurrentReadGroup_e::CV_GROUP_D: + case ReadGroup_e::CV_GROUP_D: // Skip 9-cell chips (odd indices) when counting if (chip % 2 == 0 && !validity.valid_read_cells_10_to_12) invalid_count++; break; - case CurrentReadGroup_e::AUX_GROUP_A: + case ReadGroup_e::AUX_GROUP_A: if (!validity.valid_read_gpios_1_to_3) invalid_count++; break; - case CurrentReadGroup_e::AUX_GROUP_B: + case ReadGroup_e::AUX_GROUP_B: if (!validity.valid_read_gpios_4_to_6) invalid_count++; break; default: diff --git a/lib/shared_types/shared_types.h b/lib/shared_types/shared_types.h index 6f40318d..8eb3a6d7 100644 --- a/lib/shared_types/shared_types.h +++ b/lib/shared_types/shared_types.h @@ -3,17 +3,183 @@ #include "SharedFirmwareTypes.h" -template struct BMSCoreData_s { volt min_cell_voltage; volt max_cell_voltage; volt pack_voltage; - std::array voltages; celsius max_cell_temp; celsius min_cell_temp; celsius max_board_temp; - size_t max_consecutive_invalid_packet_count; - bool charging_enabled; }; +/** + * CurrentReadGroup_e - State machine for incremental BMS register group reading + * + * This enum defines the 6-state read cycle used to distribute voltage and GPIO readings + * across multiple read_data() calls. Instead of reading all registers at once (which takes + * significant time), each call reads ONE register group, cycling through all 6 groups. + * + * STATE MACHINE CYCLE: + * + * Call 1 → CURRENT_GROUP_A → Read cells 0-2 (CV Group A) + * Call 2 → CURRENT_GROUP_B → Read cells 3-5 (CV Group B) + * Call 3 → CURRENT_GROUP_C → Read cells 6-8 (CV Group C) + * Call 4 → CURRENT_GROUP_D → Read cells 9-11 (CV Group D) [9-cell chips: skip] + * Call 5 → CURRENT_GROUP_AUX_A → Read GPIO 0-2 (Aux Group A: thermistors 0-2) + * Call 6 → CURRENT_GROUP_AUX_B → Read GPIO 3-5 (Aux Group B: thermistors 3-4, board temp) + * [GOTO Call 1] + * + * HARDWARE MAPPING: + * - Each LTC6811 chip has 12 cell voltage registers divided into 4 groups (A-D) + * - Each group contains 3 consecutive cell readings (6 bytes = 3 × 16-bit values) + * - GPIO registers are divided into 2 groups (AUX_A, AUX_B) + * - GPIO 0-3: Cell thermistors (temperature sensors) + * - GPIO 4: Board temperature sensor (MCP9701) + * - GPIO 5: Not used (padding in AUX_B) + * + * TIMING & FREQUENCY: + * - Original (main): Read all 6 groups at 50 Hz (20ms period) + * - Optimized (this branch): Read 1 group per call at 300 Hz (3ms period) + * - Effective sampling rate per cell: 300 Hz / 6 groups = 50 Hz (same as before) + * + * CHIP ARCHITECTURE NOTES: + * - System has 12 ICs total in pairs: 6 × (12-cell + 9-cell) = 126 cells total + * - Even-indexed chips (0, 2, 4, 6, 8, 10): 12 cells each + * - Odd-indexed chips (1, 3, 5, 7, 9, 11): 9 cells each + * - For 9-cell chips, GROUP_D read is skipped (no cells 10-12) + * + * VALIDATION: + * Each group read has its own validity flag in ValidPacketData_s: + * - CURRENT_GROUP_A → valid_read_cells_1_to_3 + * - CURRENT_GROUP_B → valid_read_cells_4_to_6 + * - CURRENT_GROUP_C → valid_read_cells_7_to_9 + * - CURRENT_GROUP_D → valid_read_cells_10_to_12 + * - CURRENT_GROUP_AUX_A → valid_read_gpios_1_to_3 + * - CURRENT_GROUP_AUX_B → valid_read_gpios_4_to_6 + */ + +enum ReadGroup_e { + CV_GROUP_A = 0, CV_GROUP_B, CV_GROUP_C, CV_GROUP_D, + AUX_GROUP_A, AUX_GROUP_B, NUM_GROUPS +}; + +enum ReadDataResultType_e { CELL_VOLTAGE, CELL_TEMPERATURE, BOARD_TEMPERATURE, NO_DATA }; + +// ----- leaf: per-chip group map (immutable) ----- +template +struct ReadGroupResultMap { + static constexpr std::size_t kNumGroups = ReadGroup_e::NUM_GROUPS; + + const std::array group_values; + const std::array, kNumGroups> group_data_types; + + // small helper + constexpr std::size_t data_per_group() const noexcept { return DATA_PER_GROUP; } + constexpr std::size_t num_groups() const noexcept { return kNumGroups; } +}; + +// ----- chip (immutable) ----- +template +struct Chips { + const std::size_t addr_pin; + const ReadGroupResultMap read_map; +}; + +// ----- chip-select (immutable) ----- +template +struct ChipSelect { + const std::size_t cs_pin; + const std::array, NUM_CHIPS_PER_CS> chips; + + constexpr std::size_t num_chips() const noexcept { return NUM_CHIPS_PER_CS; } +}; + +// ----- full config (immutable) + constexpr derived views ----- +template +struct ChipSelectConfig { + const std::array, NUM_CS> chip_selects; + + // Compile-time sizes + static constexpr std::size_t kNumChipSelects = NUM_CS; + static constexpr std::size_t kNumChipsPerCS = NUM_CHIPS_PER_CS; + static constexpr std::size_t kDataPerGroup = DATA_PER_GROUP; + static constexpr std::size_t kTotalChips = NUM_CS * NUM_CHIPS_PER_CS; + + // ---- Derived per-chip counts (voltage/temp/board), all constexpr ---- + constexpr std::array voltage_cells_per_chip() const { + std::array out{}; // zero-inited + for (std::size_t cs = 0; cs < kNumChipSelects; ++cs) { + const auto& sel = chip_selects[cs]; + for (std::size_t c = 0; c < kNumChipsPerCS; ++c) { + const auto& chip = sel.chips[c]; + const std::size_t flat = cs * kNumChipsPerCS + c; + for (std::size_t g = 0; g < chip.read_map.num_groups(); ++g) { + if (!chip.read_map.is_group_on[g]) continue; + for (auto kind : chip.read_map.group_data_types[g]) { + if (kind == CELL_VOLTAGE) { ++out[flat]; } + } + } + } + } + return out; + } + + constexpr std::array temp_cells_per_chip() const { + std::array out{}; + for (std::size_t cs = 0; cs < kNumChipSelects; ++cs) { + const auto& sel = chip_selects[cs]; + for (std::size_t c = 0; c < kNumChipsPerCS; ++c) { + const auto& chip = sel.chips[c]; + const std::size_t flat = cs * kNumChipsPerCS + c; + for (std::size_t g = 0; g < chip.read_map.num_groups(); ++g) { + if (!chip.read_map.is_group_on[g]) continue; + for (auto kind : chip.read_map.group_data_types[g]) { + if (kind == CELL_TEMPERATURE) { ++out[flat]; } + } + } + } + } + return out; + } + + constexpr std::array board_temps_per_chip() const { + std::array out{}; + for (std::size_t cs = 0; cs < kNumChipSelects; ++cs) { + const auto& sel = chip_selects[cs]; + for (std::size_t c = 0; c < kNumChipsPerCS; ++c) { + const auto& chip = sel.chips[c]; + const std::size_t flat = cs * kNumChipsPerCS + c; + for (std::size_t g = 0; g < chip.read_map.num_groups(); ++g) { + if (!chip.read_map.is_group_on[g]) continue; + for (auto kind : chip.read_map.group_data_types[g]) { + if (kind == BOARD_TEMPERATURE) { ++out[flat]; } + } + } + } + } + return out; + } + + // ---- Derived totals (sum of per-chip) ---- + constexpr std::size_t num_voltage_cells_total() const { + const auto v = voltage_cells_per_chip(); + std::size_t s = 0; for (auto x : v) s += x; return s; + } + + static constexpr std::size_t to_global_index(std::size_t cs_index, + std::size_t chip_index) noexcept { + return cs_index * kNumChipsPerCS + chip_index; + } + + + constexpr std::size_t num_temp_cells_total() const { + const auto t = temp_cells_per_chip(); + std::size_t s = 0; for (auto x : t) s += x; return s; + } + + constexpr std::size_t num_board_temps_total() const { + const auto b = board_temps_per_chip(); + std::size_t s = 0; for (auto x : b) s += x; return s; + } +}; #endif diff --git a/lib/systems/include/ACUController.h b/lib/systems/include/ACUController.h index 9263baf0..f2889520 100644 --- a/lib/systems/include/ACUController.h +++ b/lib/systems/include/ACUController.h @@ -21,7 +21,6 @@ namespace acu_controller_default_parameters constexpr const float PACK_MIN_VOLTAGE = 378.0; // from data sheet^ but just assume 126 * 3.0V constexpr const float PACK_INTERNAL_RESISTANCE = 0.246; // Ohms (measured) } -template struct ACUControllerData_s { time_ms last_time_uv_fault_not_present; @@ -38,11 +37,11 @@ struct ACUControllerData_s uint32_t last_bms_not_ok_eval; bool charging_enabled; bool balancing_enabled; - std::array cell_balancing_statuses; }; struct ACUControllerThresholds_s { + volt min_discharge_voltage_thresh = 0; volt cell_overvoltage_thresh_v = 0; volt cell_undervoltage_thresh_v = 0; celsius charging_ot_thresh_c = 0; @@ -65,6 +64,7 @@ struct ACUControllerPackSpecs_s float pack_nominal_capacity = 0; float pack_max_voltage = 0; float pack_min_voltage = 0; + float pack_internal_resistance = 0; }; struct ACUControllerParameters_s @@ -74,11 +74,9 @@ struct ACUControllerParameters_s ACUControllerFaultDurations_s fault_durations; ACUControllerPackSpecs_s pack_specs; }; -template class ACUController { - using ACUData = etl::singleton>; - using ACUStatus = ACUControllerData_s; + // using ACUData = etl::singleton>; public: /** @@ -100,8 +98,9 @@ class ACUController ACUControllerPackSpecs_s pack_specs = { .pack_nominal_capacity = acu_controller_default_parameters::PACK_NOMINAL_CAPACITY_AH, .pack_max_voltage = acu_controller_default_parameters::PACK_MAX_VOLTAGE, - .pack_min_voltage = acu_controller_default_parameters::PACK_MIN_VOLTAGE} - ) : _acu_parameters{thresholds, invalid_packet_count_thresh, fault_durations, pack_specs} {}; + .pack_min_voltage = acu_controller_default_parameters::PACK_MIN_VOLTAGE, + .pack_internal_resistance = acu_controller_default_parameters::PACK_INTERNAL_RESISTANCE + }) : _acu_parameters{thresholds, invalid_packet_count_thresh, fault_durations, pack_specs} {}; /** * @brief Initialize the status time stamps because we don't want accidental sudden faults @@ -113,14 +112,21 @@ class ACUController * @post updates configuration bytes and sends configuration command * @param pack_current current flowing from the pack in amps (negative during discharge, positive during charge) */ - ACUStatus evaluate_accumulator(time_ms current_millis, const BMSCoreData_s &input_state, float em_current); + ACUControllerData_s evaluate_accumulator(time_ms current_millis, const BMSCoreData_s &bms_core_data, size_t max_consecutive_invalid_packet_count, float em_current, size_t num_of_voltage_cells); + + /** + * Calculate Cell Balancing values + * @pre cell charging is enabled + * @post output will have the new values + */ + void calculate_cell_balance_statuses(bool* output, const volt* voltages, size_t num_of_voltage_cells, volt min_voltage); /** * @return state of charge - float from 0.0 to 1.0, representing a percentage from 0 to 100% */ float get_state_of_charge(float em_current, uint32_t delta_time_ms); - ACUStatus get_status() const { return _acu_state; }; + ACUControllerData_s get_status() const { return _acu_state; }; void enableCharging() { @@ -131,12 +137,7 @@ class ACUController _acu_state.charging_enabled = false; } private: - /** - * Calculate Cell Balancing values - * @pre cell charging is enabled - * @post _acu_state.cell_balance_statuses will have the new values - */ - std::array _calculate_cell_balance_statuses(std::array voltages, volt min_voltage); + /** * @pre data has been gathered @@ -166,16 +167,13 @@ class ACUController bool _check_invalid_packet_faults(time_ms current_millis); private: - /** - * @brief Internal resistance per cell (computed from pack resistance divided by number of cells) - */ - static constexpr float CELL_INTERNAL_RESISTANCE = acu_controller_default_parameters::PACK_INTERNAL_RESISTANCE / static_cast(num_cells); + /** * @brief ACU State Holder * Most importantly, holding the current cell balances, fault counters, and watchdog HIGH?LOW - * state is packaged this way so that we can feed it directly into the message interface as a struct + * state is packaged this way so that we ican feed it directly into the message interface as a struct */ - ACUStatus _acu_state = {}; + ACUControllerData_s _acu_state = {}; static constexpr uint32_t _bms_not_ok_hold_time_ms = 1000; @@ -185,8 +183,6 @@ class ACUController const ACUControllerParameters_s _acu_parameters = {}; }; -template -using ACUControllerInstance = etl::singleton>; +using ACUControllerInstance = etl::singleton; -#include "ACUController.tpp" #endif \ No newline at end of file diff --git a/lib/systems/include/ACUController.tpp b/lib/systems/src/ACUController.cpp similarity index 70% rename from lib/systems/include/ACUController.tpp rename to lib/systems/src/ACUController.cpp index 456e11a3..117c1f1a 100644 --- a/lib/systems/include/ACUController.tpp +++ b/lib/systems/src/ACUController.cpp @@ -1,7 +1,7 @@ #include "ACUController.h" -template -void ACUController::init(time_ms system_start_time, volt pack_voltage) + +void ACUController::init(time_ms system_start_time, volt pack_voltage) { _acu_state.last_time_ov_fault_not_present = system_start_time; _acu_state.last_time_uv_fault_not_present = system_start_time; @@ -16,19 +16,19 @@ void ACUController::init(time_ms syste -template -typename ACUController::ACUStatus -ACUController::evaluate_accumulator(time_ms current_millis, const BMSCoreData_s &input_state, float em_current) + +ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, const BMSCoreData_s &input_state, size_t max_consecutive_invalid_packet_count, float em_current, size_t num_of_voltage_cells) { // _acu_state.charging_enabled = input_state.charging_enabled; bool has_invalid_packet = false; - if (input_state.max_consecutive_invalid_packet_count != 0) + if (max_consecutive_invalid_packet_count != 0) { // meaning that at least one of the packets is invalid has_invalid_packet = true; } _acu_state.SoC = get_state_of_charge(em_current, current_millis - _acu_state.prev_bms_time_stamp); // Cell balancing calculations + bool previously_balancing = _acu_state.balancing_enabled; bool balance_enableable = ((previously_balancing && (input_state.max_board_temp < _acu_parameters.thresholds.balance_temp_limit_c)) || @@ -39,12 +39,12 @@ ACUController::evaluate_accumulator(ti if (allow_balancing) { _acu_state.balancing_enabled = true; - _acu_state.cell_balancing_statuses = _calculate_cell_balance_statuses(input_state.voltages, input_state.min_cell_voltage); + // _acu_state.cell_balancing_statuses = _calculate_cell_balance_statuses(input_state.voltages, input_state.min_cell_voltage); } else { // Fill with zeros, no balancing _acu_state.balancing_enabled = false; - _acu_state.cell_balancing_statuses.fill(0); + // _acu_state.cell_balancing_statuses.fill(0); } // Update voltage fault time stamps with IR compensation @@ -56,7 +56,7 @@ ACUController::evaluate_accumulator(ti if (input_state.max_cell_voltage >= _acu_parameters.thresholds.cell_overvoltage_thresh_v) { // Only calculate IR compensation when approaching OV threshold - internal_resistance_max_cell_voltage = input_state.max_cell_voltage + (CELL_INTERNAL_RESISTANCE * discharge_current); + internal_resistance_max_cell_voltage = input_state.max_cell_voltage + (_acu_parameters.pack_specs.pack_internal_resistance / num_of_voltage_cells * discharge_current); } if (internal_resistance_max_cell_voltage < _acu_parameters.thresholds.cell_overvoltage_thresh_v || has_invalid_packet) { @@ -68,7 +68,7 @@ ACUController::evaluate_accumulator(ti if (input_state.min_cell_voltage <= _acu_parameters.thresholds.cell_undervoltage_thresh_v) { // Only calculate IR compensation when approaching UV threshold - min_cell_voltage_to_check = input_state.min_cell_voltage + (CELL_INTERNAL_RESISTANCE * discharge_current); + min_cell_voltage_to_check = input_state.min_cell_voltage + (_acu_parameters.pack_specs.pack_internal_resistance / num_of_voltage_cells * discharge_current); } if (min_cell_voltage_to_check > _acu_parameters.thresholds.cell_undervoltage_thresh_v || has_invalid_packet) { @@ -88,7 +88,7 @@ ACUController::evaluate_accumulator(ti { _acu_state.last_time_cell_ot_fault_not_present = current_millis; } - if (input_state.max_consecutive_invalid_packet_count < _acu_parameters.invalid_packet_count_thresh) + if (max_consecutive_invalid_packet_count < _acu_parameters.invalid_packet_count_thresh) { _acu_state.last_time_invalid_packet_present = current_millis; } @@ -105,24 +105,24 @@ ACUController::evaluate_accumulator(ti } -template -std::array ACUController::_calculate_cell_balance_statuses(std::array voltages, volt min_voltage) + +void ACUController::calculate_cell_balance_statuses(bool* output, const volt* voltages, size_t num_of_voltage_cells, volt min_voltage) { - std::array cb = {false}; - const volt min_discharge_voltage_thresh = 3.8F; - for (size_t cell = 0; cell < num_cells; cell++) + for (size_t cell = 0; cell < num_of_voltage_cells; cell++) { volt cell_voltage = voltages[cell]; - if (((cell_voltage)-min_voltage > _acu_parameters.thresholds.v_diff_to_init_cb) && (cell_voltage > min_discharge_voltage_thresh)) // && max_voltage - (cell_voltage) < 200 && + if ((cell_voltage-min_voltage > _acu_parameters.thresholds.v_diff_to_init_cb) && (cell_voltage > _acu_parameters.thresholds.min_discharge_voltage_thresh)) // && max_voltage - (cell_voltage) < 200 && + { + output[cell] = true; + } else { - cb[cell] = true; + output[cell] = false; } } - return cb; } -template -float ACUController::get_state_of_charge(float em_current, uint32_t delta_time_ms) + +float ACUController::get_state_of_charge(float em_current, uint32_t delta_time_ms) { float delta_ah = (em_current) * ((float)(delta_time_ms / 1000.0f) / 3600.0f); // amp hours _acu_state.SoC += delta_ah / _acu_parameters.pack_specs.pack_nominal_capacity; // should be -= but EM inverted @@ -133,8 +133,8 @@ float ACUController::get_state_of_char return _acu_state.SoC; } -template -bool ACUController::_check_bms_ok(time_ms current_millis) + +bool ACUController::_check_bms_ok(time_ms current_millis) { if (_acu_state.has_fault) { _acu_state.bms_ok = !_acu_state.has_fault; @@ -145,14 +145,14 @@ bool ACUController::_check_bms_ok(time return _acu_state.bms_ok; } -template -bool ACUController::_check_faults(time_ms current_millis) + +bool ACUController::_check_faults(time_ms current_millis) { return _check_voltage_faults(current_millis) || _check_temperature_faults(current_millis) || _check_invalid_packet_faults(current_millis); } -template -bool ACUController::_check_voltage_faults(time_ms current_millis) + +bool ACUController::_check_voltage_faults(time_ms current_millis) { bool ov_fault = (current_millis - _acu_state.last_time_ov_fault_not_present) > _acu_parameters.fault_durations.max_allowed_voltage_fault_dur; bool uv_fault = (current_millis - _acu_state.last_time_uv_fault_not_present) > _acu_parameters.fault_durations.max_allowed_voltage_fault_dur; @@ -160,16 +160,16 @@ bool ACUController::_check_voltage_fau return ov_fault || uv_fault || pack_fault; } -template -bool ACUController::_check_temperature_faults(time_ms current_millis) + +bool ACUController::_check_temperature_faults(time_ms current_millis) { bool cell_ot_fault = (current_millis - _acu_state.last_time_cell_ot_fault_not_present) > _acu_parameters.fault_durations.max_allowed_temp_fault_dur; bool board_ot_fault = (current_millis - _acu_state.last_time_board_ot_fault_not_present) > _acu_parameters.fault_durations.max_allowed_temp_fault_dur; return cell_ot_fault || board_ot_fault; } -template -bool ACUController::_check_invalid_packet_faults(time_ms current_millis) + +bool ACUController::_check_invalid_packet_faults(time_ms current_millis) { bool invalid_packet_fault = (current_millis - _acu_state.last_time_invalid_packet_present) > _acu_parameters.fault_durations.max_allowed_invalid_packet_fault_dur; return invalid_packet_fault; diff --git a/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index 7982b029..bcffbef0 100644 --- a/src/ACU_InterfaceTasks.cpp +++ b/src/ACU_InterfaceTasks.cpp @@ -44,7 +44,7 @@ static ACUAllDataType_s make_acu_all_data() out.core_data.min_measured_ts_out_voltage = watchdog.min_measured_ts_out_voltage; out.core_data.min_shdn_out_voltage = watchdog.min_shdn_out_voltage; // SoC/SoH placeholders (leave unchanged here) - out.SoC = ACUControllerInstance_t::instance().get_status().SoC; + out.SoC = ACUControllerInstance::instance().get_status().SoC; return out; } @@ -55,7 +55,6 @@ void initialize_all_interfaces() SPI.setClockDivider(SPI_CLOCK_DIV8); // 16MHz (Arduino Clock Frequency) / 8 = 2MHz -> SPI Clock Serial.begin(ACUInterfaces::SERIAL_BAUDRATE); analogReadResolution(ACUInterfaces::ANALOG_READ_RESOLUTION); - /* Watchdog Interface */ WatchdogInstance::create(WatchdogPinout_s {ACUInterfaces::TEENSY_OK_PIN, ACUInterfaces::WD_KICK_PIN, @@ -127,7 +126,11 @@ HT_TASK::TaskResponse sample_bms_data(const unsigned long &sysMicros, const HT_T HT_TASK::TaskResponse write_cell_balancing_config(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - BMSDriverInstance_t::instance().write_configuration(ACUControllerInstance_t::instance().get_status().cell_balancing_statuses); + + auto data = BMSDriverInstance_t::instance().get_bms_data(); + static std::array cell_balancing_statuses; + ACUControllerInstance::instance().calculate_cell_balance_statuses(cell_balancing_statuses.data(), data.voltages.data(), ACUConstants::NUM_CELLS, data.min_cell_voltage); + BMSDriverInstance_t::instance().write_configuration(cell_balancing_statuses); return HT_TASK::TaskResponse::YIELD; } @@ -160,7 +163,7 @@ HT_TASK::TaskResponse handle_send_all_CAN_data(const unsigned long& sysMicros, c HT_TASK::TaskResponse enqueue_ACU_ok_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { FaultLatchManagerInstance::instance().clear_if_not_faulted(ACUStateMachineInstance::instance().get_state() == ACUState_e::FAULTED); - FaultLatchManagerInstance::instance().update_imd_and_bms_latches(ACUControllerInstance_t::instance().get_status().bms_ok, ADCInterfaceInstance::instance().read_imd_ok(sys_time::hal_millis())); + FaultLatchManagerInstance::instance().update_imd_and_bms_latches(ACUControllerInstance::instance().get_status().bms_ok, ADCInterfaceInstance::instance().read_imd_ok(sys_time::hal_millis())); //TODO: Where should I get veh_shdn_out_latched from? VCRInterfaceInstance::instance().set_monitoring_data(!FaultLatchManagerInstance::instance().get_latches().imd_fault_latched, !FaultLatchManagerInstance::instance().get_latches().bms_fault_latched, FaultLatchManagerInstance::instance().get_latches().shdn_out_latched); @@ -175,7 +178,7 @@ HT_TASK::TaskResponse enqueue_ACU_ok_CAN_data(const unsigned long& sysMicros, co HT_TASK::TaskResponse enqueue_ACU_core_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); - CCUInterfaceInstance::instance().handle_enqueue_acu_status_CAN_message(ACUControllerInstance_t::instance().get_status().charging_enabled); + CCUInterfaceInstance::instance().handle_enqueue_acu_status_CAN_message(ACUControllerInstance::instance().get_status().charging_enabled); CCUInterfaceInstance::instance().handle_enqueue_acu_voltage_statistics_CAN_message( bms_data.max_cell_voltage, bms_data.min_cell_voltage, @@ -194,7 +197,7 @@ HT_TASK::TaskResponse enqueue_ACU_core_CAN_data(const unsigned long& sysMicros, HT_TASK::TaskResponse enqueue_ACU_all_voltages_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages.data(), ACUConstants::CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIPS); + CCUInterfaceInstance::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages.data(), ACUConstants::VOLTAGE_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIPS); } return HT_TASK::TaskResponse::YIELD; } @@ -319,7 +322,7 @@ void print_bms_data(bms_data data) HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - if (ACUControllerInstance_t::instance().get_status().bms_ok) + if (ACUControllerInstance::instance().get_status().bms_ok) { Serial.print("BMS is OK\n"); } @@ -358,7 +361,7 @@ HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK: Serial.print("Maximum Cell Temp: "); Serial.println(BMSDriverInstance_t::instance().get_bms_data().max_cell_temp, 4); - Serial.printf("Cell Balance Statuses: %d\n", ACUControllerInstance_t::instance().get_status().cell_balancing_statuses); + // Serial.printf("Cell Balance Statuses: %d\n", ACUControllerInstance::instance().calculate_cell_balance_statuses()); Serial.print("ACU State: "); Serial.println(static_cast(ACUStateMachineInstance::instance().get_state())); @@ -366,7 +369,7 @@ HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK: Serial.print("CCU Charging Requested? : "); Serial.println(CCUInterfaceInstance::instance().is_charging_with_balancing_requested(sys_time::hal_millis()) ? "YES" : "NO"); Serial.print("State of Charge: "); - Serial.print(ACUControllerInstance_t::instance().get_status().SoC * 100, 3); + Serial.print(ACUControllerInstance::instance().get_status().SoC * 100, 3); Serial.println("%"); Serial.print("Measured GLV: "); Serial.println("V"); diff --git a/src/ACU_SystemTasks.cpp b/src/ACU_SystemTasks.cpp index 6fdd9e15..245fc244 100644 --- a/src/ACU_SystemTasks.cpp +++ b/src/ACU_SystemTasks.cpp @@ -3,7 +3,8 @@ bool initialize_all_systems() { // Initialize the ACU Controller - ACUControllerInstance_t::create(ACUControllerThresholds_s{ACUSystems::CELL_OVERVOLTAGE_THRESH, + ACUControllerInstance::create(ACUControllerThresholds_s{ ACUSystems::MIN_DISCHARGE_VOLTAGE_THRESH, + ACUSystems::CELL_OVERVOLTAGE_THRESH, ACUSystems::CELL_UNDERVOLTAGE_THRESH, ACUSystems::CHARGING_OT_THRESH, ACUSystems::RUNNING_OT_THRESH, @@ -11,7 +12,7 @@ bool initialize_all_systems() ACUSystems::VOLTAGE_DIFF_TO_INIT_CB, ACUSystems::BALANCE_TEMP_LIMIT_C, ACUSystems::BALANCE_ENABLE_TEMP_THRESH_C}); - ACUControllerInstance_t::instance().init(sys_time::hal_millis(), BMSDriverInstance_t::instance().get_bms_data().total_voltage); + ACUControllerInstance::instance().init(sys_time::hal_millis(), BMSDriverInstance_t::instance().get_bms_data().total_voltage); /* State Machine Initialization */ /* Delegate Function Definitions */ @@ -19,7 +20,7 @@ bool initialize_all_systems() { return CCUInterfaceInstance::instance().is_charging_with_balancing_requested(sys_time::hal_millis()); }); etl::delegate has_bms_fault = etl::delegate::create([]() -> bool - { return !ACUControllerInstance_t::instance().get_status().bms_ok; }); + { return !ACUControllerInstance::instance().get_status().bms_ok; }); etl::delegate has_imd_fault = etl::delegate::create([]() -> bool { return !ADCInterfaceInstance::instance().read_imd_ok(sys_time::hal_millis()); }); @@ -27,10 +28,10 @@ bool initialize_all_systems() etl::delegate received_valid_shdn_out = etl::delegate::create(ADCInterfaceInstance::instance()); etl::delegate enable_cell_balancing = etl::delegate::create([]() -> void - { ACUControllerInstance_t::instance().enableCharging(); }); + { ACUControllerInstance::instance().enableCharging(); }); etl::delegate disable_cell_balancing = etl::delegate::create([]() -> void - { ACUControllerInstance_t::instance().disableCharging(); }); + { ACUControllerInstance::instance().disableCharging(); }); etl::delegate disable_watchdog = etl::delegate::create(WatchdogInstance::instance()); etl::delegate reinitialize_watchdog = etl::delegate::create(WatchdogInstance::instance()); @@ -56,10 +57,12 @@ bool initialize_all_systems() HT_TASK::TaskResponse evaluate_accumulator(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - ACUControllerInstance_t::instance().evaluate_accumulator( + ACUControllerInstance::instance().evaluate_accumulator( sys_time::hal_millis(), BMSDriverInstance_t::instance().get_bms_core_data(), - EMInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).em_current + BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count, + EMInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).em_current, + ACUConstants::NUM_CELLS ); return HT_TASK::TaskResponse::YIELD; } diff --git a/test/test_systems/test_acu_controller.h b/test/test_systems/test_acu_controller.h index e3499433..95b7538d 100644 --- a/test/test_systems/test_acu_controller.h +++ b/test/test_systems/test_acu_controller.h @@ -6,35 +6,35 @@ #include "ACU_Constants.h" #include "shared_types.h" -constexpr size_t num_cells = 12; -constexpr size_t num_chips = 1; -constexpr size_t num_cell_temps = 4; -constexpr size_t num_board_temps = 1; +constexpr size_t num_cells = 12; // local test convenience bool charging_enabled; constexpr float ZERO_PACK_CURRENT = 0.0f; // No current flow (idle state) -ACUControllerThresholds_s thresholds = {ACUSystems::CELL_OVERVOLTAGE_THRESH, +ACUControllerThresholds_s thresholds = {ACUSystems::MIN_DISCHARGE_VOLTAGE_THRESH, + ACUSystems::CELL_OVERVOLTAGE_THRESH, ACUSystems::CELL_UNDERVOLTAGE_THRESH, ACUSystems::CHARGING_OT_THRESH, ACUSystems::RUNNING_OT_THRESH, ACUSystems::MIN_PACK_TOTAL_VOLTAGE, ACUSystems::VOLTAGE_DIFF_TO_INIT_CB, ACUSystems::BALANCE_TEMP_LIMIT_C, - ACUSystems::BALANCE_ENABLE_TEMP_THRESH_C}; + ACUSystems::BALANCE_ENABLE_TEMP_THRESH_C + }; TEST(ACUControllerTesting, initial_state) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; - std::array cb = {0}; uint32_t start_time = 0; - auto status = controller.evaluate_accumulator(start_time, {0}, ZERO_PACK_CURRENT); + controller.init(start_time, 420.0f); + + BMSCoreData_s data{}; // zeros + auto status = controller.evaluate_accumulator(start_time, data, 0, ZERO_PACK_CURRENT, num_cells); ASSERT_EQ(status.has_fault, false); - ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, false); ASSERT_EQ(status.last_time_ov_fault_not_present, 0); @@ -46,8 +46,8 @@ TEST(ACUControllerTesting, initial_state) TEST(ACUControllerTesting, charging_state) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = true; std::array cb = {0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0}; // 0b001100010010 @@ -56,26 +56,32 @@ TEST(ACUControllerTesting, charging_state) controller.init(init_time, 430.0); - BMSCoreData_s data= { - 3.7, // min cell v - 3.85, // max cell v - 430.00, // pack v - {3.7, 3.81, 3.7, 3.7, 3.81, 3.76, 3.7, 3.7, 3.84, 3.85, 3.75, 3.75} // individual cell voltage data + // Core data used by accumulator (no per-cell array in BMSCoreData_s) + BMSCoreData_s data = { + 3.7f, // min cell v + 3.85f, // max cell v + 430.0f, // pack v + }; + // Per-cell voltages for balancing calc + std::array cell_voltages = {3.7f, 3.81f, 3.7f, 3.7f, 3.81f, 3.76f, 3.7f, 3.7f, 3.84f, 3.85f, 3.75f, 3.75f}; controller.enableCharging(); - // data.charging_enabled = charging_enabled; - auto status = controller.evaluate_accumulator(init_time, data, ZERO_PACK_CURRENT); + auto status = controller.evaluate_accumulator(init_time, data, 0, ZERO_PACK_CURRENT, num_cells); ASSERT_NEAR(data.min_cell_voltage, 3.7, 0.0001); - status = controller.evaluate_accumulator(start_time, data, ZERO_PACK_CURRENT); + status = controller.evaluate_accumulator(start_time, data, 0, ZERO_PACK_CURRENT, num_cells); ASSERT_EQ(status.has_fault, false); - ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, true); + // Balance calculation moved out of evaluate_accumulator; verify outputs explicitly + std::array calc_cb{}; + controller.calculate_cell_balance_statuses(calc_cb.data(), cell_voltages.data(), num_cells, data.min_cell_voltage); + ASSERT_EQ(calc_cb, cb); + ASSERT_EQ(status.last_time_ov_fault_not_present, start_time); ASSERT_EQ(status.last_time_uv_fault_not_present, start_time); ASSERT_EQ(status.last_time_cell_ot_fault_not_present, start_time); @@ -85,8 +91,8 @@ TEST(ACUControllerTesting, charging_state) TEST(ACUControllerTesting, faulted_state) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; // or true doesn't matter std::array cb = {0}; @@ -95,25 +101,22 @@ TEST(ACUControllerTesting, faulted_state) controller.init(init_time, 430.0); - BMSCoreData_s data= { - 3.03, // min cell v - 4.21, // max cell v - 430.00, // pack v - {3.18, 3.2, 3.03, 3.21, 3.10, 3.12, 3.11, 3.12, 3.18, 3.19, 4.21, 3.06}, // individual cell voltage data - 70, // cell temp c - 50, // board temp c + BMSCoreData_s data= { + 3.03f, // min cell v + 4.21f, // max cell v + 430.0f, // pack v + 70.0f, // max cell temp c + 20.0f, // min cell temp c + 50.0f // board temp c }; - data.charging_enabled = charging_enabled; - - auto status = controller.evaluate_accumulator(init_time, data, ZERO_PACK_CURRENT); + auto status = controller.evaluate_accumulator(init_time, data, 0, ZERO_PACK_CURRENT, num_cells); ASSERT_NEAR(data.min_cell_voltage, 3.03, 0.0001); - status = controller.evaluate_accumulator(start_time, data, ZERO_PACK_CURRENT); + status = controller.evaluate_accumulator(start_time, data, 0, ZERO_PACK_CURRENT, num_cells); ASSERT_EQ(status.has_fault, true); - ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, false); ASSERT_EQ(status.last_time_ov_fault_not_present, init_time); // because they're past thresh... @@ -125,8 +128,8 @@ TEST(ACUControllerTesting, faulted_state) TEST(ACUControllerTesting, ir_compensation_discharge) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; std::array cb = {0}; @@ -141,26 +144,23 @@ TEST(ACUControllerTesting, ir_compensation_discharge) // Without IR comp: would fault immediately // With IR comp: discharge_current = 100A, CELL_INTERNAL_RESISTANCE = 0.246/12 = 0.0205Ω // Internal V = 3.05V + (0.0205Ω × 100A) = 3.05V + 2.05V = 5.10V (should NOT fault) - BMSCoreData_s data = { - 3.05, // min cell v - EXACTLY at UV threshold to trigger IR compensation - 4.15, // max cell v - well below OV threshold - 430.00, // pack v - {3.18, 3.2, 3.05, 3.21, 3.10, 3.12, 3.11, 3.12, 3.18, 3.19, 4.15, 3.08}, // individual cell voltage data - 40, // cell temp c - normal - 35, // board temp c - normal + BMSCoreData_s data = { + 3.05f, // min cell v - EXACTLY at UV threshold to trigger IR compensation + 4.15f, // max cell v - well below OV threshold + 430.0f, // pack v + 40.0f, // cell temp c - normal + 20.0f, // min cell temp c + 35.0f // board temp c - normal }; - data.charging_enabled = charging_enabled; - - auto status = controller.evaluate_accumulator(init_time, data, -100.0f); // -100A = discharge + auto status = controller.evaluate_accumulator(init_time, data, 0, -100.0f, num_cells); // -100A = discharge ASSERT_NEAR(data.min_cell_voltage, 3.05, 0.0001); - status = controller.evaluate_accumulator(start_time, data, -100.0f); + status = controller.evaluate_accumulator(start_time, data, 0, -100.0f, num_cells); // Should NOT fault - IR compensation should prevent false UV fault during high discharge ASSERT_EQ(status.has_fault, false); - ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, false); // All timestamps should be updated (no faults) @@ -173,8 +173,8 @@ TEST(ACUControllerTesting, ir_compensation_discharge) TEST(ACUControllerTesting, ir_compensation_charge) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; // Disable balancing to focus on IR compensation test std::array cb = {0}; // No balancing @@ -189,26 +189,23 @@ TEST(ACUControllerTesting, ir_compensation_charge) // Without IR comp: would fault immediately // With IR comp: discharge_current = -10A, CELL_INTERNAL_RESISTANCE = 0.246/12 = 0.0205Ω // Internal V = 4.2V + (0.0205Ω × -10A) = 4.2V - 0.205V = 3.995V (should NOT fault) - BMSCoreData_s data = { - 4.10, // min cell v - normal - 4.20, // max cell v - EXACTLY at OV threshold to trigger IR compensation - 500.00, // pack v - higher during charge - {4.10, 4.15, 4.12, 4.13, 4.14, 4.11, 4.16, 4.17, 4.18, 4.20, 4.15, 4.14}, // individual cell voltage data - 40, // cell temp c - normal - 35, // board temp c - normal + BMSCoreData_s data = { + 4.10f, // min cell v - normal + 4.20f, // max cell v - EXACTLY at OV threshold to trigger IR compensation + 500.0f, // pack v - higher during charge + 40.0f, // cell temp c - normal + 20.0f, // min cell temp c + 35.0f // board temp c - normal }; - data.charging_enabled = charging_enabled; - - auto status = controller.evaluate_accumulator(init_time, data, 10.0f); // +10A = charge + auto status = controller.evaluate_accumulator(init_time, data, 0, 10.0f, num_cells); // +10A = charge ASSERT_NEAR(data.max_cell_voltage, 4.2, 0.0001); - status = controller.evaluate_accumulator(start_time, data, 10.0f); + status = controller.evaluate_accumulator(start_time, data, 0, 10.0f, num_cells); // Should NOT fault - IR compensation should prevent false OV fault during charging ASSERT_EQ(status.has_fault, false); - ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, false); // All timestamps should be updated (no faults) @@ -222,8 +219,8 @@ TEST(ACUControllerTesting, ir_compensation_charge) // Tests that OV faults require 1000ms persistence before triggering TEST(ACUControllerTesting, cell_overvoltage_fault_persistence) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; std::array cb = {0}; @@ -234,30 +231,28 @@ TEST(ACUControllerTesting, cell_overvoltage_fault_persistence) controller.init(init_time, 430.0); // Cell voltage JUST above OV threshold (4.21V > 4.2V), zero current - BMSCoreData_s data = { + BMSCoreData_s data = { 3.70, // min cell v - normal 4.21, // max cell v - ABOVE OV threshold 500.00, // pack v - normal - {3.70, 3.75, 3.72, 3.71, 3.80, 3.76, 3.74, 3.73, 3.78, 4.21, 3.77, 3.79}, // individual cell voltage data 40, // cell temp c - normal 35, // board temp c - normal }; - data.charging_enabled = charging_enabled; // First evaluation at init_time - establishes OV condition - auto status = controller.evaluate_accumulator(init_time, data, ZERO_PACK_CURRENT); + auto status = controller.evaluate_accumulator(init_time, data, 0, ZERO_PACK_CURRENT, 126); // OV detected, timestamp NOT updated (still at init_time) ASSERT_EQ(status.last_time_ov_fault_not_present, init_time); ASSERT_EQ(status.has_fault, false); // Should NOT fault yet (duration = 0ms < 1000ms) // Second evaluation at 500ms - still within threshold - status = controller.evaluate_accumulator(before_fault_time, data, ZERO_PACK_CURRENT); + status = controller.evaluate_accumulator(before_fault_time, data, 0, ZERO_PACK_CURRENT, 126); ASSERT_EQ(status.last_time_ov_fault_not_present, init_time); // Still stuck at init_time ASSERT_EQ(status.has_fault, false); // 500ms < 1000ms - NO fault yet // Third evaluation at 1100ms - exceeds threshold - status = controller.evaluate_accumulator(after_fault_time, data, ZERO_PACK_CURRENT); + status = controller.evaluate_accumulator(after_fault_time, data, 0, ZERO_PACK_CURRENT, 126); ASSERT_EQ(status.last_time_ov_fault_not_present, init_time); // Still stuck at init_time ASSERT_EQ(status.has_fault, true); // 1100ms > 1000ms - FAULT! } @@ -265,8 +260,8 @@ TEST(ACUControllerTesting, cell_overvoltage_fault_persistence) // Tests that UV faults require 1000ms persistence before triggering TEST(ACUControllerTesting, cell_undervoltage_fault_persistence) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; std::array cb = {0}; @@ -277,30 +272,29 @@ TEST(ACUControllerTesting, cell_undervoltage_fault_persistence) controller.init(init_time, 430.0); // Cell voltage JUST below UV threshold (3.04V < 3.05V), zero current - BMSCoreData_s data = { - 3.04, // min cell v - BELOW UV threshold - 4.10, // max cell v - normal - 380.00, // pack v - normal - {3.70, 3.75, 3.04, 3.71, 3.80, 3.76, 3.74, 3.73, 3.78, 3.85, 3.77, 3.79}, // individual cell voltage data - 40, // cell temp c - normal - 35, // board temp c - normal + BMSCoreData_s data = { + 3.04f, // min cell v - BELOW UV threshold + 4.10f, // max cell v - normal + 380.0f, // pack v - normal + 40.0f, // cell temp c - normal + 20.0f, // min cell temp c + 35.0f // board temp c - normal }; - data.charging_enabled = charging_enabled; // First evaluation at init_time - establishes UV condition - auto status = controller.evaluate_accumulator(init_time, data, ZERO_PACK_CURRENT); + auto status = controller.evaluate_accumulator(init_time, data, 0, ZERO_PACK_CURRENT, num_cells); // UV detected, timestamp NOT updated (still at init_time) ASSERT_EQ(status.last_time_uv_fault_not_present, init_time); ASSERT_EQ(status.has_fault, false); // Should NOT fault yet (duration = 0ms < 1000ms) // Second evaluation at 500ms - still within threshold - status = controller.evaluate_accumulator(before_fault_time, data, ZERO_PACK_CURRENT); + status = controller.evaluate_accumulator(before_fault_time, data, 0, ZERO_PACK_CURRENT, num_cells); ASSERT_EQ(status.last_time_uv_fault_not_present, init_time); // Still stuck at init_time ASSERT_EQ(status.has_fault, false); // 500ms < 1000ms - NO fault yet // Third evaluation at 1100ms - exceeds threshold - status = controller.evaluate_accumulator(after_fault_time, data, ZERO_PACK_CURRENT); + status = controller.evaluate_accumulator(after_fault_time, data, 0, ZERO_PACK_CURRENT, num_cells); ASSERT_EQ(status.last_time_uv_fault_not_present, init_time); // Still stuck at init_time ASSERT_EQ(status.has_fault, true); // 1100ms > 1000ms - FAULT! } \ No newline at end of file From 35870c68365400921dbced15008e7c2ffda0e354 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Tue, 4 Nov 2025 22:37:01 -0800 Subject: [PATCH 10/18] removed random 8 from BMSDriverGroup and make it in terms of the packet and pec sizes in bytes --- lib/interfaces/include/BMSDriverGroup.h | 8 ++++++- lib/interfaces/include/BMSDriverGroup.tpp | 25 ++++++++++---------- lib/interfaces/include/SystemTimeInterface.h | 2 +- lib/interfaces/src/CCUInterface.cpp | 17 +++++-------- lib/interfaces/src/SystemTimeInterface.cpp | 2 +- lib/systems/src/ACUController.cpp | 8 +++---- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/lib/interfaces/include/BMSDriverGroup.h b/lib/interfaces/include/BMSDriverGroup.h index 325565fa..bd89eb9c 100644 --- a/lib/interfaces/include/BMSDriverGroup.h +++ b/lib/interfaces/include/BMSDriverGroup.h @@ -85,6 +85,7 @@ namespace bms_driver_defaults constexpr const float CV_ADC_CONVERSION_TIME_MS = 1.2f; constexpr const float GPIO_ADC_CONVERSION_TIME_MS = 1.2f; constexpr const float CV_ADC_LSB_VOLTAGE = 0.0001f; // Cell voltage ADC resolution: 100μV per LSB (1/10000 V) + constexpr const int SIZE_OF_PACKET_VALUE_BYTES = 2; // each cell voltage or gpio reading is 2 bytes } struct ValidPacketData_s @@ -149,6 +150,7 @@ struct BMSDriverGroupConfig_s float cv_adc_conversion_time_ms; float gpio_adc_conversion_time_ms; float cv_adc_lsb_voltage; + float size_of_packet_value_bytes; }; @@ -301,6 +303,10 @@ class BMSDriverGroup private: + static constexpr size_t DATA_SIZE_BYTES = 6; + static constexpr size_t PEC_SIZE_BYTES = 2; + static constexpr size_t TOTAL_PACKET_SIZE_BYTES = DATA_SIZE_BYTES + PEC_SIZE_BYTES; + ReadGroup_e _current_read_group = ReadGroup_e::CV_GROUP_A; /** @@ -386,7 +392,7 @@ class BMSDriverGroup * @brief When the inverters are idle, comms get funky from EMI. This function allows us to determine if the acu reads valid packets * @return bool of whether the PEC correctly reflects the buffer being given. If no, then we know that EMI (likely) is causing invalid reads */ - bool _check_if_valid_packet(const std::array &data, size_t param_iterator); + bool _check_if_valid_packet(const std::array &data, size_t param_iterator); /** * Generates a Packet Error Code diff --git a/lib/interfaces/include/BMSDriverGroup.tpp b/lib/interfaces/include/BMSDriverGroup.tpp index ae51af1b..a321fb8b 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -28,7 +28,8 @@ BMSDriverGroup::BMSDriverGroup(const std .CRC15_POLY = bms_driver_defaults::CRC15_POLY, .cv_adc_conversion_time_ms = bms_driver_defaults::CV_ADC_CONVERSION_TIME_MS, .gpio_adc_conversion_time_ms = bms_driver_defaults::GPIO_ADC_CONVERSION_TIME_MS, - .cv_adc_lsb_voltage = bms_driver_defaults::CV_ADC_LSB_VOLTAGE + .cv_adc_lsb_voltage = bms_driver_defaults::CV_ADC_LSB_VOLTAGE, + .size_of_packet_value_bytes = bms_driver_defaults::SIZE_OF_PACKET_VALUE_BYTES } ) : _chip_select(cs), @@ -164,7 +165,7 @@ template typename BMSDriverGroup::BMSDriverData BMSDriverGroup::_read_data_through_broadcast() { - constexpr size_t data_size = 8 * (num_chips / num_chip_selects); + constexpr size_t data_size = TOTAL_PACKET_SIZE_BYTES * (num_chips / num_chip_selects); for (size_t cs = 0; cs < num_chip_selects; cs++) { write_configuration(_config.dcto_read, _cell_discharge_en); @@ -219,32 +220,32 @@ BMSDriverGroup::_read_data_through_broad bool current_group_valid = false; switch(_current_read_group) { case ReadGroup_e::CV_GROUP_A: - current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); + current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); _bms_data.valid_read_packets[chip_index].valid_read_cells_1_to_3 = current_group_valid; start_index = 0; break; case ReadGroup_e::CV_GROUP_B: - current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); + current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); _bms_data.valid_read_packets[chip_index].valid_read_cells_4_to_6 = current_group_valid; start_index = 3; break; case ReadGroup_e::CV_GROUP_C: - current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); + current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); _bms_data.valid_read_packets[chip_index].valid_read_cells_7_to_9 = current_group_valid; start_index = 6; break; case ReadGroup_e::CV_GROUP_D: - current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); + current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); _bms_data.valid_read_packets[chip_index].valid_read_cells_10_to_12 = current_group_valid; start_index = 9; break; case ReadGroup_e::AUX_GROUP_A: - current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); + current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); _bms_data.valid_read_packets[chip_index].valid_read_gpios_1_to_3 = current_group_valid; start_index = 0; break; case ReadGroup_e::AUX_GROUP_B: - current_group_valid = _check_if_valid_packet(spi_data, 8 * chip); + current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); _bms_data.valid_read_packets[chip_index].valid_read_gpios_4_to_6 = current_group_valid; start_index = 3; break; @@ -259,10 +260,10 @@ BMSDriverGroup::_read_data_through_broad } if (_current_read_group == ReadGroup_e::AUX_GROUP_B) { - std::copy_n(spi_data.begin() + (8 * chip), 4, spi_response.begin()); + std::copy_n(spi_data.begin() + (TOTAL_PACKET_SIZE_BYTES * chip), 4, spi_response.begin()); std::fill(spi_response.begin() + 4, spi_response.end(), 0); // padding to make it 6 bytes } else { - std::copy_n(spi_data.begin() + (8 * chip), 6, spi_response.begin()); + std::copy_n(spi_data.begin() + (TOTAL_PACKET_SIZE_BYTES * chip), 6, spi_response.begin()); } if (_current_read_group <= ReadGroup_e::CV_GROUP_D) { @@ -495,7 +496,7 @@ void BMSDriverGroup::write_configuration template void BMSDriverGroup::_write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses) { - constexpr size_t data_size = 8 * (num_chips / num_chip_selects); + constexpr size_t data_size = TOTAL_PACKET_SIZE_BYTES * (num_chips / num_chip_selects); std::array cmd_and_pec = _generate_CMD_PEC(CMD_CODES_e::WRITE_CONFIG, -1); std::array full_buffer; std::array temp_pec; @@ -664,7 +665,7 @@ std::array BMSDriverGroup::_ template -bool BMSDriverGroup::_check_if_valid_packet(const std::array &data, size_t param_iterator) +bool BMSDriverGroup::_check_if_valid_packet(const std::array &data, size_t param_iterator) { std::array sample_packet; std::array sample_pec; diff --git a/lib/interfaces/include/SystemTimeInterface.h b/lib/interfaces/include/SystemTimeInterface.h index f06b550d..c1c5929a 100644 --- a/lib/interfaces/include/SystemTimeInterface.h +++ b/lib/interfaces/include/SystemTimeInterface.h @@ -10,7 +10,7 @@ namespace sys_time unsigned long millis_to_micros(unsigned long millis); const unsigned long MILLIS_TO_MICROS_FACTOR = 1000; - const unsigned long MICROS_TO_MILLIS_FACTOR = 0.001; + }; #endif // SYSTEMTIMEINTERFACE_H \ No newline at end of file diff --git a/lib/interfaces/src/CCUInterface.cpp b/lib/interfaces/src/CCUInterface.cpp index 0ab3db08..6f1ad927 100644 --- a/lib/interfaces/src/CCUInterface.cpp +++ b/lib/interfaces/src/CCUInterface.cpp @@ -37,20 +37,18 @@ void CCUInterface::handle_enqueue_acu_cell_voltages_CAN_message( const size_t num_of_chips ) { BMS_CELL_VOLTAGES_t msg = {}; - size_t num_of_groups, num_of_voltage_cells; - bool voltage_cell_group_cycle_loop_completed; msg.chip_id = static_cast(_curr_data.current_voltage_group_chip_id); msg.cell_group_id = static_cast(_curr_data.current_voltage_cell_group_id); - num_of_groups = voltage_cells_per_chip[_curr_data.current_voltage_group_chip_id] / _ccu_params.voltage_cells_per_group; - num_of_voltage_cells = std::accumulate(voltage_cells_per_chip, voltage_cells_per_chip + num_of_chips, 0); + size_t num_of_groups = voltage_cells_per_chip[_curr_data.current_voltage_group_chip_id] / _ccu_params.voltage_cells_per_group; + size_t num_of_voltage_cells = std::accumulate(voltage_cells_per_chip, voltage_cells_per_chip + num_of_chips, 0); msg.cell_group_voltage_0_ro = HYTECH_cell_group_voltage_0_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id]); msg.cell_group_voltage_1_ro = HYTECH_cell_group_voltage_1_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id + 1]); msg.cell_group_voltage_2_ro = HYTECH_cell_group_voltage_2_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id + 2]); - voltage_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_voltage_cell_group_id, num_of_groups); + bool voltage_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_voltage_cell_group_id, num_of_groups); if (voltage_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_voltage_group_chip_id, num_of_chips); @@ -64,20 +62,17 @@ void CCUInterface::handle_enqueue_acu_cell_temps_CAN_message( const size_t num_of_chips ) { BMS_CHIP_TEMPS_t chip_temps_msg = {}; - size_t num_of_groups, num_of_temp_cells; - bool voltage_cell_group_cycle_loop_completed; chip_temps_msg.chip_id = static_cast(_curr_data.current_temp_group_chip_id); chip_temps_msg.thermistor_group_id = static_cast(_curr_data.current_temp_group_id); - num_of_groups = temp_cells_per_chip[_curr_data.current_temp_group_chip_id] / _ccu_params.temp_cells_per_group; - num_of_temp_cells = std::accumulate(temp_cells_per_chip, temp_cells_per_chip + num_of_chips, 0); + size_t num_of_groups = temp_cells_per_chip[_curr_data.current_temp_group_chip_id] / _ccu_params.temp_cells_per_group; + size_t num_of_temp_cells = std::accumulate(temp_cells_per_chip, temp_cells_per_chip + num_of_chips, 0); chip_temps_msg.thermistor_cell_group_temp_0_ro = HYTECH_thermistor_cell_group_temp_0_ro_toS(cell_temps[_curr_data.current_temp_cell_id]); chip_temps_msg.thermistor_cell_group_temp_1_ro = HYTECH_thermistor_cell_group_temp_1_ro_toS(cell_temps[_curr_data.current_temp_cell_id + 1]); - bool temp_cell_group_cycle_loop_completed; - temp_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_temp_group_id, num_of_groups); + bool temp_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_temp_group_id, num_of_groups); if (temp_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_temp_group_chip_id, num_of_chips); diff --git a/lib/interfaces/src/SystemTimeInterface.cpp b/lib/interfaces/src/SystemTimeInterface.cpp index 3a3332e3..0982341c 100644 --- a/lib/interfaces/src/SystemTimeInterface.cpp +++ b/lib/interfaces/src/SystemTimeInterface.cpp @@ -16,7 +16,7 @@ namespace sys_time unsigned long micros_to_millis(unsigned long micros) { - return micros * MICROS_TO_MILLIS_FACTOR; + return micros / MILLIS_TO_MICROS_FACTOR; } unsigned long millis_to_micros(unsigned long millis) diff --git a/lib/systems/src/ACUController.cpp b/lib/systems/src/ACUController.cpp index 117c1f1a..5f38ae06 100644 --- a/lib/systems/src/ACUController.cpp +++ b/lib/systems/src/ACUController.cpp @@ -10,7 +10,7 @@ void ACUController::init(time_ms system_start_time, volt pack_voltage) _acu_state.last_time_pack_uv_fault_not_present = system_start_time; _acu_state.last_time_invalid_packet_present = system_start_time; _acu_state.prev_bms_time_stamp = system_start_time; - _acu_state.SoC = (pack_voltage <= _acu_parameters.pack_specs.pack_min_voltage) ? 0.0 : ((pack_voltage - _acu_parameters.pack_specs.pack_min_voltage) / (_acu_parameters.pack_specs.pack_max_voltage - _acu_parameters.pack_specs.pack_min_voltage)); + _acu_state.SoC = (pack_voltage <= _acu_parameters.pack_specs.pack_min_voltage) ? 0.0f : ((pack_voltage - _acu_parameters.pack_specs.pack_min_voltage) / (_acu_parameters.pack_specs.pack_max_voltage - _acu_parameters.pack_specs.pack_min_voltage)); _acu_state.balancing_enabled = false; } @@ -56,7 +56,7 @@ ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, if (input_state.max_cell_voltage >= _acu_parameters.thresholds.cell_overvoltage_thresh_v) { // Only calculate IR compensation when approaching OV threshold - internal_resistance_max_cell_voltage = input_state.max_cell_voltage + (_acu_parameters.pack_specs.pack_internal_resistance / num_of_voltage_cells * discharge_current); + internal_resistance_max_cell_voltage = input_state.max_cell_voltage + (_acu_parameters.pack_specs.pack_internal_resistance / static_cast(num_of_voltage_cells) * discharge_current); } if (internal_resistance_max_cell_voltage < _acu_parameters.thresholds.cell_overvoltage_thresh_v || has_invalid_packet) { @@ -68,7 +68,7 @@ ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, if (input_state.min_cell_voltage <= _acu_parameters.thresholds.cell_undervoltage_thresh_v) { // Only calculate IR compensation when approaching UV threshold - min_cell_voltage_to_check = input_state.min_cell_voltage + (_acu_parameters.pack_specs.pack_internal_resistance / num_of_voltage_cells * discharge_current); + min_cell_voltage_to_check = input_state.min_cell_voltage + (_acu_parameters.pack_specs.pack_internal_resistance / static_cast(num_of_voltage_cells) * discharge_current); } if (min_cell_voltage_to_check > _acu_parameters.thresholds.cell_undervoltage_thresh_v || has_invalid_packet) { @@ -124,7 +124,7 @@ void ACUController::calculate_cell_balance_statuses(bool* output, const volt* vo float ACUController::get_state_of_charge(float em_current, uint32_t delta_time_ms) { - float delta_ah = (em_current) * ((float)(delta_time_ms / 1000.0f) / 3600.0f); // amp hours + float delta_ah = (em_current) * ((float)(delta_time_ms) / HOUR_TO_MS_FACTOR); // amp hours _acu_state.SoC += delta_ah / _acu_parameters.pack_specs.pack_nominal_capacity; // should be -= but EM inverted if (_acu_state.SoC < 0.0) _acu_state.SoC = 0; From 1167818639efaf7d9e64d11b6c26e5a38b74882b Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Tue, 4 Nov 2025 22:54:34 -0800 Subject: [PATCH 11/18] exchanged valid packe data struct for an array --- lib/interfaces/include/BMSDriverGroup.h | 14 ++------ lib/interfaces/include/BMSDriverGroup.tpp | 40 ++++++++++----------- lib/systems/include/ACUController.h | 4 ++- lib/systems/include/BMSFaultDataManager.h | 13 ++----- lib/systems/include/BMSFaultDataManager.tpp | 36 +++++++++---------- lib/systems/src/ACUController.cpp | 5 +-- 6 files changed, 49 insertions(+), 63 deletions(-) diff --git a/lib/interfaces/include/BMSDriverGroup.h b/lib/interfaces/include/BMSDriverGroup.h index bd89eb9c..d78dc8d9 100644 --- a/lib/interfaces/include/BMSDriverGroup.h +++ b/lib/interfaces/include/BMSDriverGroup.h @@ -88,20 +88,12 @@ namespace bms_driver_defaults constexpr const int SIZE_OF_PACKET_VALUE_BYTES = 2; // each cell voltage or gpio reading is 2 bytes } -struct ValidPacketData_s -{ - bool valid_read_cells_1_to_3 = true; - bool valid_read_cells_4_to_6 = true; - bool valid_read_cells_7_to_9 = true; - bool valid_read_cells_10_to_12 = true; - bool valid_read_gpios_1_to_3 = true; - bool valid_read_gpios_4_to_6 = true; -}; + template struct BMSData_s { - std::array valid_read_packets; + std::array, num_chips> valid_read_packets; std::array voltages; std::array cell_temperatures; std::array board_temperatures; @@ -264,7 +256,7 @@ class BMSDriverGroup * @note Each chip has 6 validity flags (cells 1-3, 4-6, 7-9, 10-12, GPIO 1-3, 4-6) * @note Useful for fault detection and EMI resilience monitoring */ - const std::array& get_validity_data() { + const std::array, num_chips>& get_validity_data() { return _bms_data.valid_read_packets; } diff --git a/lib/interfaces/include/BMSDriverGroup.tpp b/lib/interfaces/include/BMSDriverGroup.tpp index a321fb8b..0ac72386 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -52,7 +52,7 @@ void BMSDriverGroup::init() _bms_data.voltages.fill(0); _bms_data.cell_temperatures.fill(0); _bms_data.board_temperatures.fill(0); - _bms_data.valid_read_packets.fill(ValidPacketData_s{}); + _bms_data.valid_read_packets.fill({false}); _bms_data.total_voltage = 0; } @@ -221,32 +221,32 @@ BMSDriverGroup::_read_data_through_broad switch(_current_read_group) { case ReadGroup_e::CV_GROUP_A: current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); - _bms_data.valid_read_packets[chip_index].valid_read_cells_1_to_3 = current_group_valid; + _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_A)] = current_group_valid; start_index = 0; break; case ReadGroup_e::CV_GROUP_B: current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); - _bms_data.valid_read_packets[chip_index].valid_read_cells_4_to_6 = current_group_valid; + _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_B)] = current_group_valid; start_index = 3; break; case ReadGroup_e::CV_GROUP_C: current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); - _bms_data.valid_read_packets[chip_index].valid_read_cells_7_to_9 = current_group_valid; + _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_C)] = current_group_valid; start_index = 6; break; case ReadGroup_e::CV_GROUP_D: current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); - _bms_data.valid_read_packets[chip_index].valid_read_cells_10_to_12 = current_group_valid; + _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_D)] = current_group_valid; start_index = 9; break; case ReadGroup_e::AUX_GROUP_A: current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); - _bms_data.valid_read_packets[chip_index].valid_read_gpios_1_to_3 = current_group_valid; + _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::AUX_GROUP_A)] = current_group_valid; start_index = 0; break; case ReadGroup_e::AUX_GROUP_B: current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); - _bms_data.valid_read_packets[chip_index].valid_read_gpios_4_to_6 = current_group_valid; + _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::AUX_GROUP_B)] = current_group_valid; start_index = 3; break; default: @@ -294,7 +294,7 @@ typename BMSDriverGroup::BMSDriverData BMSDriverGroup::_read_data_through_address() { ReferenceMaxMin_s max_min_reference; - ValidPacketData_s clean_valid_packet_data; // should be all reset to true + std::array clean_valid_packet_data = {true}; // should be all reset to true _bms_data.valid_read_packets.fill(clean_valid_packet_data); // reset std::array data_in_cell_voltages_1_to_12; std::array data_in_auxillaries_1_to_5; @@ -708,23 +708,23 @@ bool BMSDriverGroup::last_read_all_valid switch (_current_read_group) { case ReadGroup_e::CV_GROUP_A: - if (!validity.valid_read_cells_1_to_3) return false; + if (!validity[ReadGroup_e::CV_GROUP_A]) return false; break; case ReadGroup_e::CV_GROUP_B: - if (!validity.valid_read_cells_4_to_6) return false; + if (!validity[ReadGroup_e::CV_GROUP_B]) return false; break; case ReadGroup_e::CV_GROUP_C: - if (!validity.valid_read_cells_7_to_9) return false; + if (!validity[ReadGroup_e::CV_GROUP_C]) return false; break; case ReadGroup_e::CV_GROUP_D: // Skip 9-cell chips (odd indices) - if (chip % 2 == 0 && !validity.valid_read_cells_10_to_12) return false; + if (chip % 2 == 0 && !validity[ReadGroup_e::CV_GROUP_D]) return false; break; case ReadGroup_e::AUX_GROUP_A: - if (!validity.valid_read_gpios_1_to_3) return false; + if (!validity[ReadGroup_e::AUX_GROUP_A]) return false; break; case ReadGroup_e::AUX_GROUP_B: - if (!validity.valid_read_gpios_4_to_6) return false; + if (!validity[ReadGroup_e::AUX_GROUP_B]) return false; break; default: return false; @@ -744,23 +744,23 @@ size_t BMSDriverGroup::count_invalid_pac switch (_current_read_group) { case ReadGroup_e::CV_GROUP_A: - if (!validity.valid_read_cells_1_to_3) invalid_count++; + if (!validity[ReadGroup_e::CV_GROUP_A]) invalid_count++; break; case ReadGroup_e::CV_GROUP_B: - if (!validity.valid_read_cells_4_to_6) invalid_count++; + if (!validity[ReadGroup_e::CV_GROUP_B]) invalid_count++; break; case ReadGroup_e::CV_GROUP_C: - if (!validity.valid_read_cells_7_to_9) invalid_count++; + if (!validity[ReadGroup_e::CV_GROUP_C]) invalid_count++; break; case ReadGroup_e::CV_GROUP_D: // Skip 9-cell chips (odd indices) when counting - if (chip % 2 == 0 && !validity.valid_read_cells_10_to_12) invalid_count++; + if (chip % 2 == 0 && !validity[ReadGroup_e::CV_GROUP_D]) invalid_count++; break; case ReadGroup_e::AUX_GROUP_A: - if (!validity.valid_read_gpios_1_to_3) invalid_count++; + if (!validity[ReadGroup_e::AUX_GROUP_A]) invalid_count++; break; case ReadGroup_e::AUX_GROUP_B: - if (!validity.valid_read_gpios_4_to_6) invalid_count++; + if (!validity[ReadGroup_e::AUX_GROUP_B]) invalid_count++; break; default: break; diff --git a/lib/systems/include/ACUController.h b/lib/systems/include/ACUController.h index f2889520..e6f4fc1b 100644 --- a/lib/systems/include/ACUController.h +++ b/lib/systems/include/ACUController.h @@ -138,7 +138,6 @@ class ACUController } private: - /** * @pre data has been gathered * @return boolean, true if there exists any fault @@ -177,6 +176,9 @@ class ACUController static constexpr uint32_t _bms_not_ok_hold_time_ms = 1000; + static constexpr float _hours_to_ms_factor = 3600000.0f; // hours to milliseconds + + /** * @brief ACU Controller Parameters holder */ diff --git a/lib/systems/include/BMSFaultDataManager.h b/lib/systems/include/BMSFaultDataManager.h index a9a82bd7..6798c9bc 100644 --- a/lib/systems/include/BMSFaultDataManager.h +++ b/lib/systems/include/BMSFaultDataManager.h @@ -9,23 +9,14 @@ template class BMSFaultDataManager { public: - struct BMSFaultCountData_s { - uint8_t invalid_cell_1_to_3_count = 0; - uint8_t invalid_cell_4_to_6_count = 0; - uint8_t invalid_cell_7_to_9_count = 0; - uint8_t invalid_cell_10_to_12_count= 0; - uint8_t invalid_gpio_1_to_3_count = 0; - uint8_t invalid_gpio_4_to_6_count = 0; - }; - struct BMSFaultData_s { std::array consecutive_invalid_packet_counts{}; float valid_packet_rate = 0.0f; size_t max_consecutive_invalid_packet_count = 0; - std::array chip_invalid_cmd_counts{}; + std::array, num_chips> chip_invalid_cmd_counts{}; }; - void update_from_valid_packets( const std::array& valid_read_packets); + void update_from_valid_packets( const std::array, num_chips>& valid_read_packets); const BMSFaultData_s& get_fault_data() const; diff --git a/lib/systems/include/BMSFaultDataManager.tpp b/lib/systems/include/BMSFaultDataManager.tpp index f65e41c6..c4684c62 100644 --- a/lib/systems/include/BMSFaultDataManager.tpp +++ b/lib/systems/include/BMSFaultDataManager.tpp @@ -3,31 +3,31 @@ template void BMSFaultDataManager::update_from_valid_packets( - const std::array& valid_read_packets) + const std::array, num_chips>& valid_read_packets) { - size_t num_total_bms_packets = num_chips * sizeof(BMSFaultCountData_s); + size_t num_total_bms_packets = num_chips * ReadGroup_e::NUM_GROUPS; std::array chip_max_invalid_cmd_counts = {}; - std::array temp = {}; + std::array temp = {}; size_t num_valid_packets = 0; for (size_t chip = 0; chip < valid_read_packets.size(); chip++) { - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_1_to_3_count = (!valid_read_packets[chip].valid_read_cells_1_to_3) ? _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_1_to_3_count+1 : 0; - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_4_to_6_count = (!valid_read_packets[chip].valid_read_cells_4_to_6) ? _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_4_to_6_count+1 : 0; - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_7_to_9_count = (!valid_read_packets[chip].valid_read_cells_7_to_9) ? _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_7_to_9_count+1 : 0; - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_10_to_12_count = (!valid_read_packets[chip].valid_read_cells_10_to_12) ? _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_10_to_12_count+1 : 0; - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_gpio_1_to_3_count = (!valid_read_packets[chip].valid_read_gpios_1_to_3) ? _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_gpio_1_to_3_count+1 : 0; - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_gpio_4_to_6_count = (!valid_read_packets[chip].valid_read_gpios_4_to_6) ? _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_gpio_4_to_6_count+1 : 0; - num_valid_packets += static_cast(valid_read_packets[chip].valid_read_cells_1_to_3 + valid_read_packets[chip].valid_read_cells_4_to_6 + valid_read_packets[chip].valid_read_cells_7_to_9 + - valid_read_packets[chip].valid_read_cells_10_to_12 + valid_read_packets[chip].valid_read_gpios_1_to_3 + valid_read_packets[chip].valid_read_gpios_4_to_6); + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_A] = (!valid_read_packets[chip][ReadGroup_e::CV_GROUP_A]) ? _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_A]+1 : 0; + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_B] = (!valid_read_packets[chip][ReadGroup_e::CV_GROUP_B]) ? _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_B]+1 : 0; + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_C] = (!valid_read_packets[chip][ReadGroup_e::CV_GROUP_C]) ? _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_C]+1 : 0; + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_D] = (!valid_read_packets[chip][ReadGroup_e::CV_GROUP_D]) ? _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_D]+1 : 0; + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::AUX_GROUP_A] = (!valid_read_packets[chip][ReadGroup_e::AUX_GROUP_A]) ? _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::AUX_GROUP_A]+1 : 0; + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::AUX_GROUP_B] = (!valid_read_packets[chip][ReadGroup_e::AUX_GROUP_B]) ? _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::AUX_GROUP_B]+1 : 0; + num_valid_packets += static_cast(valid_read_packets[chip][ReadGroup_e::CV_GROUP_A] + valid_read_packets[chip][ReadGroup_e::CV_GROUP_B] + valid_read_packets[chip][ReadGroup_e::CV_GROUP_C] + + valid_read_packets[chip][ReadGroup_e::CV_GROUP_D] + valid_read_packets[chip][ReadGroup_e::AUX_GROUP_A] + valid_read_packets[chip][ReadGroup_e::AUX_GROUP_B]); - temp = {_bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_1_to_3_count, - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_4_to_6_count, - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_7_to_9_count, - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_cell_10_to_12_count, - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_gpio_1_to_3_count, - _bms_fault_data.chip_invalid_cmd_counts[chip].invalid_gpio_4_to_6_count}; - chip_max_invalid_cmd_counts[chip] = *etl::max_element(temp.begin(), temp.end()); + temp = {_bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_A], + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_B], + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_C], + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::CV_GROUP_D], + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::AUX_GROUP_A], + _bms_fault_data.chip_invalid_cmd_counts[chip][ReadGroup_e::AUX_GROUP_B]}; + chip_max_invalid_cmd_counts[chip] = *etl::max_element(temp.begin(), temp.end()); _bms_fault_data.consecutive_invalid_packet_counts[chip] = chip_max_invalid_cmd_counts[chip]; } _bms_fault_data.valid_packet_rate = static_cast(static_cast(num_valid_packets) / num_total_bms_packets); diff --git a/lib/systems/src/ACUController.cpp b/lib/systems/src/ACUController.cpp index 5f38ae06..34fe9913 100644 --- a/lib/systems/src/ACUController.cpp +++ b/lib/systems/src/ACUController.cpp @@ -123,8 +123,9 @@ void ACUController::calculate_cell_balance_statuses(bool* output, const volt* vo float ACUController::get_state_of_charge(float em_current, uint32_t delta_time_ms) -{ - float delta_ah = (em_current) * ((float)(delta_time_ms) / HOUR_TO_MS_FACTOR); // amp hours +{ + + float delta_ah = (em_current) * ((float)(delta_time_ms) / _hours_to_ms_factor); // amp hours _acu_state.SoC += delta_ah / _acu_parameters.pack_specs.pack_nominal_capacity; // should be -= but EM inverted if (_acu_state.SoC < 0.0) _acu_state.SoC = 0; From 4426c4666124a04394a3e88b33f112133719d81d Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Wed, 5 Nov 2025 07:12:45 -0800 Subject: [PATCH 12/18] created a map for cmds to read group and changed store voltage and temp logic slighly so it takes individual values --- lib/interfaces/include/BMSDriverGroup.h | 27 +++-- lib/interfaces/include/BMSDriverGroup.tpp | 118 ++++++++++------------ 2 files changed, 70 insertions(+), 75 deletions(-) diff --git a/lib/interfaces/include/BMSDriverGroup.h b/lib/interfaces/include/BMSDriverGroup.h index d78dc8d9..5a0a1c87 100644 --- a/lib/interfaces/include/BMSDriverGroup.h +++ b/lib/interfaces/include/BMSDriverGroup.h @@ -295,12 +295,6 @@ class BMSDriverGroup private: - static constexpr size_t DATA_SIZE_BYTES = 6; - static constexpr size_t PEC_SIZE_BYTES = 2; - static constexpr size_t TOTAL_PACKET_SIZE_BYTES = DATA_SIZE_BYTES + PEC_SIZE_BYTES; - - ReadGroup_e _current_read_group = ReadGroup_e::CV_GROUP_A; - /** * PEC: * The Packet Error Code (PEC) is a Error Checker–like CRC for CAN–to make sure that command and data @@ -372,10 +366,11 @@ class BMSDriverGroup void _start_ADC_conversion_through_address(const std::array& cmd_code); - void _load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cv_group, + template + void _load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, uint8_t chip_index, uint8_t start_cell_index); - - void _load_auxillaries(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_gpio_group, + template + void _load_auxillaries(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, uint8_t chip_index, uint8_t start_gpio_index); /* -------------------- GETTER FUNCTIONS -------------------- */ @@ -384,7 +379,7 @@ class BMSDriverGroup * @brief When the inverters are idle, comms get funky from EMI. This function allows us to determine if the acu reads valid packets * @return bool of whether the PEC correctly reflects the buffer being given. If no, then we know that EMI (likely) is causing invalid reads */ - bool _check_if_valid_packet(const std::array &data, size_t param_iterator); + bool _check_if_valid_packet(const std::array &data, size_t param_iterator); /** * Generates a Packet Error Code @@ -414,6 +409,18 @@ class BMSDriverGroup uint8_t _get_cmd_address(int address) { return 0x80 | (address << 3); } private: + static constexpr size_t _data_size_bytes = 6; + static constexpr size_t _pec_size_bytes = 2; + static constexpr size_t _total_packet_size_bytes = _data_size_bytes + _pec_size_bytes; + static constexpr std::array _read_group_to_cmd = { + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_C, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_D, + CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, + CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B + }; + ReadGroup_e _current_read_group = ReadGroup_e::CV_GROUP_A; /** * initializes PEC table diff --git a/lib/interfaces/include/BMSDriverGroup.tpp b/lib/interfaces/include/BMSDriverGroup.tpp index 0ac72386..6d56c68a 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -165,7 +165,7 @@ template typename BMSDriverGroup::BMSDriverData BMSDriverGroup::_read_data_through_broadcast() { - constexpr size_t data_size = TOTAL_PACKET_SIZE_BYTES * (num_chips / num_chip_selects); + constexpr size_t data_size = _total_packet_size_bytes * (num_chips / num_chip_selects); for (size_t cs = 0; cs < num_chip_selects; cs++) { write_configuration(_config.dcto_read, _cell_discharge_en); @@ -176,37 +176,9 @@ BMSDriverGroup::_read_data_through_broad // Get buffers for each group we care about, all at once for ONE chip select line _start_wakeup_protocol(cs); - switch (_current_read_group) { - case ReadGroup_e::CV_GROUP_A: - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, -1); // The address should never be used here - spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); - break; - case ReadGroup_e::CV_GROUP_B: - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, -1); - spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); - break; - case ReadGroup_e::CV_GROUP_C: - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_C, -1); - spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); - break; - case ReadGroup_e::CV_GROUP_D: - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_D, -1); - spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); - break; - case ReadGroup_e::AUX_GROUP_A: - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, -1); - spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); - break; - case ReadGroup_e::AUX_GROUP_B: - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B, -1); - spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); - break; - default: - // NUM_CURRENT_GROUPS is a sentinel value and should never be reached - __builtin_unreachable(); - } + cmd_pec = _generate_CMD_PEC(_read_group_to_cmd[_current_read_group], -1); // The address should never be used here + spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); - for (size_t chip = 0; chip < num_chips / num_chip_selects; chip++) { size_t chip_index = chip + (cs * (num_chips / num_chip_selects)); @@ -220,32 +192,32 @@ BMSDriverGroup::_read_data_through_broad bool current_group_valid = false; switch(_current_read_group) { case ReadGroup_e::CV_GROUP_A: - current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); + current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_A)] = current_group_valid; start_index = 0; break; case ReadGroup_e::CV_GROUP_B: - current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); + current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_B)] = current_group_valid; start_index = 3; break; case ReadGroup_e::CV_GROUP_C: - current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); + current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_C)] = current_group_valid; start_index = 6; break; case ReadGroup_e::CV_GROUP_D: - current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); + current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_D)] = current_group_valid; start_index = 9; break; case ReadGroup_e::AUX_GROUP_A: - current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); + current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::AUX_GROUP_A)] = current_group_valid; start_index = 0; break; case ReadGroup_e::AUX_GROUP_B: - current_group_valid = _check_if_valid_packet(spi_data, TOTAL_PACKET_SIZE_BYTES * chip); + current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::AUX_GROUP_B)] = current_group_valid; start_index = 3; break; @@ -260,16 +232,24 @@ BMSDriverGroup::_read_data_through_broad } if (_current_read_group == ReadGroup_e::AUX_GROUP_B) { - std::copy_n(spi_data.begin() + (TOTAL_PACKET_SIZE_BYTES * chip), 4, spi_response.begin()); + std::copy_n(spi_data.begin() + (_total_packet_size_bytes * chip), 4, spi_response.begin()); std::fill(spi_response.begin() + 4, spi_response.end(), 0); // padding to make it 6 bytes } else { - std::copy_n(spi_data.begin() + (TOTAL_PACKET_SIZE_BYTES * chip), 6, spi_response.begin()); + std::copy_n(spi_data.begin() + (_total_packet_size_bytes * chip), 6, spi_response.begin()); } - + size_t num_values = _data_size_bytes / _config.size_of_packet_value_bytes; + std::array value_buffer; + if (_current_read_group <= ReadGroup_e::CV_GROUP_D) { - _load_cell_voltages(_bms_data, _max_min_reference, spi_response, chip_index, start_index); + for (size_t i = 0; i < num_values; i++) { + std::copy_n(spi_response.begin() + (i * _config.size_of_packet_value_bytes), _config.size_of_packet_value_bytes, value_buffer.begin()); + _load_cell_voltages<_config.size_of_packet_value_bytes>(_bms_data, _max_min_reference, value_buffer, chip_index, start_index + i); + } } else { - _load_auxillaries(_bms_data, _max_min_reference, spi_response, chip_index, start_index); + for (size_t i = 0; i < num_values; i++) { + std::copy_n(spi_response.begin() + (i * _config.size_of_packet_value_bytes), _config.size_of_packet_value_bytes, value_buffer.begin()); + _load_auxillaries<_config.size_of_packet_value_bytes>(_bms_data, _max_min_reference, value_buffer, chip_index, start_index + i); + } } } } @@ -331,13 +311,21 @@ BMSDriverGroup::_read_data_through_addre // DEBUG: Check to see that the PEC is what we expect it to be - _bms_data = _load_cell_voltages(_bms_data, max_min_reference, data_in_cell_voltages_1_to_12, chip, battery_cell_count); - _bms_data = _load_auxillaries(_bms_data, max_min_reference, data_in_auxillaries_1_to_5, chip, gpio_count); - } + size_t num_values = _data_size_bytes / _config.size_of_packet_value_bytes; + std::array value_buffer; + + for (size_t i = 0; i < 4*num_values; i++) { + std::copy_n(data_in_cell_voltages_1_to_12.begin() + (i * _config.size_of_packet_value_bytes), _config.size_of_packet_value_bytes, value_buffer.begin()); + _load_cell_voltages<_config.size_of_packet_value_bytes>(_bms_data, max_min_reference, value_buffer, chip, i); + } + for (size_t i = 0; i < 2*num_values; i++) { + std::copy_n(data_in_auxillaries_1_to_5.begin() + (i * _config.size_of_packet_value_bytes), _config.size_of_packet_value_bytes, value_buffer.begin()); + _load_auxillaries(_bms_data, max_min_reference, value_buffer, chip, gpio_count); + } _bms_data.min_cell_voltage = max_min_reference.min_cell_voltage; _bms_data.max_cell_voltage = max_min_reference.max_cell_voltage; - _bms_data.total_voltage = _sum_cell_voltages(); + _bms_data.total_voltage = max_min_reference.total_voltage; _bms_data.avg_cell_voltage = _bms_data.total_voltage / num_cells; // Avoid divide by zero - skip calculation if no GPIOs were read @@ -350,41 +338,41 @@ BMSDriverGroup::_read_data_through_addre return _bms_data; } - template -void BMSDriverGroup::_load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cv_group, +template +void BMSDriverGroup::_load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, uint8_t chip_index, uint8_t start_cell_index) { - std::array data_in_cell_voltage; uint8_t cell_global_offset = (chip_index / 2) * 21 + (chip_index % 2) * 12; - for (int cell_Index = start_cell_index; cell_Index < start_cell_index+3; cell_Index++) - { - std::copy_n(data_in_cv_group.begin() + (cell_Index - start_cell_index) * 2, 2, data_in_cell_voltage.begin()); + // for (int cell_Index = start_cell_index; cell_Index < start_cell_index+3; cell_Index++) + // { + // std::copy_n(data_in_cv_group.begin() + (cell_Index - start_cell_index) * 2, 2, data_in_cell_voltage.begin()); uint16_t voltage_in = data_in_cell_voltage[1] << 8 | data_in_cell_voltage[0]; float voltage_converted = voltage_in * _config.cv_adc_lsb_voltage; - uint8_t cell_voltage_index = cell_global_offset + cell_Index; + uint8_t cell_voltage_index = cell_global_offset + start_cell_index; // Calculate the correct global voltage array index _store_voltage_data(bms_data, max_min_ref, voltage_converted, cell_voltage_index); - } + // } } template -void BMSDriverGroup::_load_auxillaries(BMSDriverData& bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_gpio_group, +template +void BMSDriverGroup::_load_auxillaries(BMSDriverData& bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, uint8_t chip_index, uint8_t start_gpio_index) { - for (int gpio_index = start_gpio_index; gpio_index < start_gpio_index + 3 && gpio_index < 5; gpio_index++) // There are only five Auxillary ports - { - std::array data_in_gpio_voltage; - std::copy_n(data_in_gpio_group.begin() + (gpio_index - start_gpio_index) * 2, 2, data_in_gpio_voltage.begin()); - - uint16_t gpio_in = data_in_gpio_voltage[1] << 8 | data_in_gpio_voltage[0]; - _store_temperature_humidity_data(bms_data, max_min_ref, gpio_in, gpio_index, chip_index); - } + // for (int gpio_index = start_gpio_index; gpio_index < start_gpio_index + 3 && gpio_index < 5; gpio_index++) // There are only five Auxillary ports + // { + // std::array data_in_gpio_voltage; + // std::copy_n(data_in_gpio_group.begin() + (gpio_index - start_gpio_index) * 2, 2, data_in_gpio_voltage.begin()); + + uint16_t gpio_in = data_in_temp[1] << 8 | data_in_temp[0]; + _store_temperature_humidity_data(bms_data, max_min_ref, gpio_in, start_gpio_index, chip_index); + // } } template @@ -496,7 +484,7 @@ void BMSDriverGroup::write_configuration template void BMSDriverGroup::_write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses) { - constexpr size_t data_size = TOTAL_PACKET_SIZE_BYTES * (num_chips / num_chip_selects); + constexpr size_t data_size = _total_packet_size_bytes * (num_chips / num_chip_selects); std::array cmd_and_pec = _generate_CMD_PEC(CMD_CODES_e::WRITE_CONFIG, -1); std::array full_buffer; std::array temp_pec; @@ -665,7 +653,7 @@ std::array BMSDriverGroup::_ template -bool BMSDriverGroup::_check_if_valid_packet(const std::array &data, size_t param_iterator) +bool BMSDriverGroup::_check_if_valid_packet(const std::array &data, size_t param_iterator) { std::array sample_packet; std::array sample_pec; From 5e3bb2e97f946a070b2e311bded2d41432854e03 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Thu, 6 Nov 2025 15:27:41 -0800 Subject: [PATCH 13/18] removed 2 const for size_of_packet_value_bytes --- lib/interfaces/include/BMSDriverGroup.h | 37 +++--- lib/interfaces/include/BMSDriverGroup.tpp | 153 +++++++++++----------- 2 files changed, 92 insertions(+), 98 deletions(-) diff --git a/lib/interfaces/include/BMSDriverGroup.h b/lib/interfaces/include/BMSDriverGroup.h index 5a0a1c87..3c9519b5 100644 --- a/lib/interfaces/include/BMSDriverGroup.h +++ b/lib/interfaces/include/BMSDriverGroup.h @@ -85,7 +85,7 @@ namespace bms_driver_defaults constexpr const float CV_ADC_CONVERSION_TIME_MS = 1.2f; constexpr const float GPIO_ADC_CONVERSION_TIME_MS = 1.2f; constexpr const float CV_ADC_LSB_VOLTAGE = 0.0001f; // Cell voltage ADC resolution: 100μV per LSB (1/10000 V) - constexpr const int SIZE_OF_PACKET_VALUE_BYTES = 2; // each cell voltage or gpio reading is 2 bytes + constexpr const size_t SIZE_OF_PACKET_VALUE_BYTES = 2; } @@ -142,7 +142,6 @@ struct BMSDriverGroupConfig_s float cv_adc_conversion_time_ms; float gpio_adc_conversion_time_ms; float cv_adc_lsb_voltage; - float size_of_packet_value_bytes; }; @@ -158,7 +157,7 @@ constexpr ReadGroup_e advance_read_group(ReadGroup_e current) ); } -template +template class BMSDriverGroup { public: @@ -294,6 +293,18 @@ class BMSDriverGroup } private: + static constexpr size_t _data_size_bytes = 6; + static constexpr size_t _pec_size_bytes = 2; + static constexpr size_t _total_packet_size_bytes = _data_size_bytes + _pec_size_bytes; + static constexpr std::array _read_group_to_cmd = { + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_C, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_D, + CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, + CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B + }; + ReadGroup_e _current_read_group = ReadGroup_e::CV_GROUP_A; /** * PEC: @@ -366,11 +377,9 @@ class BMSDriverGroup void _start_ADC_conversion_through_address(const std::array& cmd_code); - template - void _load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, + void _load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, uint8_t chip_index, uint8_t start_cell_index); - template - void _load_auxillaries(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, + void _load_auxillaries(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, uint8_t chip_index, uint8_t start_gpio_index); /* -------------------- GETTER FUNCTIONS -------------------- */ @@ -409,18 +418,6 @@ class BMSDriverGroup uint8_t _get_cmd_address(int address) { return 0x80 | (address << 3); } private: - static constexpr size_t _data_size_bytes = 6; - static constexpr size_t _pec_size_bytes = 2; - static constexpr size_t _total_packet_size_bytes = _data_size_bytes + _pec_size_bytes; - static constexpr std::array _read_group_to_cmd = { - CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, - CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, - CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_C, - CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_D, - CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, - CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B - }; - ReadGroup_e _current_read_group = ReadGroup_e::CV_GROUP_A; /** * initializes PEC table @@ -486,7 +483,7 @@ class BMSDriverGroup }; template -using BMSDriverInstance = etl::singleton>; +using BMSDriverInstance = etl::singleton>; #include diff --git a/lib/interfaces/include/BMSDriverGroup.tpp b/lib/interfaces/include/BMSDriverGroup.tpp index 6d56c68a..13441b43 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -7,8 +7,8 @@ #include #include -template -BMSDriverGroup::BMSDriverGroup(const std::array& cs, +template +BMSDriverGroup::BMSDriverGroup(const std::array& cs, const std::array& cs_per_chip, const std::array& addr, const BMSDriverGroupConfig_s default_params = { @@ -28,9 +28,7 @@ BMSDriverGroup::BMSDriverGroup(const std .CRC15_POLY = bms_driver_defaults::CRC15_POLY, .cv_adc_conversion_time_ms = bms_driver_defaults::CV_ADC_CONVERSION_TIME_MS, .gpio_adc_conversion_time_ms = bms_driver_defaults::GPIO_ADC_CONVERSION_TIME_MS, - .cv_adc_lsb_voltage = bms_driver_defaults::CV_ADC_LSB_VOLTAGE, - .size_of_packet_value_bytes = bms_driver_defaults::SIZE_OF_PACKET_VALUE_BYTES - + .cv_adc_lsb_voltage = bms_driver_defaults::CV_ADC_LSB_VOLTAGE } ) : _chip_select(cs), _chip_select_per_chip(cs_per_chip), @@ -38,8 +36,8 @@ BMSDriverGroup::BMSDriverGroup(const std _config(default_params), _pec15Table(_initialize_Pec_Table()) {} -template -void BMSDriverGroup::init() +template +void BMSDriverGroup::init() { // We initialized the pec table during beginning of runtime which allows _pec15table to be const -> no need to call in init() for (size_t i = 0; i < num_chip_selects; i++) @@ -56,8 +54,8 @@ void BMSDriverGroup::init() _bms_data.total_voltage = 0; } -template -void BMSDriverGroup::_start_wakeup_protocol() +template +void BMSDriverGroup::_start_wakeup_protocol() { for (size_t cs = 0; cs < num_chip_selects; cs++) { @@ -65,8 +63,8 @@ void BMSDriverGroup::_start_wakeup_proto } } -template -void BMSDriverGroup::_start_wakeup_protocol(size_t cs) +template +void BMSDriverGroup::_start_wakeup_protocol(size_t cs) { if constexpr (chip_type == LTC6811_Type_e::LTC6811_1) { @@ -82,8 +80,8 @@ void BMSDriverGroup::_start_wakeup_proto } } -template -constexpr std::array BMSDriverGroup::_initialize_Pec_Table() +template +constexpr std::array BMSDriverGroup::_initialize_Pec_Table() { std::array temp{}; // Logic to fill temp @@ -109,8 +107,8 @@ constexpr std::array BMSDriverGroup -BMSCoreData_s BMSDriverGroup::get_bms_core_data() +template +BMSCoreData_s BMSDriverGroup::get_bms_core_data() { BMSCoreData_s out{}; @@ -127,16 +125,16 @@ BMSCoreData_s BMSDriverGroup::get_bms_co return out; } -template -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::get_bms_data() +template +typename BMSDriverGroup::BMSDriverData +BMSDriverGroup::get_bms_data() { return _bms_data; } -template -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::read_data() +template +typename BMSDriverGroup::BMSDriverData +BMSDriverGroup::read_data() { BMSDriverData bms_data; if constexpr (chip_type == LTC6811_Type_e::LTC6811_1) @@ -161,9 +159,9 @@ BMSDriverGroup::read_data() return bms_data; } -template -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::_read_data_through_broadcast() +template +typename BMSDriverGroup::BMSDriverData +BMSDriverGroup::_read_data_through_broadcast() { constexpr size_t data_size = _total_packet_size_bytes * (num_chips / num_chip_selects); for (size_t cs = 0; cs < num_chip_selects; cs++) @@ -237,18 +235,18 @@ BMSDriverGroup::_read_data_through_broad } else { std::copy_n(spi_data.begin() + (_total_packet_size_bytes * chip), 6, spi_response.begin()); } - size_t num_values = _data_size_bytes / _config.size_of_packet_value_bytes; - std::array value_buffer; + size_t num_values = _data_size_bytes / size_of_packet_value_bytes; + std::array value_buffer; if (_current_read_group <= ReadGroup_e::CV_GROUP_D) { for (size_t i = 0; i < num_values; i++) { - std::copy_n(spi_response.begin() + (i * _config.size_of_packet_value_bytes), _config.size_of_packet_value_bytes, value_buffer.begin()); - _load_cell_voltages<_config.size_of_packet_value_bytes>(_bms_data, _max_min_reference, value_buffer, chip_index, start_index + i); + std::copy_n(spi_response.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); + _load_cell_voltages(_bms_data, _max_min_reference, value_buffer, chip_index, start_index + i); } } else { for (size_t i = 0; i < num_values; i++) { - std::copy_n(spi_response.begin() + (i * _config.size_of_packet_value_bytes), _config.size_of_packet_value_bytes, value_buffer.begin()); - _load_auxillaries<_config.size_of_packet_value_bytes>(_bms_data, _max_min_reference, value_buffer, chip_index, start_index + i); + std::copy_n(spi_response.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); + _load_auxillaries(_bms_data, _max_min_reference, value_buffer, chip_index, start_index + i); } } } @@ -269,9 +267,9 @@ BMSDriverGroup::_read_data_through_broad return _bms_data; } -template -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::_read_data_through_address() +template +typename BMSDriverGroup::BMSDriverData +BMSDriverGroup::_read_data_through_address() { ReferenceMaxMin_s max_min_reference; std::array clean_valid_packet_data = {true}; // should be all reset to true @@ -311,17 +309,18 @@ BMSDriverGroup::_read_data_through_addre // DEBUG: Check to see that the PEC is what we expect it to be - size_t num_values = _data_size_bytes / _config.size_of_packet_value_bytes; - std::array value_buffer; + size_t num_values = _data_size_bytes / size_of_packet_value_bytes; + std::array value_buffer; for (size_t i = 0; i < 4*num_values; i++) { - std::copy_n(data_in_cell_voltages_1_to_12.begin() + (i * _config.size_of_packet_value_bytes), _config.size_of_packet_value_bytes, value_buffer.begin()); - _load_cell_voltages<_config.size_of_packet_value_bytes>(_bms_data, max_min_reference, value_buffer, chip, i); + std::copy_n(data_in_cell_voltages_1_to_12.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); + _load_cell_voltages(_bms_data, max_min_reference, value_buffer, chip, i); } for (size_t i = 0; i < 2*num_values; i++) { - std::copy_n(data_in_auxillaries_1_to_5.begin() + (i * _config.size_of_packet_value_bytes), _config.size_of_packet_value_bytes, value_buffer.begin()); + std::copy_n(data_in_auxillaries_1_to_5.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); _load_auxillaries(_bms_data, max_min_reference, value_buffer, chip, gpio_count); } + } _bms_data.min_cell_voltage = max_min_reference.min_cell_voltage; _bms_data.max_cell_voltage = max_min_reference.max_cell_voltage; @@ -338,9 +337,8 @@ BMSDriverGroup::_read_data_through_addre return _bms_data; } -template -template -void BMSDriverGroup::_load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, +template +void BMSDriverGroup::_load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, uint8_t chip_index, uint8_t start_cell_index) { @@ -360,9 +358,8 @@ void BMSDriverGroup::_load_cell_voltages // } } -template -template -void BMSDriverGroup::_load_auxillaries(BMSDriverData& bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, +template +void BMSDriverGroup::_load_auxillaries(BMSDriverData& bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, uint8_t chip_index, uint8_t start_gpio_index) { // for (int gpio_index = start_gpio_index; gpio_index < start_gpio_index + 3 && gpio_index < 5; gpio_index++) // There are only five Auxillary ports @@ -375,8 +372,8 @@ void BMSDriverGroup::_load_auxillaries(B // } } -template -void BMSDriverGroup::_store_voltage_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, volt voltage_in, uint8_t cell_index) +template +void BMSDriverGroup::_store_voltage_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, volt voltage_in, uint8_t cell_index) { max_min_reference.total_voltage -= bms_data.voltages[cell_index]; bms_data.voltages[cell_index] = voltage_in; @@ -394,8 +391,8 @@ void BMSDriverGroup::_store_voltage_data } } -template -void BMSDriverGroup::_store_temperature_humidity_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, const uint16_t &gpio_in, uint8_t gpio_index, uint8_t chip_index) +template +void BMSDriverGroup::_store_temperature_humidity_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, const uint16_t &gpio_in, uint8_t gpio_index, uint8_t chip_index) { // there is 8 cell temperatures per chip, and 2 board temperatures per board, so 4+1 per chip if (gpio_index < 4) // These are all thermistors [0,1,2,3]. @@ -435,8 +432,8 @@ void BMSDriverGroup::_store_temperature_ /* -------------------- WRITING DATA FUNCTIONS -------------------- */ -template -void BMSDriverGroup::write_configuration(const std::array &cell_balance_statuses) +template +void BMSDriverGroup::write_configuration(const std::array &cell_balance_statuses) { std::array cb; size_t global_cell_index = 0; @@ -458,8 +455,8 @@ void BMSDriverGroup::write_configuration write_configuration(_config.dcto_write, cb); } -template -void BMSDriverGroup::write_configuration(uint8_t dcto_mode, const std::array &cell_balance_statuses) +template +void BMSDriverGroup::write_configuration(uint8_t dcto_mode, const std::array &cell_balance_statuses) { std::copy(cell_balance_statuses.begin(), cell_balance_statuses.end(), _cell_discharge_en.begin()); @@ -481,8 +478,8 @@ void BMSDriverGroup::write_configuration } } -template -void BMSDriverGroup::_write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses) +template +void BMSDriverGroup::_write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses) { constexpr size_t data_size = _total_packet_size_bytes * (num_chips / num_chip_selects); std::array cmd_and_pec = _generate_CMD_PEC(CMD_CODES_e::WRITE_CONFIG, -1); @@ -510,8 +507,8 @@ void BMSDriverGroup::_write_config_throu } /* UNUSED: LTC6811-2 ADDRESS MODE - REFERENCE ONLY -template -void BMSDriverGroup::_write_config_through_address(uint8_t dcto_mode, const std::array& buffer_format, const std::array &cell_balance_statuses) +template +void BMSDriverGroup::_write_config_through_address(uint8_t dcto_mode, const std::array& buffer_format, const std::array &cell_balance_statuses) { // Need to manipulate the command code to have address, therefore have to send command num_chips times std::array cmd_and_pec; @@ -530,8 +527,8 @@ void BMSDriverGroup::_write_config_throu } */ -template -void BMSDriverGroup::_start_cell_voltage_ADC_conversion() +template +void BMSDriverGroup::_start_cell_voltage_ADC_conversion() { uint16_t adc_cmd = (uint16_t)CMD_CODES_e::START_CV_ADC_CONVERSION | (_config.adc_mode_cv_conversion << 7) | (_config.discharge_permitted << 4) | static_cast(_config.adc_conversion_cell_select_mode); std::array cmd; @@ -547,8 +544,8 @@ void BMSDriverGroup::_start_cell_voltage } } -template -void BMSDriverGroup::_start_GPIO_ADC_conversion() +template +void BMSDriverGroup::_start_GPIO_ADC_conversion() { uint16_t adc_cmd = (uint16_t)CMD_CODES_e::START_GPIO_ADC_CONVERSION | (_config.adc_mode_gpio_conversion << 7); // | static_cast(_config.adc_conversion_gpio_select_mode); std::array cmd; @@ -565,8 +562,8 @@ void BMSDriverGroup::_start_GPIO_ADC_con } } -template -void BMSDriverGroup::_start_ADC_conversion_through_broadcast(const std::array &cmd_code) +template +void BMSDriverGroup::_start_ADC_conversion_through_broadcast(const std::array &cmd_code) { // Leave the command code as is std::array cc = {cmd_code[0], cmd_code[1]}; @@ -583,8 +580,8 @@ void BMSDriverGroup::_start_ADC_conversi } /* UNUSED: LTC6811-2 ADDRESS MODE - REFERENCE ONLY -template -void BMSDriverGroup::_start_ADC_conversion_through_address(const std::array& cmd_code) +template +void BMSDriverGroup::_start_ADC_conversion_through_address(const std::array& cmd_code) { // Need to manipulate the command code to have address, therefore have to send command num_chips times for (size_t i = 0; i < num_chips; i++) @@ -602,8 +599,8 @@ void BMSDriverGroup::_start_ADC_conversi /* -------------------- GETTER FUNCTIONS -------------------- */ // This implementation is taken directly from the data sheet linked here: https://www.analog.com/media/en/technical-documentation/data-sheets/LTC6811-1-6811-2.pdf -template -std::array BMSDriverGroup::_calculate_specific_PEC(const uint8_t *data, int length) +template +std::array BMSDriverGroup::_calculate_specific_PEC(const uint8_t *data, int length) { std::array pec; uint16_t remainder; @@ -620,8 +617,8 @@ std::array BMSDriverGroup::_ return pec; } -template -std::array BMSDriverGroup::_generate_formatted_CMD(CMD_CODES_e command, int ic_index) +template +std::array BMSDriverGroup::_generate_formatted_CMD(CMD_CODES_e command, int ic_index) { std::array cmd; const uint16_t cmd_val = static_cast(command); @@ -639,8 +636,8 @@ std::array BMSDriverGroup::_ return cmd; } -template -std::array BMSDriverGroup::_generate_CMD_PEC(CMD_CODES_e command, int ic_index) +template +std::array BMSDriverGroup::_generate_CMD_PEC(CMD_CODES_e command, int ic_index) { std::array cmd_pec; std::array cmd = _generate_formatted_CMD(command, ic_index); @@ -652,8 +649,8 @@ std::array BMSDriverGroup::_ -template -bool BMSDriverGroup::_check_if_valid_packet(const std::array &data, size_t param_iterator) +template +bool BMSDriverGroup::_check_if_valid_packet(const std::array &data, size_t param_iterator) { std::array sample_packet; std::array sample_pec; @@ -666,8 +663,8 @@ bool BMSDriverGroup::_check_if_valid_pac /* -------------------- OBSERVABILITY FUNCTIONS -------------------- */ -template -const char* BMSDriverGroup::get_current_read_group_name() +template +const char* BMSDriverGroup::get_current_read_group_name() { switch (_current_read_group) { case ReadGroup_e::CV_GROUP_A: @@ -687,8 +684,8 @@ const char* BMSDriverGroup::get_current_ } } -template -bool BMSDriverGroup::last_read_all_valid() +template +bool BMSDriverGroup::last_read_all_valid() { // Check validity for the specific group that was just read (current state before advancing) for (size_t chip = 0; chip < num_chips; chip++) { @@ -721,8 +718,8 @@ bool BMSDriverGroup::last_read_all_valid return true; } -template -size_t BMSDriverGroup::count_invalid_packets() +template +size_t BMSDriverGroup::count_invalid_packets() { size_t invalid_count = 0; From 1d632d8ab9aa8464d686a92e9deae3a64c69e9c4 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Thu, 6 Nov 2025 19:54:21 -0800 Subject: [PATCH 14/18] added ChipSelectConfig as param to BMSDriverGroup and made user it pases all tests and builds --- include/ACU_Constants.h | 125 +++--- include/ACU_InterfaceTasks.h | 4 +- include/ACU_SystemTasks.h | 5 +- lib/interfaces/include/BMSDriverGroup.h | 122 +++--- lib/interfaces/include/BMSDriverGroup.tpp | 500 ++++++++++------------ lib/shared_types/shared_types.h | 253 ++++++----- src/ACU_InterfaceTasks.cpp | 10 +- 7 files changed, 504 insertions(+), 515 deletions(-) diff --git a/include/ACU_Constants.h b/include/ACU_Constants.h index 5eac4677..20901a28 100644 --- a/include/ACU_Constants.h +++ b/include/ACU_Constants.h @@ -55,27 +55,24 @@ namespace ACUInterfaces { namespace ACUConstants { constexpr size_t NUM_CELLS = 126; - constexpr size_t NUM_CHIPS = 12; + constexpr size_t NUM_CHIPS_PER_SELECT = 6; constexpr size_t NUM_CHIP_SELECTS = 2; constexpr size_t NUM_CHIPS_PER_CS = 6; constexpr size_t DATA_PER_CHIP_GROUP = 3; - constexpr std::array TEMP_CELLS_PER_CHIP = { - 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4 + constexpr std::array VOLTAGE_CELLS_PER_CHIP = { + 12, 9, 12, 9, 12, 9, 12, 9, 12, 9, 12, 9 }; - constexpr std::array VOLTAGE_CELLS_PER_CHIP = { - 12, 9, 12, 9, 12, 9, - 12, 9, 12, 9, 12, 9 + constexpr std::array TEMP_CELLS_PER_CHIP = { + 4,4,4,4,4,4,4,4,4,4,4,4 }; - constexpr ChipSelectConfig BMS_CHIP_SELECTS = ChipSelectConfig{ + constexpr ChipSelectConfig BMS_CHIP_SELECTS = ChipSelectConfig( std::array{ - ChipSelect{ + ChipSelect( 9, std::array{ - Chips{0, - ReadGroupResultMap{ - {3, 3, 3, 3, 3, 2}, + Chip{0, + ReadGroupResultMap( std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B @@ -84,11 +81,10 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{1, - ReadGroupResultMap{ - {3, 3, 3, 0, 3, 2}, + Chip{1, + ReadGroupResultMap( std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B @@ -97,12 +93,11 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{2, - ReadGroupResultMap{ - {3, 3, 3, 3, 3, 2}, - std::array{ + Chip{2, + ReadGroupResultMap( + std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C @@ -110,11 +105,10 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{3, - ReadGroupResultMap{ - {3, 3, 3, 0, 3, 2}, + Chip{3, + ReadGroupResultMap( std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B @@ -123,12 +117,11 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{4, - ReadGroupResultMap{ - {3, 3, 3, 3, 3, 2}, - std::array{ + Chip{4, + ReadGroupResultMap( + std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C @@ -136,11 +129,10 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{5, - ReadGroupResultMap{ - {3, 3, 3, 0, 3, 2}, + Chip{5, + ReadGroupResultMap( std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B @@ -149,17 +141,16 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, } - }, - ChipSelect{ + ), + ChipSelect( 10, std::array{ - Chips{6, - ReadGroupResultMap{ - {3, 3, 3, 3, 3, 2}, - std::array{ + Chip{6, + ReadGroupResultMap( + std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C @@ -167,11 +158,10 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{7, - ReadGroupResultMap{ - {3, 3, 3, 0, 3, 2}, + Chip{7, + ReadGroupResultMap( std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B @@ -180,12 +170,11 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{8, - ReadGroupResultMap{ - {3, 3, 3, 3, 3, 2}, - std::array{ + Chip{8, + ReadGroupResultMap( + std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C @@ -193,11 +182,10 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{9, - ReadGroupResultMap{ - {3, 3, 3, 0, 3, 2}, + Chip{9, + ReadGroupResultMap( std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B @@ -206,12 +194,11 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{10, - ReadGroupResultMap{ - {3, 3, 3, 3, 3, 2}, - std::array{ + Chip{10, + ReadGroupResultMap( + std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // C @@ -219,11 +206,10 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, - Chips{11, - ReadGroupResultMap{ - {3, 3, 3, 0, 3, 2}, + Chip{11, + ReadGroupResultMap( std::array{ std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // A std::array{ ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE, ReadDataResultType_e::CELL_VOLTAGE }, // B @@ -232,20 +218,19 @@ namespace ACUConstants std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::CELL_TEMPERATURE }, // AUX_A std::array{ ReadDataResultType_e::CELL_TEMPERATURE, ReadDataResultType_e::BOARD_TEMPERATURE, ReadDataResultType_e::NO_DATA } // AUX_B } - } + ) }, } + ) } - } - }; + ); + constexpr size_t NUM_VOLTAGE_CELLS = BMS_CHIP_SELECTS.get_num_cell_voltages(); + constexpr size_t NUM_TEMP_CELLS = BMS_CHIP_SELECTS.get_num_cell_temps(); + constexpr size_t NUM_BOARD_TEMPS = BMS_CHIP_SELECTS.get_num_board_temps(); const float VALID_SHDN_OUT_MIN_VOLTAGE_THRESHOLD = 12.0F; const uint32_t MIN_ALLOWED_INVALID_SHDN_OUT_MS = 10; // 10 ms -- requies 100 Hz samp freq. - // Initialize chip_select, chip_select_per_chip, and address - constexpr std::array CS = {9, 10}; - constexpr std::array CS_PER_CHIP = {9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10}; - constexpr std::array ADDR = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; // only for addressable bms chips /* Task Times */ constexpr uint32_t TICK_SM_PERIOD_US = 1000UL; // 1 000 us = 1000 Hz diff --git a/include/ACU_InterfaceTasks.h b/include/ACU_InterfaceTasks.h index 7fa445cf..8ff563c7 100644 --- a/include/ACU_InterfaceTasks.h +++ b/include/ACU_InterfaceTasks.h @@ -24,8 +24,8 @@ #include using chip_type = LTC6811_Type_e; -using BMSDriverInstance_t = BMSDriverInstance; -using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; +using BMSDriverInstance_t = BMSDriverInstance; +using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; /** * Init Functions - to be called in setup */ diff --git a/include/ACU_SystemTasks.h b/include/ACU_SystemTasks.h index 5a0f5356..65a2ff7c 100644 --- a/include/ACU_SystemTasks.h +++ b/include/ACU_SystemTasks.h @@ -19,8 +19,9 @@ #include using chip_type = LTC6811_Type_e; -using BMSDriverInstance_t = BMSDriverInstance; -using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; +using BMSDriverInstance_t = BMSDriverInstance; +using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; + bool initialize_all_systems(); /* Delegate Functions */ diff --git a/lib/interfaces/include/BMSDriverGroup.h b/lib/interfaces/include/BMSDriverGroup.h index 3c9519b5..c80a929f 100644 --- a/lib/interfaces/include/BMSDriverGroup.h +++ b/lib/interfaces/include/BMSDriverGroup.h @@ -90,13 +90,13 @@ namespace bms_driver_defaults -template +template struct BMSData_s { std::array, num_chips> valid_read_packets; - std::array voltages; - std::array cell_temperatures; - std::array board_temperatures; + std::array voltages; + std::array cell_temperatures; + std::array board_temperatures; volt min_cell_voltage; volt max_cell_voltage; celsius max_cell_temp; @@ -157,21 +157,34 @@ constexpr ReadGroup_e advance_read_group(ReadGroup_e current) ); } -template +template class BMSDriverGroup { public: - constexpr static size_t num_cells = (num_chips / 2) * 21; + // constexpr static size_t num_cells = (num_chips / 2) * 21; - constexpr static size_t num_cell_temps = (num_chips * 4); - constexpr static size_t num_board_temps = num_chips; + // constexpr static size_t num_cell_temps = (num_chips * 4); + // constexpr static size_t num_board_temps = num_chips; - using BMSDriverData = BMSData_s; + static constexpr size_t _packet_data_size_bytes = 6; + static constexpr size_t _packet_pec_size_bytes = 2; + static constexpr size_t _num_values_per_packet = _packet_data_size_bytes / size_of_packet_value_bytes; + static constexpr size_t _total_packet_size_bytes = _packet_data_size_bytes + _packet_pec_size_bytes; + static constexpr std::array _read_group_to_cmd = { + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_C, + CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_D, + CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, + CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B + }; + using ChipSelectConfig_t = ChipSelectConfig; + using ChipSelect_t = ChipSelect; + using Chip_t = Chip<_num_values_per_packet>; + using BMSDriverData_t = BMSData_s; BMSDriverGroup( - const std::array& cs, - const std::array& cs_per_chip, - const std::array& addr, + const ChipSelectConfig_t& chip_select_config, const BMSDriverGroupConfig_s default_params ); @@ -196,7 +209,7 @@ class BMSDriverGroup * AND record the maximum value and locations */ // void read_thermistor_and_humidity(); - BMSDriverData read_data(); + BMSDriverData_t read_data(); /** * Getter function to retrieve the ACUData structure @@ -206,7 +219,7 @@ class BMSDriverGroup /** * Getter function to retrieve the BMSDriverData structure */ - BMSDriverData get_bms_data(); + BMSDriverData_t get_bms_data(); /* -------------------- WRITING DATA FUNCTIONS -------------------- */ @@ -215,12 +228,12 @@ class BMSDriverGroup * @pre needs access to undervoltage, overvoltage, configuration MACROS, and discharge data * @post sends packaged data over SPI */ - void write_configuration(uint8_t dcto_mode, const std::array &cell_balance_statuses); + void write_configuration(uint8_t dcto_mode, const std::array &cell_balance_statuses); /** * Alternative header for configuration function call */ - void write_configuration(const std::array &cell_balance_statuses); + void write_configuration(const bool* cell_balance_statuses, size_t cell_balance_statuses_size); /* -------------------- OBSERVABILITY FUNCTIONS -------------------- */ @@ -255,7 +268,7 @@ class BMSDriverGroup * @note Each chip has 6 validity flags (cells 1-3, 4-6, 7-9, 10-12, GPIO 1-3, 4-6) * @note Useful for fault detection and EMI resilience monitoring */ - const std::array, num_chips>& get_validity_data() { + const std::array, num_chip_selects * num_chips_per_chip_select>& get_validity_data() { return _bms_data.valid_read_packets; } @@ -279,8 +292,8 @@ class BMSDriverGroup * @note Each bit represents one cell's balance enable status * @note Useful for verifying write_configuration() worked correctly */ - const std::array& get_cell_discharge_enable() { - return _cell_discharge_en; + const std::array& get_cell_discharge_enable() { + return _cell_discharge_en; } /** @@ -293,17 +306,6 @@ class BMSDriverGroup } private: - static constexpr size_t _data_size_bytes = 6; - static constexpr size_t _pec_size_bytes = 2; - static constexpr size_t _total_packet_size_bytes = _data_size_bytes + _pec_size_bytes; - static constexpr std::array _read_group_to_cmd = { - CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, - CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, - CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_C, - CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_D, - CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, - CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B - }; ReadGroup_e _current_read_group = ReadGroup_e::CV_GROUP_A; /** @@ -324,9 +326,9 @@ class BMSDriverGroup */ void _start_wakeup_protocol(); - void _start_wakeup_protocol(size_t cs); + void _start_wakeup_protocol(size_t chip_select_pin); - BMSDriverData _read_data_through_broadcast(); + BMSDriverData_t _read_data_through_broadcast(); /** * REFERENCE ONLY: LTC6811-2 ADDRESS MODE IS BROKEN AND UNUSED @@ -350,15 +352,15 @@ class BMSDriverGroup * PRODUCTION: All production code uses LTC6811_1 (broadcast mode) exclusively. * See ACU_InterfaceTasks.cpp lines 27-28. */ - BMSDriverData _read_data_through_address(); + BMSDriverData_t _read_data_through_address(); - void _store_temperature_humidity_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, const uint16_t &gpio_in, uint8_t gpio_index, uint8_t chip_index); + void _store_cell_temperature_data(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_reference, const uint16_t &temp_in, uint8_t cell_temp_index); + void _store_board_temperature_data(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_reference, const uint16_t &temp_in, uint8_t board_index); + void _store_voltage_data(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_reference, volt voltage_in, uint8_t cell_index); - void _store_voltage_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, volt voltage_in, uint8_t cell_index); + void _write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses); - void _write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses); - - void _write_config_through_address(uint8_t dcto_mode, const std::array& buffer_format, const std::array &cell_balance_statuses); + // void _write_config_through_address(uint8_t dcto_mode, const std::array& buffer_format, const std::array &cell_balance_statuses); /** * Writes command to start cell voltage ADC converion @@ -375,20 +377,18 @@ class BMSDriverGroup void _start_ADC_conversion_through_broadcast(const std::array &cmd_code); - void _start_ADC_conversion_through_address(const std::array& cmd_code); - - void _load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, - uint8_t chip_index, uint8_t start_cell_index); - void _load_auxillaries(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, - uint8_t chip_index, uint8_t start_gpio_index); + // void _start_ADC_conversion_through_address(const std::array& cmd_code); + void _load_cell_voltages(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, uint8_t cell_index); + void _load_cell_temps(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, uint8_t cell_index); + void _load_board_temps(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, uint8_t board_index); /* -------------------- GETTER FUNCTIONS -------------------- */ /** * @brief When the inverters are idle, comms get funky from EMI. This function allows us to determine if the acu reads valid packets * @return bool of whether the PEC correctly reflects the buffer being given. If no, then we know that EMI (likely) is causing invalid reads */ - bool _check_if_valid_packet(const std::array &data, size_t param_iterator); + bool _check_if_valid_packet(const std::array &data, size_t param_iterator); /** * Generates a Packet Error Code @@ -404,13 +404,13 @@ class BMSDriverGroup * Generates a formmatted 2 byte array for the Command bytes * @return unsigned 8 bit array of length 2 */ - std::array _generate_formatted_CMD(CMD_CODES_e command, int ic_index); + std::array _generate_formatted_CMD(CMD_CODES_e command, size_t chip_addr); /** * Generates Command and PEC as one byte array of length 4: CMD0, CMD1, PEC0, PEC1 * @return unsigned 8 bit, length 4 */ - std::array _generate_CMD_PEC(CMD_CODES_e command, int ic_index); + std::array _generate_CMD_PEC(CMD_CODES_e command, size_t chip_addr); /** * @return usable command address for LTC6811_2 @@ -428,7 +428,7 @@ class BMSDriverGroup constexpr std::array _initialize_Pec_Table(); /* MEMBER VARIABLES */ - BMSDriverData _bms_data; + BMSDriverData_t _bms_data; /** * Tracks min/max/sum values across all 6 read groups within a single timestamp cycle. @@ -442,25 +442,9 @@ class BMSDriverGroup * It can only be 9 or 10 * NOTE: needs to be initialized */ - const std::array _chip_select; - - /** - * We will need this for both models of the IC - * This determines where we get our signals from on the Arduino - * It can only be 9 or 10 - * NOTE: needs to be initialized - */ - const std::array _chip_select_per_chip; + const ChipSelectConfig_t _chip_select_config; - /** - * We will only end up using the address if this is a LTC6811-2 - * NOTE: But if we are, we need to call a setup function to instatiate each with the correct addresses - * EX) BMS Segments 1, 4, and 5 are on chip select 9 - * BMS Segments 2, 3, and 6 are on chip select 10 - * Those segments correspond to 2 ICs each, so the instance with chip_select 9 - * Will have IC addresses: 0,1,6,7,8,9 | The rest are for chip_select 10 - */ - const std::array _address; // constant + /** * REPLACING SEPARATE CONFIGURATION FILE @@ -479,11 +463,11 @@ class BMSDriverGroup * We only use 12 bits to represent a 1 (discharge) or 0 (charge) * out of the 16 bits */ - std::array _cell_discharge_en = {}; // not const + std::array _cell_discharge_en = {}; // not const }; -template -using BMSDriverInstance = etl::singleton>; +template +using BMSDriverInstance = etl::singleton>; #include diff --git a/lib/interfaces/include/BMSDriverGroup.tpp b/lib/interfaces/include/BMSDriverGroup.tpp index 13441b43..37bdd45a 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -7,10 +7,8 @@ #include #include -template -BMSDriverGroup::BMSDriverGroup(const std::array& cs, - const std::array& cs_per_chip, - const std::array& addr, +template +BMSDriverGroup::BMSDriverGroup(const ChipSelectConfig_t& chip_select_config, const BMSDriverGroupConfig_s default_params = { .device_refup_mode = bms_driver_defaults::DEVICE_REFUP_MODE, .adcopt = bms_driver_defaults::ADCOPT, @@ -30,22 +28,18 @@ BMSDriverGroup -void BMSDriverGroup::init() +template +void BMSDriverGroup::init() { // We initialized the pec table during beginning of runtime which allows _pec15table to be const -> no need to call in init() - for (size_t i = 0; i < num_chip_selects; i++) + for (const ChipSelect_t& cs : _chip_select_config.chip_selects) { - int cs = _chip_select[i]; - // chip select defines - pinMode(cs, OUTPUT); - digitalWrite(cs, HIGH); + pinMode(cs.cs_pin, OUTPUT); + digitalWrite(cs.cs_pin, HIGH); } _bms_data.voltages.fill(0); _bms_data.cell_temperatures.fill(0); @@ -54,34 +48,34 @@ void BMSDriverGroup -void BMSDriverGroup::_start_wakeup_protocol() +template +void BMSDriverGroup::_start_wakeup_protocol() { - for (size_t cs = 0; cs < num_chip_selects; cs++) + for (const ChipSelect_t& chip_select : _chip_select_config.chip_selects) { - _start_wakeup_protocol(cs); + _start_wakeup_protocol(chip_select.cs_pin); } } -template -void BMSDriverGroup::_start_wakeup_protocol(size_t cs) +template +void BMSDriverGroup::_start_wakeup_protocol(size_t cs_pin) { if constexpr (chip_type == LTC6811_Type_e::LTC6811_1) { - ltc_spi_interface::_write_and_delay_low(_chip_select[cs], 400); + ltc_spi_interface::_write_and_delay_low(cs_pin, 400); SPI.transfer16(0); - ltc_spi_interface::_write_and_delay_high(_chip_select[cs], 400); + ltc_spi_interface::_write_and_delay_high(cs_pin, 400); } else { - ltc_spi_interface::_write_and_delay_low(_chip_select[cs], 400); + ltc_spi_interface::_write_and_delay_low(cs_pin, 400); SPI.transfer(0); - ltc_spi_interface::_write_and_delay_high(_chip_select[cs], 400); // t_wake is 400 microseconds; wait that long to ensure device has turned on. + ltc_spi_interface::_write_and_delay_high(cs_pin, 400); // t_wake is 400 microseconds; wait that long to ensure device has turned on. } } -template -constexpr std::array BMSDriverGroup::_initialize_Pec_Table() +template +constexpr std::array BMSDriverGroup::_initialize_Pec_Table() { std::array temp{}; // Logic to fill temp @@ -107,8 +101,8 @@ constexpr std::array BMSDriverGroup -BMSCoreData_s BMSDriverGroup::get_bms_core_data() +template +BMSCoreData_s BMSDriverGroup::get_bms_core_data() { BMSCoreData_s out{}; @@ -125,18 +119,18 @@ BMSCoreData_s BMSDriverGroup -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::get_bms_data() +template +typename BMSDriverGroup::BMSDriverData_t +BMSDriverGroup::get_bms_data() { return _bms_data; } -template -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::read_data() +template +typename BMSDriverGroup::BMSDriverData_t +BMSDriverGroup::read_data() { - BMSDriverData bms_data; + BMSDriverData_t bms_data; if constexpr (chip_type == LTC6811_Type_e::LTC6811_1) { bms_data = _read_data_through_broadcast(); @@ -159,105 +153,88 @@ BMSDriverGroup -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::_read_data_through_broadcast() + +template +typename BMSDriverGroup::BMSDriverData_t +BMSDriverGroup::_read_data_through_broadcast() { - constexpr size_t data_size = _total_packet_size_bytes * (num_chips / num_chip_selects); - for (size_t cs = 0; cs < num_chip_selects; cs++) + + constexpr size_t chip_select_packet_size = _total_packet_size_bytes * num_chips_per_chip_select; + size_t chip_start_voltage_cell_index = 0; + size_t chip_start_temperature_cell_index = 0; + size_t chip_start_board_temperature_index = 0; + for (size_t chip_select_index = 0; chip_select_index < num_chip_selects; chip_select_index++) { + const ChipSelect_t& chip_select = _chip_select_config.chip_selects[chip_select_index]; + write_configuration(_config.dcto_read, _cell_discharge_en); std::array cmd_pec; - std::array spi_data; + std::array spi_data; // Get buffers for each group we care about, all at once for ONE chip select line - _start_wakeup_protocol(cs); + _start_wakeup_protocol(chip_select.cs_pin); cmd_pec = _generate_CMD_PEC(_read_group_to_cmd[_current_read_group], -1); // The address should never be used here - spi_data = ltc_spi_interface::read_registers_command(_chip_select[cs], cmd_pec); + spi_data = ltc_spi_interface::read_registers_command(chip_select.cs_pin, cmd_pec); - for (size_t chip = 0; chip < num_chips / num_chip_selects; chip++) { - size_t chip_index = chip + (cs * (num_chips / num_chip_selects)); - - // relevant for cell voltage reading - int cells_per_chip = (chip_index % 2 == 0) ? 12 : 9; // Even indexed ICs have 12 cells, odd have 9 + for (size_t chip_index = 0; chip_index < num_chips_per_chip_select; chip_index++) { + Chip_t chip = chip_select.chips[chip_index]; + size_t global_chip_index = _chip_select_config.global_chip_index(chip_select_index, chip_index); uint8_t start_index; - std::array spi_response; + std::array spi_response; //relevant for GPIO reading bool current_group_valid = false; - switch(_current_read_group) { - case ReadGroup_e::CV_GROUP_A: - current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); - _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_A)] = current_group_valid; - start_index = 0; - break; - case ReadGroup_e::CV_GROUP_B: - current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); - _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_B)] = current_group_valid; - start_index = 3; - break; - case ReadGroup_e::CV_GROUP_C: - current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); - _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_C)] = current_group_valid; - start_index = 6; - break; - case ReadGroup_e::CV_GROUP_D: - current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); - _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::CV_GROUP_D)] = current_group_valid; - start_index = 9; - break; - case ReadGroup_e::AUX_GROUP_A: - current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); - _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::AUX_GROUP_A)] = current_group_valid; - start_index = 0; - break; - case ReadGroup_e::AUX_GROUP_B: - current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip); - _bms_data.valid_read_packets[chip_index][static_cast(ReadGroup_e::AUX_GROUP_B)] = current_group_valid; - start_index = 3; - break; - default: - // NUM_CURRENT_GROUPS is a sentinel value and should never be reached - __builtin_unreachable(); - } + current_group_valid = _check_if_valid_packet(spi_data, _total_packet_size_bytes * chip_index); + _bms_data.valid_read_packets[chip_index][static_cast(_current_read_group)] = current_group_valid; // Skip processing if current group packet is invalid and skip cells 9-12 for group D cuz they don't exist - if (!current_group_valid || (_current_read_group == ReadGroup_e::CV_GROUP_D && cells_per_chip == 9)) { + + size_t chip_packet_num_values = chip.read_map.get_num_values_in_group(_current_read_group); + size_t chip_packet_size_byte = _packet_data_size_bytes * chip_packet_num_values; + + // Skip processing if current group packet is invalid and updates indexes accordingly + if (!current_group_valid) { continue; } - if (_current_read_group == ReadGroup_e::AUX_GROUP_B) { - std::copy_n(spi_data.begin() + (_total_packet_size_bytes * chip), 4, spi_response.begin()); - std::fill(spi_response.begin() + 4, spi_response.end(), 0); // padding to make it 6 bytes - } else { - std::copy_n(spi_data.begin() + (_total_packet_size_bytes * chip), 6, spi_response.begin()); - } - size_t num_values = _data_size_bytes / size_of_packet_value_bytes; + + std::copy_n(spi_data.begin() + (_total_packet_size_bytes * chip_index), chip_packet_size_byte, spi_response.begin()); + std::fill(spi_response.begin() + chip_packet_size_byte, spi_response.end(), 0); // padding + std::array value_buffer; - - if (_current_read_group <= ReadGroup_e::CV_GROUP_D) { - for (size_t i = 0; i < num_values; i++) { - std::copy_n(spi_response.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); - _load_cell_voltages(_bms_data, _max_min_reference, value_buffer, chip_index, start_index + i); - } - } else { - for (size_t i = 0; i < num_values; i++) { - std::copy_n(spi_response.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); - _load_auxillaries(_bms_data, _max_min_reference, value_buffer, chip_index, start_index + i); + size_t start_voltage_index = chip_start_voltage_cell_index + chip.read_map.get_group_start_cell_voltage_index(_current_read_group); + size_t start_temperature_index = chip_start_temperature_cell_index + chip.read_map.get_group_start_cell_temperature_index(_current_read_group); + size_t start_board_temperature_index = chip_start_board_temperature_index + chip.read_map.get_group_start_board_temperature_index(_current_read_group); + auto read_group_data_types = chip.read_map.group_data_types[_current_read_group]; + for (size_t i = 0; i < chip_packet_num_values; i++) { + std::copy_n(spi_response.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); + switch (read_group_data_types[i]){ + case CELL_VOLTAGE: + _load_cell_voltages(_bms_data, _max_min_reference, value_buffer, start_voltage_index++); + break; + case CELL_TEMPERATURE: + _load_cell_temps(_bms_data, _max_min_reference, value_buffer, start_temperature_index++); + break; + case BOARD_TEMPERATURE: + _load_board_temps(_bms_data, _max_min_reference, value_buffer, start_board_temperature_index++); + break; } } + chip_start_voltage_cell_index += chip.read_map.get_num_cell_voltages(); + chip_start_temperature_cell_index += chip.read_map.get_num_cell_temps(); + chip_start_board_temperature_index += chip.read_map.get_num_board_temps(); } } _bms_data.min_cell_voltage = _max_min_reference.min_cell_voltage; _bms_data.max_cell_voltage = _max_min_reference.max_cell_voltage; _bms_data.total_voltage = _max_min_reference.total_voltage; - _bms_data.avg_cell_voltage = _bms_data.total_voltage / num_cells; + _bms_data.avg_cell_voltage = _bms_data.total_voltage / num_voltage_cells; - _bms_data.average_cell_temperature = _max_min_reference.total_thermistor_temps / (4 * num_chips); + _bms_data.average_cell_temperature = _max_min_reference.total_thermistor_temps / num_temp_cells; _bms_data.max_cell_temp = _max_min_reference.max_cell_temp; _bms_data.min_cell_temp = _max_min_reference.min_cell_temp; @@ -267,113 +244,99 @@ BMSDriverGroup -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::_read_data_through_address() +template +typename BMSDriverGroup::BMSDriverData_t +BMSDriverGroup::_read_data_through_address() { ReferenceMaxMin_s max_min_reference; std::array clean_valid_packet_data = {true}; // should be all reset to true _bms_data.valid_read_packets.fill(clean_valid_packet_data); // reset - std::array data_in_cell_voltages_1_to_12; - std::array data_in_auxillaries_1_to_5; + // std::array data_in_cell_voltages_1_to_12; + std::array chip_data; + // std::array data_in_auxillaries_1_to_5; std::array cmd_pec; size_t battery_cell_count = 0; size_t gpio_count = 0; - for (size_t chip = 0; chip < num_chips; chip++) - { - _start_wakeup_protocol(); - - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, chip); - auto data_in_3_cell_voltages = ltc_spi_interface::read_registers_command<8>(_chip_select_per_chip[chip], cmd_pec); - std::copy(data_in_3_cell_voltages.begin(), data_in_3_cell_voltages.begin() + 6, data_in_cell_voltages_1_to_12.begin()); - - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, chip); - data_in_3_cell_voltages = ltc_spi_interface::read_registers_command<8>(_chip_select_per_chip[chip], cmd_pec); - std::copy(data_in_3_cell_voltages.begin(), data_in_3_cell_voltages.begin() + 6, data_in_cell_voltages_1_to_12.begin() + 6); - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_C, chip); - data_in_3_cell_voltages = ltc_spi_interface::read_registers_command<8>(_chip_select_per_chip[chip], cmd_pec); - std::copy(data_in_3_cell_voltages.begin(), data_in_3_cell_voltages.begin() + 6, data_in_cell_voltages_1_to_12.begin() + 12); - - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_D, chip); - data_in_3_cell_voltages = ltc_spi_interface::read_registers_command<8>(_chip_select_per_chip[chip], cmd_pec); - std::copy(data_in_3_cell_voltages.begin(), data_in_3_cell_voltages.begin() + 6, data_in_cell_voltages_1_to_12.begin() + 18); - - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, chip); - auto data_in_3_auxillaries = ltc_spi_interface::read_registers_command<8>(_chip_select_per_chip[chip], cmd_pec); - std::copy(data_in_3_auxillaries.begin(), data_in_3_auxillaries.begin() + 6, data_in_auxillaries_1_to_5.begin()); - - cmd_pec = _generate_CMD_PEC(CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B, chip); - data_in_3_auxillaries = ltc_spi_interface::read_registers_command<8>(_chip_select_per_chip[chip], cmd_pec); - std::copy(data_in_3_auxillaries.begin(), data_in_3_auxillaries.begin() + 4, data_in_auxillaries_1_to_5.begin() + 6); - - // DEBUG: Check to see that the PEC is what we expect it to be - - size_t num_values = _data_size_bytes / size_of_packet_value_bytes; - std::array value_buffer; - - for (size_t i = 0; i < 4*num_values; i++) { - std::copy_n(data_in_cell_voltages_1_to_12.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); - _load_cell_voltages(_bms_data, max_min_reference, value_buffer, chip, i); - } - for (size_t i = 0; i < 2*num_values; i++) { - std::copy_n(data_in_auxillaries_1_to_5.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); - _load_auxillaries(_bms_data, max_min_reference, value_buffer, chip, gpio_count); + size_t start_cell_voltage_index = 0; + size_t start_cell_temp_index = 0; + size_t start_board_temp_index = 0; + size_t chip_data_index = 0; + std::array buffer; + std::array value_buffer; + for (const ChipSelect_t& chip_select : _chip_select_config.chip_selects){ + _start_wakeup_protocol(chip_select.cs_pin); + for (const Chip_t& chip : chip_select.chips){ + size_t chip_packet_num_values = chip.read_map.get_num_values_in_each_group(_current_read_group); + size_t chip_packet_size_byte = _packet_data_size_bytes * chip_packet_num_values; + + for (size_t group = 0; group < ReadGroup_e::NUM_GROUPS; group ++){ + cmd_pec = _generate_CMD_PEC(_read_group_to_cmd[group], chip); + buffer = ltc_spi_interface::read_registers_command<_total_packet_size_bytes>(chip_select.cs_pin, cmd_pec); + auto read_group_data_types = chip.read_map.group_data_types[group]; + for (size_t i = 0; i < chip_packet_num_values; i++){ + std::copy_n(buffer.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); + switch (read_group_data_types[i]){ + case CELL_VOLTAGE: + _load_cell_voltages(_bms_data, _max_min_reference, value_buffer, start_cell_voltage_index++); + break; + case CELL_TEMPERATURE: + _load_cell_temps(_bms_data, _max_min_reference, value_buffer, start_cell_temp_index++); + break; + case BOARD_TEMPERATURE: + _load_board_temps(_bms_data, _max_min_reference, value_buffer, start_board_temp_index++); + break; + } + } + } } } + //Because increments everytime cell is read and all of them are read + size_t total_num_voltage_cells = start_cell_voltage_index; + size_t total_num_temp_cells = start_cell_temp_index; + _bms_data.min_cell_voltage = max_min_reference.min_cell_voltage; _bms_data.max_cell_voltage = max_min_reference.max_cell_voltage; _bms_data.total_voltage = max_min_reference.total_voltage; - _bms_data.avg_cell_voltage = _bms_data.total_voltage / num_cells; + _bms_data.avg_cell_voltage = _bms_data.total_voltage / total_num_voltage_cells; - // Avoid divide by zero - skip calculation if no GPIOs were read - if (gpio_count > 0) { - _bms_data.average_cell_temperature = max_min_reference.total_thermistor_temps / gpio_count; - } + _bms_data.average_cell_temperature = max_min_reference.total_thermistor_temps / total_num_temp_cells; _bms_data.max_cell_temp = _bms_data.cell_temperatures[_bms_data.max_cell_temperature_cell_id]; _bms_data.max_board_temp = _bms_data.board_temperatures[_bms_data.max_board_temperature_segment_id]; + return _bms_data; } -template -void BMSDriverGroup::_load_cell_voltages(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, - uint8_t chip_index, uint8_t start_cell_index) +template +void BMSDriverGroup::_load_cell_voltages(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_cell_voltage, uint8_t cell_index) { - - uint8_t cell_global_offset = (chip_index / 2) * 21 + (chip_index % 2) * 12; - - // for (int cell_Index = start_cell_index; cell_Index < start_cell_index+3; cell_Index++) - // { - // std::copy_n(data_in_cv_group.begin() + (cell_Index - start_cell_index) * 2, 2, data_in_cell_voltage.begin()); - uint16_t voltage_in = data_in_cell_voltage[1] << 8 | data_in_cell_voltage[0]; float voltage_converted = voltage_in * _config.cv_adc_lsb_voltage; - uint8_t cell_voltage_index = cell_global_offset + start_cell_index; - // Calculate the correct global voltage array index - _store_voltage_data(bms_data, max_min_ref, voltage_converted, cell_voltage_index); - // } + _store_voltage_data(bms_data, max_min_ref, voltage_converted, cell_index); +} + +template +void BMSDriverGroup::_load_cell_temps(BMSDriverData_t& bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, + uint8_t cell_index) +{ + uint16_t temp_in = data_in_temp[1] << 8 | data_in_temp[0]; + _store_cell_temperature_data(bms_data, max_min_ref, temp_in, cell_index); } -template -void BMSDriverGroup::_load_auxillaries(BMSDriverData& bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, - uint8_t chip_index, uint8_t start_gpio_index) +template +void BMSDriverGroup::_load_board_temps(BMSDriverData_t& bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_temp, + uint8_t cell_index) { - // for (int gpio_index = start_gpio_index; gpio_index < start_gpio_index + 3 && gpio_index < 5; gpio_index++) // There are only five Auxillary ports - // { - // std::array data_in_gpio_voltage; - // std::copy_n(data_in_gpio_group.begin() + (gpio_index - start_gpio_index) * 2, 2, data_in_gpio_voltage.begin()); - - uint16_t gpio_in = data_in_temp[1] << 8 | data_in_temp[0]; - _store_temperature_humidity_data(bms_data, max_min_ref, gpio_in, start_gpio_index, chip_index); - // } + uint16_t temp_in = data_in_temp[1] << 8 | data_in_temp[0]; + _store_board_temperature_data(bms_data, max_min_ref, temp_in, cell_index); } -template -void BMSDriverGroup::_store_voltage_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, volt voltage_in, uint8_t cell_index) +template +void BMSDriverGroup::_store_voltage_data(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_reference, volt voltage_in, uint8_t cell_index) { max_min_reference.total_voltage -= bms_data.voltages[cell_index]; bms_data.voltages[cell_index] = voltage_in; @@ -391,72 +354,71 @@ void BMSDriverGroup -void BMSDriverGroup::_store_temperature_humidity_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, const uint16_t &gpio_in, uint8_t gpio_index, uint8_t chip_index) +template +void BMSDriverGroup::_store_cell_temperature_data(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_reference, const uint16_t &temp_in, uint8_t cell_index) { - // there is 8 cell temperatures per chip, and 2 board temperatures per board, so 4+1 per chip - if (gpio_index < 4) // These are all thermistors [0,1,2,3]. - { - // Calculate the cell temperature index: 4 thermistors per chip - uint8_t cell_temp_index = chip_index * 4 + gpio_index; - max_min_reference.total_thermistor_temps -= bms_data.cell_temperatures[cell_temp_index]; - float thermistor_resistance = (2740 / (gpio_in / 50000.0)) - 2740; - bms_data.cell_temperatures[cell_temp_index] = 1 / ((1 / 298.15) + (1 / 3984.0) * std::log(thermistor_resistance / 10000.0)) - 272.15; // calculation for thermistor temperature in C - max_min_reference.total_thermistor_temps += bms_data.cell_temperatures[cell_temp_index]; + max_min_reference.total_thermistor_temps -= bms_data.cell_temperatures[cell_index]; + float thermistor_resistance = (2740 / (temp_in / 50000.0)) - 2740; + bms_data.cell_temperatures[cell_index] = 1 / ((1 / 298.15) + (1 / 3984.0) * std::log(thermistor_resistance / 10000.0)) - 272.15; // calculation for thermistor temperature in C + max_min_reference.total_thermistor_temps += bms_data.cell_temperatures[cell_index]; - if (bms_data.cell_temperatures[cell_temp_index] > max_min_reference.max_cell_temp) - { - max_min_reference.max_cell_temp = bms_data.cell_temperatures[cell_temp_index]; - bms_data.max_cell_temperature_cell_id = cell_temp_index; - } - if (bms_data.cell_temperatures[cell_temp_index] < max_min_reference.min_cell_temp) - { - max_min_reference.min_cell_temp = bms_data.cell_temperatures[cell_temp_index]; - bms_data.min_cell_temperature_cell_id = cell_temp_index; - } + if (bms_data.cell_temperatures[cell_index] > max_min_reference.max_cell_temp) + { + max_min_reference.max_cell_temp = bms_data.cell_temperatures[cell_index]; + bms_data.max_cell_temperature_cell_id = cell_index; } - else // this is apparently the case for temperature sensor for the BOARD, not the cells. There is 2 per segment + if (bms_data.cell_temperatures[cell_index] < max_min_reference.min_cell_temp) { + max_min_reference.min_cell_temp = bms_data.cell_temperatures[cell_index]; + bms_data.min_cell_temperature_cell_id = cell_index; + } +} +template +void BMSDriverGroup::_store_board_temperature_data(BMSDriverData_t &bms_data, ReferenceMaxMin_s &max_min_reference, const uint16_t &temp_in, uint8_t board_index) +{ constexpr float mcp_9701_temperature_coefficient = 0.0195f; constexpr float mcp_9701_output_v_at_0c = 0.4f; - bms_data.board_temperatures[chip_index] = ((gpio_in / 10000.0f) - mcp_9701_output_v_at_0c) / mcp_9701_temperature_coefficient; // 2 per board = 1 per chip, calculation for bord temps - if (bms_data.board_temperatures[chip_index] > max_min_reference.max_board_temp) + bms_data.board_temperatures[board_index] = ((temp_in / 10000.0f) - mcp_9701_output_v_at_0c) / mcp_9701_temperature_coefficient; // 2 per board = 1 per chip, calculation for bord temps + if (bms_data.board_temperatures[board_index] > max_min_reference.max_board_temp) { - max_min_reference.max_board_temp = bms_data.board_temperatures[chip_index]; + max_min_reference.max_board_temp = bms_data.board_temperatures[board_index]; - bms_data.max_board_temperature_segment_id = chip_index; // Because each segment only has 1 humidity and 1 board temp sensor + bms_data.max_board_temperature_segment_id = board_index; // Because each segment only has 1 humidity and 1 board temp sensor } - } } /* -------------------- WRITING DATA FUNCTIONS -------------------- */ -template -void BMSDriverGroup::write_configuration(const std::array &cell_balance_statuses) +template +void BMSDriverGroup::write_configuration(const bool* cell_balance_statuses, size_t cell_balance_statuses_size) { - std::array cb; + std::array cb; size_t global_cell_index = 0; - for (size_t chip = 0; chip < num_chips; chip++) - { - uint16_t chip_cb = 0; - size_t cells_per_chip = (chip % 2 == 0) ? 12 : 9; - for (size_t cell_i = 0; cell_i < cells_per_chip; cell_i++) - { - if (cell_balance_statuses[global_cell_index]) + for (size_t chip_select_index = 0; chip_select_index < num_chip_selects; chip_select_index++){ + ChipSelect_t chip_select = _chip_select_config.chip_selects[chip_select_index]; + for (size_t chip_index = 0; chip_index < num_chips_per_chip_select; chip_index++){ + Chip_t chip = chip_select.chips[chip_index]; + uint16_t chip_cb = 0; + size_t cells_per_chip = chip.read_map.get_num_cell_voltages(); + for (size_t cell_i = 0; cell_i < cells_per_chip; cell_i++) { - chip_cb = (0b1 << cell_i) | chip_cb; + if (cell_balance_statuses[global_cell_index]) + { + chip_cb = (0b1 << cell_i) | chip_cb; + } + global_cell_index++; + } + if (cell_balance_statuses_size > _chip_select_config.global_chip_index(chip_select_index, chip_index)){ //Redudanancy + cb[_chip_select_config.global_chip_index(chip_select_index, chip_index)] = chip_cb; } - global_cell_index++; } - cb[chip] = chip_cb; } - write_configuration(_config.dcto_write, cb); } -template -void BMSDriverGroup::write_configuration(uint8_t dcto_mode, const std::array &cell_balance_statuses) +template +void BMSDriverGroup::write_configuration(uint8_t dcto_mode, const std::array &cell_balance_statuses) { std::copy(cell_balance_statuses.begin(), cell_balance_statuses.end(), _cell_discharge_en.begin()); @@ -478,37 +440,33 @@ void BMSDriverGroup -void BMSDriverGroup::_write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses) +template +void BMSDriverGroup::_write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses) { - constexpr size_t data_size = _total_packet_size_bytes * (num_chips / num_chip_selects); + constexpr size_t data_size = _total_packet_size_bytes * num_chips_per_chip_select; std::array cmd_and_pec = _generate_CMD_PEC(CMD_CODES_e::WRITE_CONFIG, -1); std::array full_buffer; std::array temp_pec; // Needs to be sent on each chip select line - for (size_t cs = 0; cs < num_chip_selects; cs++) + for (size_t chip_select_index = 0; chip_select_index < num_chip_selects; chip_select_index++) { - size_t j = 0; - for (int i = num_chips - 1; i >= 0; i--) // This needs to be flipped because when writing a command, primary device holds the last bytes - { // Find chips with the same CS - if (_chip_select_per_chip[i] == _chip_select[cs]) // This could be an optimization: && j < (num_chips + 1) / 2) - { - buffer_format[4] = ((cell_balance_statuses[i] & 0x0FF)); - buffer_format[5] = ((dcto_mode & 0x0F) << 4) | ((cell_balance_statuses[i] & 0xF00) >> 8); - temp_pec = _calculate_specific_PEC(buffer_format.data(), 6); - std::copy_n(buffer_format.begin(), 6, full_buffer.data() + (j * 8)); - std::copy_n(temp_pec.begin(), 2, full_buffer.data() + 6 + (j * 8)); - j++; - } + for (size_t chip_index = num_chips_per_chip_select - 1; chip_index >= 0; chip_index--) // This needs to be flipped because when writing a command, primary device holds the last bytes + { + size_t global_chip_index = _chip_select_config.global_chip_index(chip_select_index, chip_index); + buffer_format[4] = ((cell_balance_statuses[global_chip_index] & 0x0FF)); + buffer_format[5] = ((dcto_mode & 0x0F) << 4) | ((cell_balance_statuses[global_chip_index] & 0xF00) >> 8); + temp_pec = _calculate_specific_PEC(buffer_format.data(), _packet_data_size_bytes); + std::copy_n(buffer_format.begin(), _packet_data_size_bytes, full_buffer.data() + (chip_select_index * _total_packet_size_bytes)); + std::copy_n(temp_pec.begin(), _packet_pec_size_bytes, full_buffer.data() + _packet_data_size_bytes + (chip_select_index * _total_packet_size_bytes)); } - ltc_spi_interface::write_registers_command(_chip_select[cs], cmd_and_pec, full_buffer); + ltc_spi_interface::write_registers_command(_chip_select_config.chip_selects[chip_select_index].cs_pin, cmd_and_pec, full_buffer); } } /* UNUSED: LTC6811-2 ADDRESS MODE - REFERENCE ONLY -template -void BMSDriverGroup::_write_config_through_address(uint8_t dcto_mode, const std::array& buffer_format, const std::array &cell_balance_statuses) +template +void BMSDriverGroup::_write_config_through_address(uint8_t dcto_mode, const std::array& buffer_format, const std::array &cell_balance_statuses) { // Need to manipulate the command code to have address, therefore have to send command num_chips times std::array cmd_and_pec; @@ -527,8 +485,8 @@ void BMSDriverGroup -void BMSDriverGroup::_start_cell_voltage_ADC_conversion() +template +void BMSDriverGroup::_start_cell_voltage_ADC_conversion() { uint16_t adc_cmd = (uint16_t)CMD_CODES_e::START_CV_ADC_CONVERSION | (_config.adc_mode_cv_conversion << 7) | (_config.discharge_permitted << 4) | static_cast(_config.adc_conversion_cell_select_mode); std::array cmd; @@ -544,8 +502,8 @@ void BMSDriverGroup -void BMSDriverGroup::_start_GPIO_ADC_conversion() +template +void BMSDriverGroup::_start_GPIO_ADC_conversion() { uint16_t adc_cmd = (uint16_t)CMD_CODES_e::START_GPIO_ADC_CONVERSION | (_config.adc_mode_gpio_conversion << 7); // | static_cast(_config.adc_conversion_gpio_select_mode); std::array cmd; @@ -562,8 +520,8 @@ void BMSDriverGroup -void BMSDriverGroup::_start_ADC_conversion_through_broadcast(const std::array &cmd_code) +template +void BMSDriverGroup::_start_ADC_conversion_through_broadcast(const std::array &cmd_code) { // Leave the command code as is std::array cc = {cmd_code[0], cmd_code[1]}; @@ -573,15 +531,15 @@ void BMSDriverGroup -void BMSDriverGroup::_start_ADC_conversion_through_address(const std::array& cmd_code) +template +void BMSDriverGroup::_start_ADC_conversion_through_address(const std::array& cmd_code) { // Need to manipulate the command code to have address, therefore have to send command num_chips times for (size_t i = 0; i < num_chips; i++) @@ -599,8 +557,8 @@ void BMSDriverGroup -std::array BMSDriverGroup::_calculate_specific_PEC(const uint8_t *data, int length) +template +std::array BMSDriverGroup::_calculate_specific_PEC(const uint8_t *data, int length) { std::array pec; uint16_t remainder; @@ -617,8 +575,8 @@ std::array BMSDriverGroup -std::array BMSDriverGroup::_generate_formatted_CMD(CMD_CODES_e command, int ic_index) +template +std::array BMSDriverGroup::_generate_formatted_CMD(CMD_CODES_e command, size_t chip_addr) { std::array cmd; const uint16_t cmd_val = static_cast(command); @@ -630,17 +588,17 @@ std::array BMSDriverGroup(_get_cmd_address(_address[ic_index]) | (cmd_val >> 8)); + cmd[0] = static_cast(_get_cmd_address(chip_addr) | (cmd_val >> 8)); cmd[1] = static_cast(cmd_val); } return cmd; } -template -std::array BMSDriverGroup::_generate_CMD_PEC(CMD_CODES_e command, int ic_index) +template +std::array BMSDriverGroup::_generate_CMD_PEC(CMD_CODES_e command, size_t chip_addr) { std::array cmd_pec; - std::array cmd = _generate_formatted_CMD(command, ic_index); + std::array cmd = _generate_formatted_CMD(command, chip_addr); std::array pec = _calculate_specific_PEC(cmd.data(), 2); std::copy_n(cmd.data(), 2, cmd_pec.data()); // Copy first two bytes (cmd) std::copy_n(pec.data(), 2, cmd_pec.data() + 2); // Copy next two bytes (pec) @@ -649,8 +607,8 @@ std::array BMSDriverGroup -bool BMSDriverGroup::_check_if_valid_packet(const std::array &data, size_t param_iterator) +template +bool BMSDriverGroup::_check_if_valid_packet(const std::array &data, size_t param_iterator) { std::array sample_packet; std::array sample_pec; @@ -663,8 +621,8 @@ bool BMSDriverGroup -const char* BMSDriverGroup::get_current_read_group_name() +template +const char* BMSDriverGroup::get_current_read_group_name() { switch (_current_read_group) { case ReadGroup_e::CV_GROUP_A: @@ -684,11 +642,11 @@ const char* BMSDriverGroup -bool BMSDriverGroup::last_read_all_valid() +template +bool BMSDriverGroup::last_read_all_valid() { // Check validity for the specific group that was just read (current state before advancing) - for (size_t chip = 0; chip < num_chips; chip++) { + for (size_t chip = 0; chip < num_chip_selects * num_chips_per_chip_select; chip++) { const auto& validity = _bms_data.valid_read_packets[chip]; switch (_current_read_group) { @@ -718,13 +676,13 @@ bool BMSDriverGroup -size_t BMSDriverGroup::count_invalid_packets() +template +size_t BMSDriverGroup::count_invalid_packets() { size_t invalid_count = 0; // Count invalidity for the specific group that was just read - for (size_t chip = 0; chip < num_chips; chip++) { + for (size_t chip = 0; chip < num_chip_selects * num_chips_per_chip_select; chip++) { const auto& validity = _bms_data.valid_read_packets[chip]; switch (_current_read_group) { diff --git a/lib/shared_types/shared_types.h b/lib/shared_types/shared_types.h index 8eb3a6d7..0189ab37 100644 --- a/lib/shared_types/shared_types.h +++ b/lib/shared_types/shared_types.h @@ -63,123 +63,184 @@ enum ReadGroup_e { AUX_GROUP_A, AUX_GROUP_B, NUM_GROUPS }; -enum ReadDataResultType_e { CELL_VOLTAGE, CELL_TEMPERATURE, BOARD_TEMPERATURE, NO_DATA }; +enum ReadDataResultType_e { CELL_VOLTAGE, CELL_TEMPERATURE, BOARD_TEMPERATURE, NUM_DATA_TYPES, NO_DATA }; -// ----- leaf: per-chip group map (immutable) ----- template -struct ReadGroupResultMap { - static constexpr std::size_t kNumGroups = ReadGroup_e::NUM_GROUPS; - - const std::array group_values; - const std::array, kNumGroups> group_data_types; - - // small helper - constexpr std::size_t data_per_group() const noexcept { return DATA_PER_GROUP; } - constexpr std::size_t num_groups() const noexcept { return kNumGroups; } -}; - -// ----- chip (immutable) ----- -template -struct Chips { - const std::size_t addr_pin; - const ReadGroupResultMap read_map; -}; - -// ----- chip-select (immutable) ----- -template -struct ChipSelect { - const std::size_t cs_pin; - const std::array, NUM_CHIPS_PER_CS> chips; - - constexpr std::size_t num_chips() const noexcept { return NUM_CHIPS_PER_CS; } -}; - -// ----- full config (immutable) + constexpr derived views ----- -template -struct ChipSelectConfig { - const std::array, NUM_CS> chip_selects; - - // Compile-time sizes - static constexpr std::size_t kNumChipSelects = NUM_CS; - static constexpr std::size_t kNumChipsPerCS = NUM_CHIPS_PER_CS; - static constexpr std::size_t kDataPerGroup = DATA_PER_GROUP; - static constexpr std::size_t kTotalChips = NUM_CS * NUM_CHIPS_PER_CS; - - // ---- Derived per-chip counts (voltage/temp/board), all constexpr ---- - constexpr std::array voltage_cells_per_chip() const { - std::array out{}; // zero-inited - for (std::size_t cs = 0; cs < kNumChipSelects; ++cs) { - const auto& sel = chip_selects[cs]; - for (std::size_t c = 0; c < kNumChipsPerCS; ++c) { - const auto& chip = sel.chips[c]; - const std::size_t flat = cs * kNumChipsPerCS + c; - for (std::size_t g = 0; g < chip.read_map.num_groups(); ++g) { - if (!chip.read_map.is_group_on[g]) continue; - for (auto kind : chip.read_map.group_data_types[g]) { - if (kind == CELL_VOLTAGE) { ++out[flat]; } - } +class ReadGroupResultMap { +public: + const std::array, NUM_GROUPS> group_data_types; + + // constexpr ctor so the object can be constexpr if inputs are constexpr + constexpr explicit ReadGroupResultMap(const std::array, NUM_GROUPS>& gdt) + : group_data_types(gdt) + , num_values_in_each_group(make_per_group_counts(gdt)) + , num_data_type_counts(count_type(gdt)) + {} + + constexpr std::size_t get_num_values_in_group(ReadGroup_e group) const { + return num_values_in_each_group[static_cast(group)]; + } + constexpr std::size_t get_num_cell_voltages() const { return num_data_type_counts[CELL_VOLTAGE]; } + constexpr std::size_t get_num_cell_temps() const { return num_data_type_counts[CELL_TEMPERATURE]; } + constexpr std::size_t get_num_board_temps() const { return num_data_type_counts[BOARD_TEMPERATURE]; } + constexpr std::size_t get_group_start_cell_voltage_index(ReadGroup_e group){ + std::size_t index = 0; + for (std::size_t g = 0; g < static_cast(group); ++g) { + for (std::size_t k = 0; k < DATA_PER_GROUP; ++k) { + if (group_data_types[g][k] == CELL_VOLTAGE) { + ++index; } } } - return out; + return index; } - - constexpr std::array temp_cells_per_chip() const { - std::array out{}; - for (std::size_t cs = 0; cs < kNumChipSelects; ++cs) { - const auto& sel = chip_selects[cs]; - for (std::size_t c = 0; c < kNumChipsPerCS; ++c) { - const auto& chip = sel.chips[c]; - const std::size_t flat = cs * kNumChipsPerCS + c; - for (std::size_t g = 0; g < chip.read_map.num_groups(); ++g) { - if (!chip.read_map.is_group_on[g]) continue; - for (auto kind : chip.read_map.group_data_types[g]) { - if (kind == CELL_TEMPERATURE) { ++out[flat]; } - } + constexpr std::size_t get_group_start_cell_temperature_index(ReadGroup_e group){ + std::size_t index = 0; + for (std::size_t g = 0; g < static_cast(group); ++g) { + for (std::size_t k = 0; k < DATA_PER_GROUP; ++k) { + if (group_data_types[g][k] == CELL_TEMPERATURE) { + ++index; } } } - return out; + return index; } - - constexpr std::array board_temps_per_chip() const { - std::array out{}; - for (std::size_t cs = 0; cs < kNumChipSelects; ++cs) { - const auto& sel = chip_selects[cs]; - for (std::size_t c = 0; c < kNumChipsPerCS; ++c) { - const auto& chip = sel.chips[c]; - const std::size_t flat = cs * kNumChipsPerCS + c; - for (std::size_t g = 0; g < chip.read_map.num_groups(); ++g) { - if (!chip.read_map.is_group_on[g]) continue; - for (auto kind : chip.read_map.group_data_types[g]) { - if (kind == BOARD_TEMPERATURE) { ++out[flat]; } - } + constexpr std::size_t get_group_start_board_temperature_index(ReadGroup_e group){ + std::size_t index = 0; + for (std::size_t g = 0; g < static_cast(group); ++g) { + for (std::size_t k = 0; k < DATA_PER_GROUP; ++k) { + if (group_data_types[g][k] == BOARD_TEMPERATURE) { + ++index; } } } - return out; + return index; } - // ---- Derived totals (sum of per-chip) ---- - constexpr std::size_t num_voltage_cells_total() const { - const auto v = voltage_cells_per_chip(); - std::size_t s = 0; for (auto x : v) s += x; return s; +private: + const std::array num_values_in_each_group; + const std::array num_data_type_counts; + + static constexpr std::array make_per_group_counts(const std::array, NUM_GROUPS>& gdt) { + std::array out{}; // zero-initialized + for (std::size_t g = 0; g < out.size(); ++g) { + std::size_t c = 0; + for (std::size_t k = 0; k < DATA_PER_GROUP; ++k) + if (gdt[g][k] != NO_DATA) ++c; + out[g] = c; + } + return out; } - static constexpr std::size_t to_global_index(std::size_t cs_index, - std::size_t chip_index) noexcept { - return cs_index * kNumChipsPerCS + chip_index; + static constexpr std::array count_type(const std::array, NUM_GROUPS>& gdt) { + std::array counts{}; // zero-initialized + for (std::size_t g = 0; g < gdt.size(); ++g) + for (std::size_t k = 0; k < DATA_PER_GROUP; ++k) + switch (gdt[g][k]) { + case CELL_VOLTAGE: + ++counts[CELL_VOLTAGE]; + break; + case CELL_TEMPERATURE: + ++counts[CELL_TEMPERATURE]; + break; + case BOARD_TEMPERATURE: + ++counts[BOARD_TEMPERATURE]; + break; + default: + break; // NO_DATA or unrecognized + } + + return counts; } +}; +// ----- chip (immutable) ----- +template +struct Chip { + const size_t addr_pin; + const ReadGroupResultMap read_map; +}; - constexpr std::size_t num_temp_cells_total() const { - const auto t = temp_cells_per_chip(); - std::size_t s = 0; for (auto x : t) s += x; return s; - } +// ----- chip-select (immutable) ----- +template +class ChipSelect { +public: + const std::size_t cs_pin; + const std::array, NUM_CHIPS_PER_CS> chips; + + + constexpr std::size_t get_num_cell_voltages() const { return num_data_type_counts[CELL_VOLTAGE]; } + constexpr std::size_t get_num_cell_temps() const { return num_data_type_counts[CELL_TEMPERATURE]; } + constexpr std::size_t get_num_board_temps() const { return num_data_type_counts[BOARD_TEMPERATURE]; } + + // Constructor: initialize all const members + constexpr ChipSelect( + std::size_t cs, + const std::array, NUM_CHIPS_PER_CS>& chips_in + ) + : cs_pin(cs) + , chips(chips_in) + , num_data_type_counts(count_type(chips_in)) // <-- uses static helper + {} + + + +private: + const std::array num_data_type_counts; + // Static helper: computes counts from the given chips array + static constexpr std::array + count_type(const std::array, NUM_CHIPS_PER_CS>& chips_in) + { + std::array counts{}; // zero-initialized + + for (const auto& chip : chips_in) { + counts[CELL_VOLTAGE] += chip.read_map.get_num_cell_voltages(); + counts[CELL_TEMPERATURE] += chip.read_map.get_num_cell_temps(); + counts[BOARD_TEMPERATURE]+= chip.read_map.get_num_board_temps(); + } - constexpr std::size_t num_board_temps_total() const { - const auto b = board_temps_per_chip(); - std::size_t s = 0; for (auto x : b) s += x; return s; + return counts; } }; + + +// ----- full config (immutable) + constexpr derived views ----- +template +class ChipSelectConfig { +public: + const std::array, NUM_CS> chip_selects; + + constexpr ChipSelectConfig( + const std::array, NUM_CS>& chip_selects + ) : + chip_selects(chip_selects) + , num_data_type_counts(count_type(chip_selects)) // <-- uses static helper + {} + + constexpr std::size_t get_num_cell_voltages() const { return num_data_type_counts[CELL_VOLTAGE]; } + constexpr std::size_t get_num_cell_temps() const { return num_data_type_counts[CELL_TEMPERATURE]; } + constexpr std::size_t get_num_board_temps() const { return num_data_type_counts[BOARD_TEMPERATURE]; } + + size_t constexpr global_chip_index(size_t cs_index, size_t chip_index) const noexcept { + return cs_index * NUM_CHIPS_PER_CS + chip_index; + } + + private: + const std::array num_data_type_counts; + + // Static helper: computes counts from the given chips array + static constexpr std::array + count_type(const std::array, NUM_CS>& chip_selects) + { + std::array counts{}; // zero-initialized + + for (const auto& cs : chip_selects) { + counts[CELL_VOLTAGE] += cs.get_num_cell_voltages(); + counts[CELL_TEMPERATURE] += cs.get_num_cell_temps(); + counts[BOARD_TEMPERATURE]+= cs.get_num_board_temps(); + } + + return counts; + } +}; #endif diff --git a/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index bcffbef0..3af1fd4f 100644 --- a/src/ACU_InterfaceTasks.cpp +++ b/src/ACU_InterfaceTasks.cpp @@ -66,7 +66,7 @@ void initialize_all_interfaces() FaultLatchManagerInstance::instance().set_shdn_out_latched(true); // Start shdn out latch cleared /* BMS Driver */ - BMSDriverInstance_t::create(ACUConstants::CS, ACUConstants::CS_PER_CHIP, ACUConstants::ADDR); + BMSDriverInstance_t::create(ACUConstants::BMS_CHIP_SELECTS); BMSDriverInstance_t::instance().init(); /* Get Initial Pack Voltage for SoC and SoH Approximations */ auto data = BMSDriverInstance_t::instance().read_data(); @@ -130,7 +130,7 @@ HT_TASK::TaskResponse write_cell_balancing_config(const unsigned long &sysMicros auto data = BMSDriverInstance_t::instance().get_bms_data(); static std::array cell_balancing_statuses; ACUControllerInstance::instance().calculate_cell_balance_statuses(cell_balancing_statuses.data(), data.voltages.data(), ACUConstants::NUM_CELLS, data.min_cell_voltage); - BMSDriverInstance_t::instance().write_configuration(cell_balancing_statuses); + BMSDriverInstance_t::instance().write_configuration(cell_balancing_statuses.data(), cell_balancing_statuses.size()); return HT_TASK::TaskResponse::YIELD; } @@ -197,7 +197,7 @@ HT_TASK::TaskResponse enqueue_ACU_core_CAN_data(const unsigned long& sysMicros, HT_TASK::TaskResponse enqueue_ACU_all_voltages_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages.data(), ACUConstants::VOLTAGE_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIPS); + CCUInterfaceInstance::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages.data(), ACUConstants::VOLTAGE_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_SELECT); } return HT_TASK::TaskResponse::YIELD; } @@ -205,7 +205,7 @@ HT_TASK::TaskResponse enqueue_ACU_all_voltages_CAN_data(const unsigned long& sys HT_TASK::TaskResponse enqueue_ACU_all_temps_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance::instance().handle_enqueue_acu_cell_temps_CAN_message(bms_data.cell_temperatures.data(), ACUConstants::TEMP_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIPS); + CCUInterfaceInstance::instance().handle_enqueue_acu_cell_temps_CAN_message(bms_data.cell_temperatures.data(), ACUConstants::TEMP_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_SELECT); } return HT_TASK::TaskResponse::YIELD; } @@ -297,7 +297,7 @@ void print_bms_data(bms_data data) Serial.print("Number of Global Faults: "); Serial.println(BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count); Serial.println("Number of Consecutive Faults Per Chip: "); - for (size_t c = 0; c < ACUConstants::NUM_CHIPS; c++) { + for (size_t c = 0; c < ACUConstants::NUM_CHIPS_PER_SELECT * ACUConstants::NUM_CHIP_SELECTS; c++) { Serial.print("CHIP "); Serial.print(c); Serial.print(": "); From ecb4c9175350cbec2b7ac24f8623431ae91b9071 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Thu, 6 Nov 2025 20:20:46 -0800 Subject: [PATCH 15/18] removed some ACU Constants --- include/ACU_Constants.h | 40 +++++++++++++++++++++++++----------- include/ACU_InterfaceTasks.h | 4 ++-- include/ACU_SystemTasks.h | 4 ++-- src/ACU_InterfaceTasks.cpp | 12 +++++------ src/ACU_SystemTasks.cpp | 2 +- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/include/ACU_Constants.h b/include/ACU_Constants.h index 20901a28..9109100d 100644 --- a/include/ACU_Constants.h +++ b/include/ACU_Constants.h @@ -54,21 +54,14 @@ namespace ACUInterfaces { namespace ACUConstants { - constexpr size_t NUM_CELLS = 126; - constexpr size_t NUM_CHIPS_PER_SELECT = 6; + constexpr size_t NUM_CHIPS_PER_CHIP_SELECT = 6; constexpr size_t NUM_CHIP_SELECTS = 2; - constexpr size_t NUM_CHIPS_PER_CS = 6; constexpr size_t DATA_PER_CHIP_GROUP = 3; - constexpr std::array VOLTAGE_CELLS_PER_CHIP = { - 12, 9, 12, 9, 12, 9, 12, 9, 12, 9, 12, 9 - }; - constexpr std::array TEMP_CELLS_PER_CHIP = { - 4,4,4,4,4,4,4,4,4,4,4,4 - }; - constexpr ChipSelectConfig BMS_CHIP_SELECTS = ChipSelectConfig( + + constexpr ChipSelectConfig BMS_CHIP_SELECTS = ChipSelectConfig( std::array{ - ChipSelect( + ChipSelect( 9, std::array{ Chip{0, @@ -145,7 +138,7 @@ namespace ACUConstants }, } ), - ChipSelect( + ChipSelect( 10, std::array{ Chip{6, @@ -228,6 +221,29 @@ namespace ACUConstants constexpr size_t NUM_VOLTAGE_CELLS = BMS_CHIP_SELECTS.get_num_cell_voltages(); constexpr size_t NUM_TEMP_CELLS = BMS_CHIP_SELECTS.get_num_cell_temps(); constexpr size_t NUM_BOARD_TEMPS = BMS_CHIP_SELECTS.get_num_board_temps(); + + constexpr std::array VOLTAGE_CELLS_PER_CHIP = [](){ + std::array arr{}; + size_t i = 0; + for (size_t chip_select_index = 0; chip_select_index < NUM_CHIP_SELECTS; chip_select_index ++){ + for (size_t chip_select = 0; chip_select < NUM_CHIPS_PER_CHIP_SELECT; chip_select ++){ + arr[i] = BMS_CHIP_SELECTS.chip_selects[chip_select_index].chips[chip_select].read_map.get_num_cell_voltages(); + i++; + } + } + return arr; + }(); + constexpr std::array TEMP_CELLS_PER_CHIP = [](){ + std::array arr{}; + size_t i = 0; + for (size_t chip_select_index = 0; chip_select_index < NUM_CHIP_SELECTS; chip_select_index ++){ + for (size_t chip_select = 0; chip_select < NUM_CHIPS_PER_CHIP_SELECT; chip_select ++){ + arr[i] = BMS_CHIP_SELECTS.chip_selects[chip_select_index].chips[chip_select].read_map.get_num_cell_temps(); + i++; + } + } + return arr; + }(); const float VALID_SHDN_OUT_MIN_VOLTAGE_THRESHOLD = 12.0F; const uint32_t MIN_ALLOWED_INVALID_SHDN_OUT_MS = 10; // 10 ms -- requies 100 Hz samp freq. diff --git a/include/ACU_InterfaceTasks.h b/include/ACU_InterfaceTasks.h index 8ff563c7..0361d9a1 100644 --- a/include/ACU_InterfaceTasks.h +++ b/include/ACU_InterfaceTasks.h @@ -24,8 +24,8 @@ #include using chip_type = LTC6811_Type_e; -using BMSDriverInstance_t = BMSDriverInstance; -using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; +using BMSDriverInstance_t = BMSDriverInstance; +using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; /** * Init Functions - to be called in setup */ diff --git a/include/ACU_SystemTasks.h b/include/ACU_SystemTasks.h index 65a2ff7c..bb84b9bb 100644 --- a/include/ACU_SystemTasks.h +++ b/include/ACU_SystemTasks.h @@ -19,8 +19,8 @@ #include using chip_type = LTC6811_Type_e; -using BMSDriverInstance_t = BMSDriverInstance; -using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; +using BMSDriverInstance_t = BMSDriverInstance; +using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; bool initialize_all_systems(); diff --git a/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index 3af1fd4f..53b33ce0 100644 --- a/src/ACU_InterfaceTasks.cpp +++ b/src/ACU_InterfaceTasks.cpp @@ -128,8 +128,8 @@ HT_TASK::TaskResponse write_cell_balancing_config(const unsigned long &sysMicros { auto data = BMSDriverInstance_t::instance().get_bms_data(); - static std::array cell_balancing_statuses; - ACUControllerInstance::instance().calculate_cell_balance_statuses(cell_balancing_statuses.data(), data.voltages.data(), ACUConstants::NUM_CELLS, data.min_cell_voltage); + static std::array cell_balancing_statuses; + ACUControllerInstance::instance().calculate_cell_balance_statuses(cell_balancing_statuses.data(), data.voltages.data(), ACUConstants::NUM_VOLTAGE_CELLS, data.min_cell_voltage); BMSDriverInstance_t::instance().write_configuration(cell_balancing_statuses.data(), cell_balancing_statuses.size()); return HT_TASK::TaskResponse::YIELD; } @@ -197,7 +197,7 @@ HT_TASK::TaskResponse enqueue_ACU_core_CAN_data(const unsigned long& sysMicros, HT_TASK::TaskResponse enqueue_ACU_all_voltages_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages.data(), ACUConstants::VOLTAGE_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_SELECT); + CCUInterfaceInstance::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages.data(), ACUConstants::VOLTAGE_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_CHIP_SELECT); } return HT_TASK::TaskResponse::YIELD; } @@ -205,7 +205,7 @@ HT_TASK::TaskResponse enqueue_ACU_all_voltages_CAN_data(const unsigned long& sys HT_TASK::TaskResponse enqueue_ACU_all_temps_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance::instance().handle_enqueue_acu_cell_temps_CAN_message(bms_data.cell_temperatures.data(), ACUConstants::TEMP_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_SELECT); + CCUInterfaceInstance::instance().handle_enqueue_acu_cell_temps_CAN_message(bms_data.cell_temperatures.data(), ACUConstants::TEMP_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_CHIP_SELECT); } return HT_TASK::TaskResponse::YIELD; } @@ -246,7 +246,7 @@ void print_bms_data(bms_data data) Serial.println(data.max_cell_voltage_id); Serial.print("Average Voltage: "); - Serial.print(data.total_voltage / ACUConstants::NUM_CELLS, 4); + Serial.print(data.total_voltage / ACUConstants::NUM_VOLTAGE_CELLS, 4); Serial.println("V"); Serial.println(); @@ -297,7 +297,7 @@ void print_bms_data(bms_data data) Serial.print("Number of Global Faults: "); Serial.println(BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count); Serial.println("Number of Consecutive Faults Per Chip: "); - for (size_t c = 0; c < ACUConstants::NUM_CHIPS_PER_SELECT * ACUConstants::NUM_CHIP_SELECTS; c++) { + for (size_t c = 0; c < ACUConstants::NUM_CHIPS_PER_CHIP_SELECT * ACUConstants::NUM_CHIP_SELECTS; c++) { Serial.print("CHIP "); Serial.print(c); Serial.print(": "); diff --git a/src/ACU_SystemTasks.cpp b/src/ACU_SystemTasks.cpp index 245fc244..f8d90274 100644 --- a/src/ACU_SystemTasks.cpp +++ b/src/ACU_SystemTasks.cpp @@ -62,7 +62,7 @@ HT_TASK::TaskResponse evaluate_accumulator(const unsigned long &sysMicros, const BMSDriverInstance_t::instance().get_bms_core_data(), BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count, EMInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).em_current, - ACUConstants::NUM_CELLS + ACUConstants::NUM_VOLTAGE_CELLS ); return HT_TASK::TaskResponse::YIELD; } From ae43b99205ea2997ac7e095c6aba6baf5e3d5646 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Sun, 16 Nov 2025 12:10:16 -0500 Subject: [PATCH 16/18] merged with temp2 branch to remove any excess other pr changes from mixed prs --- include/ACU_Constants.h | 28 +-- include/ACU_InterfaceTasks.h | 6 +- include/ACU_SystemTasks.h | 3 +- lib/interfaces/include/ACUCANBuffers.h | 18 -- ...CUCANInterface.h => ACUCANInterfaceImpl.h} | 37 ++-- lib/interfaces/include/BMSDriverGroup.h | 50 +++--- lib/interfaces/include/BMSDriverGroup.tpp | 43 +++-- lib/interfaces/include/CCUInterface.h | 132 +++++++------- lib/interfaces/include/SystemTimeInterface.h | 6 - lib/interfaces/src/ACUCANBuffers.cpp | 7 - lib/interfaces/src/ACUCANInterface.cpp | 66 ------- lib/interfaces/src/ACUCANInterfaceImpl.cpp | 53 ++++++ lib/interfaces/src/CCUInterface.cpp | 148 +++++++--------- lib/interfaces/src/EMInterface.cpp | 2 +- lib/interfaces/src/SystemTimeInterface.cpp | 10 -- lib/interfaces/src/VCRInterface.cpp | 5 +- lib/shared_types/shared_types.h | 50 +----- lib/systems/include/ACUController.h | 46 ++--- .../ACUController.tpp} | 69 ++++---- platformio.ini | 6 +- src/ACU_InterfaceTasks.cpp | 65 +++---- src/ACU_SystemTasks.cpp | 19 +- src/main.cpp | 9 +- src/main_spi_test.cpp | 10 +- test/test_systems/test_acu_controller.h | 164 +++++++++--------- 25 files changed, 456 insertions(+), 596 deletions(-) delete mode 100644 lib/interfaces/include/ACUCANBuffers.h rename lib/interfaces/include/{ACUCANInterface.h => ACUCANInterfaceImpl.h} (59%) delete mode 100644 lib/interfaces/src/ACUCANBuffers.cpp delete mode 100644 lib/interfaces/src/ACUCANInterface.cpp create mode 100644 lib/interfaces/src/ACUCANInterfaceImpl.cpp rename lib/systems/{src/ACUController.cpp => include/ACUController.tpp} (67%) diff --git a/include/ACU_Constants.h b/include/ACU_Constants.h index 9109100d..a9ef5de5 100644 --- a/include/ACU_Constants.h +++ b/include/ACU_Constants.h @@ -15,7 +15,6 @@ using time_ms = uint32_t; namespace ACUSystems { - constexpr const volt MIN_DISCHARGE_VOLTAGE_THRESH = 3.8F; // Minimum voltage for a cell to be discharged constexpr const volt CELL_OVERVOLTAGE_THRESH = 4.2; // Cell overvoltage threshold in Volts constexpr const volt CELL_UNDERVOLTAGE_THRESH = 3.05; // Cell undervoltage threshold in Volts constexpr const volt MIN_PACK_TOTAL_VOLTAGE = 420.0; // Volts @@ -53,12 +52,12 @@ namespace ACUInterfaces { } namespace ACUConstants -{ +{ + constexpr size_t NUM_CELLS = 126; constexpr size_t NUM_CHIPS_PER_CHIP_SELECT = 6; constexpr size_t NUM_CHIP_SELECTS = 2; constexpr size_t DATA_PER_CHIP_GROUP = 3; - constexpr ChipSelectConfig BMS_CHIP_SELECTS = ChipSelectConfig( std::array{ ChipSelect( @@ -221,29 +220,6 @@ namespace ACUConstants constexpr size_t NUM_VOLTAGE_CELLS = BMS_CHIP_SELECTS.get_num_cell_voltages(); constexpr size_t NUM_TEMP_CELLS = BMS_CHIP_SELECTS.get_num_cell_temps(); constexpr size_t NUM_BOARD_TEMPS = BMS_CHIP_SELECTS.get_num_board_temps(); - - constexpr std::array VOLTAGE_CELLS_PER_CHIP = [](){ - std::array arr{}; - size_t i = 0; - for (size_t chip_select_index = 0; chip_select_index < NUM_CHIP_SELECTS; chip_select_index ++){ - for (size_t chip_select = 0; chip_select < NUM_CHIPS_PER_CHIP_SELECT; chip_select ++){ - arr[i] = BMS_CHIP_SELECTS.chip_selects[chip_select_index].chips[chip_select].read_map.get_num_cell_voltages(); - i++; - } - } - return arr; - }(); - constexpr std::array TEMP_CELLS_PER_CHIP = [](){ - std::array arr{}; - size_t i = 0; - for (size_t chip_select_index = 0; chip_select_index < NUM_CHIP_SELECTS; chip_select_index ++){ - for (size_t chip_select = 0; chip_select < NUM_CHIPS_PER_CHIP_SELECT; chip_select ++){ - arr[i] = BMS_CHIP_SELECTS.chip_selects[chip_select_index].chips[chip_select].read_map.get_num_cell_temps(); - i++; - } - } - return arr; - }(); const float VALID_SHDN_OUT_MIN_VOLTAGE_THRESHOLD = 12.0F; const uint32_t MIN_ALLOWED_INVALID_SHDN_OUT_MS = 10; // 10 ms -- requies 100 Hz samp freq. diff --git a/include/ACU_InterfaceTasks.h b/include/ACU_InterfaceTasks.h index 0361d9a1..a48308f3 100644 --- a/include/ACU_InterfaceTasks.h +++ b/include/ACU_InterfaceTasks.h @@ -11,12 +11,10 @@ #include "WatchdogInterface.h" #include "WatchdogMetrics.h" #include "ACUEthernetInterface.h" -#include "ACUCANInterface.h" -#include "CCUInterface.h" +#include "ACUCANInterfaceImpl.h" #include "ADCInterface.h" #include "FaultLatchManager.h" #include "SystemTimeInterface.h" -#include "ACUCANBuffers.h" /* For Debugging */ #include "ACUStateMachine.h" @@ -24,8 +22,10 @@ #include using chip_type = LTC6811_Type_e; +using ACUControllerInstance_t = ACUControllerInstance; using BMSDriverInstance_t = BMSDriverInstance; using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; + /** * Init Functions - to be called in setup */ diff --git a/include/ACU_SystemTasks.h b/include/ACU_SystemTasks.h index bb84b9bb..a3d0dc20 100644 --- a/include/ACU_SystemTasks.h +++ b/include/ACU_SystemTasks.h @@ -13,14 +13,13 @@ #include "CCUInterface.h" #include "EMInterface.h" #include "BMSDriverGroup.h" -#include "BMSFaultDataManager.h" #include "ADCInterface.h" #include "SystemTimeInterface.h" #include using chip_type = LTC6811_Type_e; +using ACUControllerInstance_t = ACUControllerInstance; using BMSDriverInstance_t = BMSDriverInstance; -using BMSFaultDataManagerInstance_t = BMSFaultDataManagerInstance; bool initialize_all_systems(); diff --git a/lib/interfaces/include/ACUCANBuffers.h b/lib/interfaces/include/ACUCANBuffers.h deleted file mode 100644 index 484a26e2..00000000 --- a/lib/interfaces/include/ACUCANBuffers.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ACU_CAN_BUFFERS_H -#define ACU_CAN_BUFFERS_H - -#include -#include "FlexCAN_T4.h" -#include "CANInterface.h" - -const size_t CAN_MSG_SIZE = sizeof(CAN_message_t); -using CANRXBuffer_t = Circular_Buffer; -using CANTXBuffer_t = Circular_Buffer; - -namespace ACUCANBuffers { - extern CANRXBuffer_t ccu_can_rx_buffer; - extern CANRXBuffer_t em_can_rx_buffer; - extern CANTXBuffer_t ccu_can_tx_buffer; -} - -#endif // CAN_BUFFERS_H diff --git a/lib/interfaces/include/ACUCANInterface.h b/lib/interfaces/include/ACUCANInterfaceImpl.h similarity index 59% rename from lib/interfaces/include/ACUCANInterface.h rename to lib/interfaces/include/ACUCANInterfaceImpl.h index 7d2b62c6..b06540d6 100644 --- a/lib/interfaces/include/ACUCANInterface.h +++ b/lib/interfaces/include/ACUCANInterfaceImpl.h @@ -1,5 +1,5 @@ -#ifndef ACUCANINTERFACE_H -#define ACUCANINTERFACE_H +#ifndef ACUCANINTERFACEIMPL_H +#define ACUCANINTERFACEIMPL_H #include #include @@ -14,44 +14,43 @@ #include "shared_types.h" #include "hytech.h" // generated CAN library -#include "ACUCANBuffers.h" #include "ACUController.h" +#include "CCUInterface.h" #include "VCRInterface.h" #include "EMInterface.h" -#include "CCUInterface.h" -/* FlexCAN type alias */ +const size_t CAN_MSG_SIZE = sizeof(CAN_message_t); +using CANRXBuffer_t = Circular_Buffer; +using CANTXBuffer_t = Circular_Buffer; + +/* RX buffers for CAN extern declarations*/ template using FlexCAN_t = FlexCAN_T4; -/* CANInterfaces struct - holds references to all CAN-connected interfaces */ struct CANInterfaces_s { explicit CANInterfaces_s(CCUInterface &ccu_int, EMInterface &em_int) : ccu_interface(ccu_int), em_interface(em_int) {} - CCUInterface& ccu_interface; + CCUInterface & ccu_interface; EMInterface & em_interface; }; using CANInterfacesInstance = etl::singleton; +namespace ACUCANInterfaceImpl { + extern CANRXBuffer_t ccu_can_rx_buffer; + extern CANRXBuffer_t em_can_rx_buffer; + extern CANTXBuffer_t ccu_can_tx_buffer; -/* ACUCANInterface namespace - Main CAN interface handler functions */ -namespace ACUCANInterface { - // CAN hardware instances extern FlexCAN_t CCU_CAN; extern FlexCAN_t EM_CAN; - // CAN receive callbacks void on_ccu_can_receive(const CAN_message_t &msg); void on_em_can_receive(const CAN_message_t &msg); + + void acu_CAN_recv(CANInterfaces_s &interfaces, const CAN_message_t &msg, unsigned long millis); - // Main CAN message handler (templated free function) - void acu_CAN_recv(CANInterfaces_s &interfaces, - const CAN_message_t &msg, - unsigned long millis); - - // Send all queued CAN messages void send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface); -} + +}; // namespace ACUCANInterfaceImpl -#endif +#endif // ACUCANINTERFACEIMPL_H diff --git a/lib/interfaces/include/BMSDriverGroup.h b/lib/interfaces/include/BMSDriverGroup.h index c80a929f..fc70e008 100644 --- a/lib/interfaces/include/BMSDriverGroup.h +++ b/lib/interfaces/include/BMSDriverGroup.h @@ -87,6 +87,15 @@ namespace bms_driver_defaults constexpr const float CV_ADC_LSB_VOLTAGE = 0.0001f; // Cell voltage ADC resolution: 100μV per LSB (1/10000 V) constexpr const size_t SIZE_OF_PACKET_VALUE_BYTES = 2; } +namespace ref_max_min_defaults +{ + constexpr const volt TOTAL_VOLTAGE = 0; + constexpr const volt MAX_CELL_VOLTAGE = 0; + constexpr const volt MIN_CELL_VOLTAGE = 10; + constexpr const celsius MIN_CELL_TEMP = 80; + constexpr const celsius MAX_CELL_TEMP = 0; + constexpr const celsius MAX_BOARD_TEMP = 0; +}; @@ -114,13 +123,13 @@ struct BMSData_s struct ReferenceMaxMin_s { - volt total_voltage = 0; - volt max_cell_voltage = 0; - volt min_cell_voltage = 10; - celsius min_cell_temp = 80; - celsius max_cell_temp = 0; - celsius max_board_temp = 0; - celsius total_thermistor_temps = 0; + volt total_voltage; + volt max_cell_voltage; + volt min_cell_voltage; + celsius min_cell_temp; + celsius max_cell_temp; + celsius max_board_temp; + celsius total_thermistor_temps; }; struct BMSDriverGroupConfig_s @@ -161,15 +170,9 @@ template _read_group_to_cmd = { CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_A, CMD_CODES_e::READ_CELL_VOLTAGE_GROUP_B, @@ -178,11 +181,15 @@ class BMSDriverGroup CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_A, CMD_CODES_e::READ_GPIO_VOLTAGE_GROUP_B }; - using ChipSelectConfig_t = ChipSelectConfig; - using ChipSelect_t = ChipSelect; - using Chip_t = Chip<_num_values_per_packet>; - using BMSDriverData_t = BMSData_s; + // constexpr static size_t num_cell_temps = (num_chips * 4); + // constexpr static size_t num_board_temps = num_chips; + + using BMSCoreData_t = BMSCoreData_s; + using BMSDriverData_t = BMSData_s; + using ChipSelectConfig_t = ChipSelectConfig; + using ChipSelect_t = ChipSelect; + using Chip_t = Chip<_data_size_bytes / size_of_packet_value_bytes>; BMSDriverGroup( const ChipSelectConfig_t& chip_select_config, const BMSDriverGroupConfig_s default_params @@ -214,7 +221,7 @@ class BMSDriverGroup /** * Getter function to retrieve the ACUData structure */ - BMSCoreData_s get_bms_core_data(); + BMSCoreData_t get_bms_core_data(); /** * Getter function to retrieve the BMSDriverData structure @@ -418,7 +425,6 @@ class BMSDriverGroup uint8_t _get_cmd_address(int address) { return 0x80 | (address << 3); } private: - /** * initializes PEC table * Made static so that it can be called in constructor -> _pec15table is made const diff --git a/lib/interfaces/include/BMSDriverGroup.tpp b/lib/interfaces/include/BMSDriverGroup.tpp index 37bdd45a..d4f6a651 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -8,7 +8,7 @@ #include template -BMSDriverGroup::BMSDriverGroup(const ChipSelectConfig_t& chip_select_config, +BMSDriverGroup::BMSDriverGroup(const ChipSelectConfig_t& chip_select_config = ACUConstants::BMS_CHIP_SELECTS, const BMSDriverGroupConfig_s default_params = { .device_refup_mode = bms_driver_defaults::DEVICE_REFUP_MODE, .adcopt = bms_driver_defaults::ADCOPT, @@ -46,6 +46,14 @@ void BMSDriverGroup @@ -102,15 +110,19 @@ constexpr std::array BMSDriverGroup -BMSCoreData_s BMSDriverGroup::get_bms_core_data() +typename BMSDriverGroup::BMSCoreData_t +BMSDriverGroup::get_bms_core_data() { - BMSCoreData_s out{}; + BMSCoreData_t out{}; // Basic voltages out.min_cell_voltage = _bms_data.min_cell_voltage; out.max_cell_voltage = _bms_data.max_cell_voltage; out.pack_voltage = _bms_data.total_voltage; + // Per-cell array (sizes must match) + out.voltages = _bms_data.voltages; + // Temps out.max_cell_temp = _bms_data.max_cell_temp; out.min_cell_temp = _bms_data.min_cell_temp; @@ -183,7 +195,7 @@ BMSDriverGroup spi_response; + std::array spi_response; //relevant for GPIO reading bool current_group_valid = false; @@ -193,7 +205,7 @@ BMSDriverGroup clean_valid_packet_data = {true}; // should be all reset to true _bms_data.valid_read_packets.fill(clean_valid_packet_data); // reset // std::array data_in_cell_voltages_1_to_12; - std::array chip_data; + std::array chip_data; // std::array data_in_auxillaries_1_to_5; std::array cmd_pec; size_t battery_cell_count = 0; @@ -268,7 +278,7 @@ BMSDriverGroup> 8); - temp_pec = _calculate_specific_PEC(buffer_format.data(), _packet_data_size_bytes); - std::copy_n(buffer_format.begin(), _packet_data_size_bytes, full_buffer.data() + (chip_select_index * _total_packet_size_bytes)); - std::copy_n(temp_pec.begin(), _packet_pec_size_bytes, full_buffer.data() + _packet_data_size_bytes + (chip_select_index * _total_packet_size_bytes)); + temp_pec = _calculate_specific_PEC(buffer_format.data(), _total_packet_size_bytes); + std::copy_n(buffer_format.begin(), _total_packet_size_bytes, full_buffer.data() + (chip_select_index * _total_packet_size_bytes)); + std::copy_n(temp_pec.begin(), _pec_size_bytes, full_buffer.data() + _total_packet_size_bytes + (chip_select_index * _total_packet_size_bytes)); } ltc_spi_interface::write_registers_command(_chip_select_config.chip_selects[chip_select_index].cs_pin, cmd_and_pec, full_buffer); } diff --git a/lib/interfaces/include/CCUInterface.h b/lib/interfaces/include/CCUInterface.h index e304ac5e..b3417864 100644 --- a/lib/interfaces/include/CCUInterface.h +++ b/lib/interfaces/include/CCUInterface.h @@ -12,44 +12,34 @@ #include "FlexCAN_T4.h" #include "SharedFirmwareTypes.h" #include "shared_types.h" -#include "ACUCANBuffers.h" // NEW: Include shared buffer declarations -enum ACUChargingState_e -{ - CHARGING = 1, - NOT_CHARGING = 0, -}; namespace ccu_interface_defaults{ constexpr const uint16_t MIN_CHARGING_ENABLE_THRESHOLD_MS = 1000; - constexpr const size_t VOLTAGE_CELLS_PER_GROUP = 3; - constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_EVEN = 4; - constexpr const size_t VOLTAGE_CELL_GROUPS_PER_IC_ODD = 3; - constexpr const size_t TEMP_CELL_GROUPS_PER_IC = 2; - constexpr const size_t TEMP_CELLS_PER_GROUP = 2; + constexpr const size_t NUM_CELLS = 126; + constexpr const size_t NUM_CELLTEMPS = 48; + constexpr const size_t NUM_CHIPS = 12; }; -struct CCUInterfaceParams_s { - unsigned long min_charging_enable_threshold; - size_t voltage_cell_groups_per_ic_even; - size_t voltage_cell_groups_per_ic_odd; - size_t temp_cell_groups_per_ic; - size_t voltage_cells_per_group; - size_t temp_cells_per_group; -}; struct CCUCANInterfaceData_s { - unsigned long last_time_charging_with_balancing_requested; + unsigned long last_time_charging_requested; unsigned long prev_ccu_msg_recv_ms; + bool charging_requested; + bool is_connected_to_CCU; + size_t detailed_voltages_ic_id; + size_t detailed_voltages_group_id; + size_t detailed_voltages_cell_id; + size_t detailed_temps_ic_id; + size_t detailed_temps_group_id; + size_t detailed_temps_cell_id; + size_t detailed_temps_board_id; +}; - size_t current_voltage_group_chip_id; - size_t current_voltage_cell_group_id; - size_t current_voltage_cell_id; - - size_t current_temp_group_chip_id; - size_t current_temp_group_id; - size_t current_temp_cell_id; - - size_t current_temp_board_id; +struct CCUInterfaceParams_s { + unsigned long min_charging_enable_threshold; + size_t num_cells; + size_t num_celltemps; + size_t num_chips; }; class CCUInterface @@ -60,63 +50,69 @@ class CCUInterface CCUInterface(unsigned long init_millis, CCUInterfaceParams_s params = { .min_charging_enable_threshold = ccu_interface_defaults::MIN_CHARGING_ENABLE_THRESHOLD_MS, - .voltage_cell_groups_per_ic_even = ccu_interface_defaults::VOLTAGE_CELL_GROUPS_PER_IC_EVEN, - .voltage_cell_groups_per_ic_odd = ccu_interface_defaults::VOLTAGE_CELL_GROUPS_PER_IC_ODD, - .temp_cell_groups_per_ic = ccu_interface_defaults::TEMP_CELL_GROUPS_PER_IC, - .voltage_cells_per_group = ccu_interface_defaults::VOLTAGE_CELLS_PER_GROUP, - .temp_cells_per_group = ccu_interface_defaults::TEMP_CELLS_PER_GROUP + .num_cells = ccu_interface_defaults::NUM_CELLS, + .num_celltemps = ccu_interface_defaults::NUM_CELLTEMPS, + .num_chips = ccu_interface_defaults::NUM_CHIPS } ) : _ccu_params{params} { - - _curr_data.last_time_charging_with_balancing_requested = 0; + _curr_data.last_time_charging_requested = 0; _curr_data.prev_ccu_msg_recv_ms = 0; - - _curr_data.current_voltage_cell_group_id = 0; - _curr_data.current_voltage_group_chip_id = 0; - _curr_data.current_voltage_cell_id = 0; - - _curr_data.current_temp_group_id = 0; - _curr_data.current_temp_group_chip_id = 0; - _curr_data.current_temp_cell_id = 0; - - - _curr_data.current_temp_board_id = 0; + _curr_data.charging_requested = false; + _curr_data.is_connected_to_CCU = false; + _curr_data.detailed_voltages_group_id = 0; + _curr_data.detailed_voltages_ic_id = 0; + _curr_data.detailed_voltages_cell_id = 0; + _curr_data.detailed_temps_group_id = 0; + _curr_data.detailed_temps_ic_id = 0; + _curr_data.detailed_temps_cell_id = 0; + _curr_data.detailed_temps_board_id = 0; }; - bool is_connected_to_CCU(unsigned long curr_millis) {return (curr_millis - _curr_data.prev_ccu_msg_recv_ms) < _ccu_params.min_charging_enable_threshold; } + bool is_charging_requested() { return _curr_data.charging_requested; } - bool is_charging_with_balancing_requested(unsigned long curr_millis) {return (curr_millis - _curr_data.last_time_charging_with_balancing_requested) < _ccu_params.min_charging_enable_threshold; } + bool is_connected_to_CCU() {return _curr_data.is_connected_to_CCU; } void receive_CCU_status_message(const CAN_message_t &msg, unsigned long curr_millis); - void handle_enqueue_acu_status_CAN_message(bool charging_enabled); - - void handle_enqueue_acu_voltage_statistics_CAN_message(float max_cell_voltage, float min_cell_voltage, float pack_voltage, float avg_cell_voltage); - void handle_enqueue_acu_cell_voltages_CAN_message(const volt* cell_voltages, const size_t* voltage_cells_per_chip, const size_t num_of_chips); - void handle_enqueue_acu_temp_statistics_CAN_message(celsius max_board_temp, celsius max_cell_temp, celsius min_cell_temp); - void handle_enqueue_acu_cell_temps_CAN_message(const celsius* cell_temps, const size_t* temp_cells_per_chip, const size_t num_of_chips); - void handle_enqueue_acu_cell_board_temps_CAN_message(const celsius* board_temps, const size_t num_of_boards); + void set_system_latch_state(unsigned long curr_millis, bool is_latched); - CCUCANInterfaceData_s get_latest_data(); - -private: - CCUCANInterfaceData_s _curr_data; - CCUInterfaceParams_s _ccu_params; + CCUCANInterfaceData_s get_latest_data(unsigned long curr_millis); - bool _increment_and_loop_id(size_t &id, size_t max_id, size_t increment = 1) + template + void set_ACU_data(ACUAllData_s input) { - if (id == max_id - increment) { - id = 0; - return true; + _acu_core_data.avg_cell_voltage = input.core_data.avg_cell_voltage; + _acu_core_data.max_cell_voltage = input.core_data.max_cell_voltage; + _acu_core_data.min_cell_voltage = input.core_data.min_cell_voltage; + _acu_core_data.pack_voltage = input.core_data.pack_voltage; + for (size_t c = 0; c < num_cells; c++) + { + _acu_all_data.cell_voltages[c] = input.cell_voltages[c]; + } + for (size_t temp = 0; temp < num_celltemps; temp++) + { + _acu_all_data.cell_temps[temp] = input.cell_temps[temp]; } - else { - id += increment; - return false; + for (size_t board = 0; board < num_chips; board++) { + _acu_all_data.board_temps[board] = input.board_temps[board]; } + _acu_all_data.core_data.max_board_temp = input.core_data.max_board_temp; + _acu_all_data.core_data.min_cell_temp = input.core_data.min_cell_temp; + _acu_all_data.core_data.max_cell_temp = input.core_data.max_cell_temp; } + void handle_enqueue_acu_status_CAN_message(); + void handle_enqueue_acu_core_voltages_CAN_message(); + void handle_enqueue_acu_voltages_CAN_message(); + void handle_enqueue_acu_temps_CAN_message(); + +private: + CCUCANInterfaceData_s _curr_data; + ACUCoreData_s _acu_core_data; + ACUAllData_s _acu_all_data; + CCUInterfaceParams_s _ccu_params; }; using CCUInterfaceInstance = etl::singleton; diff --git a/lib/interfaces/include/SystemTimeInterface.h b/lib/interfaces/include/SystemTimeInterface.h index c1c5929a..426b471c 100644 --- a/lib/interfaces/include/SystemTimeInterface.h +++ b/lib/interfaces/include/SystemTimeInterface.h @@ -5,12 +5,6 @@ namespace sys_time { unsigned long hal_millis(); unsigned long hal_micros(); - - unsigned long micros_to_millis(unsigned long micros); - unsigned long millis_to_micros(unsigned long millis); - - const unsigned long MILLIS_TO_MICROS_FACTOR = 1000; - }; #endif // SYSTEMTIMEINTERFACE_H \ No newline at end of file diff --git a/lib/interfaces/src/ACUCANBuffers.cpp b/lib/interfaces/src/ACUCANBuffers.cpp deleted file mode 100644 index ce082795..00000000 --- a/lib/interfaces/src/ACUCANBuffers.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "ACUCANBuffers.h" - -namespace ACUCANBuffers { - CANTXBuffer_t ccu_can_tx_buffer{}; - CANRXBuffer_t ccu_can_rx_buffer{}; - CANRXBuffer_t em_can_rx_buffer{}; -} \ No newline at end of file diff --git a/lib/interfaces/src/ACUCANInterface.cpp b/lib/interfaces/src/ACUCANInterface.cpp deleted file mode 100644 index 0e78e15a..00000000 --- a/lib/interfaces/src/ACUCANInterface.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "ACUCANInterface.h" -#include "ACUCANBuffers.h" -#include -#include - -namespace ACUCANInterface { - -// Define CAN hardware instances -FlexCAN_t CCU_CAN; -FlexCAN_t EM_CAN; - -// CAN receive callback for CCU CAN bus -void on_ccu_can_receive(const CAN_message_t &msg) -{ - std::array buf; - std::memmove(buf.data(), &msg, sizeof(msg)); - ACUCANBuffers::ccu_can_rx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); -} - -// CAN receive callback for EM CAN bus -void on_em_can_receive(const CAN_message_t &msg) -{ - std::array buf; - std::memmove(buf.data(), &msg, sizeof(msg)); - ACUCANBuffers::em_can_rx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); -} - -// Send all queued CAN messages to the specified CAN interface -void send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface) -{ - CAN_message_t msg; - while (buffer.available()) - { - std::array buf; - buffer.pop_front(buf.data(), sizeof(CAN_message_t)); - std::memmove(&msg, buf.data(), sizeof(msg)); - can_interface->write(msg); - } -} - -void acu_CAN_recv( - CANInterfaces_s &interfaces, - const CAN_message_t &msg, - unsigned long millis) -{ - switch (msg.id) - { - case CCU_STATUS_CANID: - { - interfaces.ccu_interface.receive_CCU_status_message(msg, millis); - break; - } - case EM_MEASUREMENT_CANID: - { - interfaces.em_interface.receive_EM_measurement_message(msg, millis); - break; - } - default: - { - break; - } - } -} - - -} // namespace ACUCANInterface diff --git a/lib/interfaces/src/ACUCANInterfaceImpl.cpp b/lib/interfaces/src/ACUCANInterfaceImpl.cpp new file mode 100644 index 00000000..5d6ab7ca --- /dev/null +++ b/lib/interfaces/src/ACUCANInterfaceImpl.cpp @@ -0,0 +1,53 @@ +#include "ACUCANInterfaceImpl.h" + +CANRXBuffer_t ACUCANInterfaceImpl::ccu_can_rx_buffer; +CANRXBuffer_t ACUCANInterfaceImpl::em_can_rx_buffer; +CANTXBuffer_t ACUCANInterfaceImpl::ccu_can_tx_buffer; + +void ACUCANInterfaceImpl::on_ccu_can_receive(const CAN_message_t &msg) +{ + std::array buf; + memmove(buf.data(), &msg, sizeof(msg)); + ccu_can_rx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); +} + +void ACUCANInterfaceImpl::on_em_can_receive(const CAN_message_t &msg) +{ + std::array buf; + memmove(buf.data(), &msg, sizeof(msg)); + ccu_can_tx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); + em_can_rx_buffer.push_back(buf.data(), sizeof(CAN_message_t)); +} + +void ACUCANInterfaceImpl::acu_CAN_recv(CANInterfaces_s &interfaces, const CAN_message_t &msg, unsigned long millis) +{ + switch (msg.id) + { + case CCU_STATUS_CANID: + { + interfaces.ccu_interface.receive_CCU_status_message(msg, millis); + break; + } + case EM_MEASUREMENT_CANID: + { + interfaces.em_interface.receive_EM_measurement_message(msg, millis); + break; + } + default: + { + break; + } + } +} + +void ACUCANInterfaceImpl::send_all_CAN_msgs(CANTXBuffer_t &buffer, FlexCAN_T4_Base *can_interface) +{ + CAN_message_t msg; + while (buffer.available()) + { + std::array buf; + buffer.pop_front(buf.data(), sizeof(CAN_message_t)); + memmove(&msg, buf.data(), sizeof(msg)); + can_interface->write(msg); + } +} diff --git a/lib/interfaces/src/CCUInterface.cpp b/lib/interfaces/src/CCUInterface.cpp index 6f1ad927..a1636c85 100644 --- a/lib/interfaces/src/CCUInterface.cpp +++ b/lib/interfaces/src/CCUInterface.cpp @@ -1,112 +1,92 @@ -#include "hytech.h" #include "CCUInterface.h" +#include "ACUCANInterfaceImpl.h" +#include "hytech.h" + void CCUInterface::receive_CCU_status_message(const CAN_message_t& msg, unsigned long curr_millis) { CCU_STATUS_t ccu_msg; Unpack_CCU_STATUS_hytech(&ccu_msg, &msg.buf[0], msg.len); - - if (ccu_msg.charger_enabled) _curr_data.last_time_charging_with_balancing_requested = curr_millis; + if (ccu_msg.charger_enabled == false || (_curr_data.charging_requested && ccu_msg.charger_enabled)) { + _curr_data.last_time_charging_requested = curr_millis; + } + _curr_data.is_connected_to_CCU = (curr_millis - _curr_data.prev_ccu_msg_recv_ms) < _ccu_params.min_charging_enable_threshold; _curr_data.prev_ccu_msg_recv_ms = curr_millis; } -void CCUInterface::handle_enqueue_acu_status_CAN_message(bool charging_enabled) { +void CCUInterface::handle_enqueue_acu_status_CAN_message() { BMS_STATUS_t msg = {}; - if (charging_enabled) { - msg.charging_state = ACUChargingState_e::CHARGING; + if (_curr_data.charging_requested) { + msg.state = 2; // charging } else { - msg.charging_state = ACUChargingState_e::NOT_CHARGING; + msg.state = 1; // discharging } - CAN_util::enqueue_msg(&msg, &Pack_BMS_STATUS_hytech, ACUCANBuffers::ccu_can_tx_buffer); + CAN_util::enqueue_msg(&msg, &Pack_BMS_STATUS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } -void CCUInterface::handle_enqueue_acu_voltage_statistics_CAN_message( - float max_cell_voltage, float min_cell_voltage, float pack_voltage, float avg_cell_voltage -) { +void CCUInterface::handle_enqueue_acu_core_voltages_CAN_message() { BMS_VOLTAGES_t msg = {}; - msg.max_cell_voltage_ro = HYTECH_max_cell_voltage_ro_toS(max_cell_voltage); - msg.min_cell_voltage_ro = HYTECH_min_cell_voltage_ro_toS(min_cell_voltage); - msg.total_voltage_ro = HYTECH_total_voltage_ro_toS(pack_voltage); - msg.average_voltage_ro = HYTECH_average_voltage_ro_toS(avg_cell_voltage); - CAN_util::enqueue_msg(&msg, &Pack_BMS_VOLTAGES_hytech, ACUCANBuffers::ccu_can_tx_buffer); + msg.high_voltage_ro = HYTECH_high_voltage_ro_toS(_acu_core_data.max_cell_voltage); + msg.low_voltage_ro = HYTECH_low_voltage_ro_toS(_acu_core_data.min_cell_voltage); + msg.total_voltage_ro = HYTECH_total_voltage_ro_toS(_acu_core_data.pack_voltage); + msg.average_voltage_ro = HYTECH_average_voltage_ro_toS(_acu_core_data.avg_cell_voltage); + CAN_util::enqueue_msg(&msg, &Pack_BMS_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } -void CCUInterface::handle_enqueue_acu_cell_voltages_CAN_message( - const volt* cell_voltages, - const size_t* voltage_cells_per_chip, - const size_t num_of_chips -) { - BMS_CELL_VOLTAGES_t msg = {}; - - msg.chip_id = static_cast(_curr_data.current_voltage_group_chip_id); - msg.cell_group_id = static_cast(_curr_data.current_voltage_cell_group_id); - - size_t num_of_groups = voltage_cells_per_chip[_curr_data.current_voltage_group_chip_id] / _ccu_params.voltage_cells_per_group; - size_t num_of_voltage_cells = std::accumulate(voltage_cells_per_chip, voltage_cells_per_chip + num_of_chips, 0); - - msg.cell_group_voltage_0_ro = HYTECH_cell_group_voltage_0_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id]); - msg.cell_group_voltage_1_ro = HYTECH_cell_group_voltage_1_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id + 1]); - msg.cell_group_voltage_2_ro = HYTECH_cell_group_voltage_2_ro_toS(cell_voltages[_curr_data.current_voltage_cell_id + 2]); +void CCUInterface::handle_enqueue_acu_voltages_CAN_message() { + BMS_DETAILED_VOLTAGES_t detailed_msg = {}; + detailed_msg.ic_id = static_cast(_curr_data.detailed_voltages_ic_id); + detailed_msg.group_id = static_cast(_curr_data.detailed_voltages_group_id); + detailed_msg.voltage_0_ro = HYTECH_voltage_0_ro_toS(_acu_all_data.cell_voltages[_curr_data.detailed_voltages_cell_id]); + detailed_msg.voltage_1_ro = HYTECH_voltage_1_ro_toS(_acu_all_data.cell_voltages[_curr_data.detailed_voltages_cell_id+1]); + detailed_msg.voltage_2_ro = HYTECH_voltage_2_ro_toS(_acu_all_data.cell_voltages[_curr_data.detailed_voltages_cell_id+2]); - bool voltage_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_voltage_cell_group_id, num_of_groups); - - if (voltage_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_voltage_group_chip_id, num_of_chips); - - _increment_and_loop_id(_curr_data.current_voltage_cell_id, num_of_voltage_cells, _ccu_params.voltage_cells_per_group); + if (_curr_data.detailed_voltages_ic_id % 2 == 0) { + _curr_data.detailed_voltages_group_id = (_curr_data.detailed_voltages_group_id == 3) ? 0 : _curr_data.detailed_voltages_group_id+1; + } else { + _curr_data.detailed_voltages_group_id = (_curr_data.detailed_voltages_group_id == 2) ? 0 : _curr_data.detailed_voltages_group_id+1; + } + if (_curr_data.detailed_voltages_group_id == 0) { + _curr_data.detailed_voltages_ic_id = (_curr_data.detailed_voltages_ic_id == (ccu_interface_defaults::NUM_CHIPS - 1)) ? 0 : _curr_data.detailed_voltages_ic_id+1; + } + _curr_data.detailed_voltages_cell_id = (_curr_data.detailed_voltages_cell_id == ccu_interface_defaults::NUM_CELLS - 3) ? 0 : _curr_data.detailed_voltages_cell_id+3; - CAN_util::enqueue_msg(&msg, &Pack_BMS_CELL_VOLTAGES_hytech, ACUCANBuffers::ccu_can_tx_buffer); + CAN_util::enqueue_msg(&detailed_msg, &Pack_BMS_DETAILED_VOLTAGES_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } -void CCUInterface::handle_enqueue_acu_cell_temps_CAN_message( - const celsius* cell_temps, - const size_t* temp_cells_per_chip, - const size_t num_of_chips -) { - BMS_CHIP_TEMPS_t chip_temps_msg = {}; - - chip_temps_msg.chip_id = static_cast(_curr_data.current_temp_group_chip_id); - chip_temps_msg.thermistor_group_id = static_cast(_curr_data.current_temp_group_id); - - size_t num_of_groups = temp_cells_per_chip[_curr_data.current_temp_group_chip_id] / _ccu_params.temp_cells_per_group; - size_t num_of_temp_cells = std::accumulate(temp_cells_per_chip, temp_cells_per_chip + num_of_chips, 0); - chip_temps_msg.thermistor_cell_group_temp_0_ro = HYTECH_thermistor_cell_group_temp_0_ro_toS(cell_temps[_curr_data.current_temp_cell_id]); - chip_temps_msg.thermistor_cell_group_temp_1_ro = HYTECH_thermistor_cell_group_temp_1_ro_toS(cell_temps[_curr_data.current_temp_cell_id + 1]); - - bool temp_cell_group_cycle_loop_completed = _increment_and_loop_id(_curr_data.current_temp_group_id, num_of_groups); - - if (temp_cell_group_cycle_loop_completed) _increment_and_loop_id(_curr_data.current_temp_group_chip_id, num_of_chips); - - _increment_and_loop_id(_curr_data.current_temp_cell_id, num_of_temp_cells, _ccu_params.temp_cells_per_group); - - CAN_util::enqueue_msg(&chip_temps_msg, &Pack_BMS_CHIP_TEMPS_hytech, ACUCANBuffers::ccu_can_tx_buffer); - - -} +void CCUInterface::handle_enqueue_acu_temps_CAN_message() { + BMS_DETAILED_TEMPS_t detailed_msg = {}; + detailed_msg.ic_id = static_cast(_curr_data.detailed_temps_ic_id); + detailed_msg.group_id = static_cast(_curr_data.detailed_temps_group_id); + detailed_msg.thermistor_id_0_ro = HYTECH_thermistor_id_0_ro_toS(_acu_all_data.cell_temps[_curr_data.detailed_temps_cell_id]); + detailed_msg.thermistor_id_1_ro = HYTECH_thermistor_id_1_ro_toS(_acu_all_data.cell_temps[_curr_data.detailed_temps_cell_id+1]); + detailed_msg.thermistor_id_2_ro = HYTECH_thermistor_id_2_ro_toS(_acu_all_data.cell_temps[_curr_data.detailed_temps_cell_id+2]); + + _curr_data.detailed_temps_group_id = (_curr_data.detailed_temps_group_id == 1) ? 0 : _curr_data.detailed_temps_group_id+1; + if (_curr_data.detailed_temps_group_id == 0) { + _curr_data.detailed_temps_ic_id = (_curr_data.detailed_temps_ic_id == (ccu_interface_defaults::NUM_CHIPS - 1)) ? 0 : _curr_data.detailed_temps_ic_id+1; + } + _curr_data.detailed_temps_cell_id = (_curr_data.detailed_temps_cell_id == (ccu_interface_defaults::NUM_CELLTEMPS - 3)) ? 0 : _curr_data.detailed_temps_cell_id+3; + CAN_util::enqueue_msg(&detailed_msg, &Pack_BMS_DETAILED_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); -void CCUInterface::handle_enqueue_acu_temp_statistics_CAN_message( - celsius max_board_temp, - celsius max_cell_temp, - celsius min_cell_temp -) { BMS_ONBOARD_TEMPS_t board_temp_msg = {}; - board_temp_msg.max_board_temp_ro = HYTECH_max_board_temp_ro_toS(max_board_temp); - board_temp_msg.max_cell_temp_ro = HYTECH_max_cell_temp_ro_toS(max_cell_temp); - board_temp_msg.min_cell_temp_ro = HYTECH_min_cell_temp_ro_toS(min_cell_temp); - CAN_util::enqueue_msg(&board_temp_msg, &Pack_BMS_ONBOARD_TEMPS_hytech, ACUCANBuffers::ccu_can_tx_buffer); -} + board_temp_msg.max_board_temp_ro = HYTECH_max_board_temp_ro_toS(_acu_all_data.core_data.max_board_temp); + board_temp_msg.high_cell_temp_ro = HYTECH_high_cell_temp_ro_toS(_acu_all_data.core_data.max_cell_temp); + board_temp_msg.low_cell_temp_ro = HYTECH_low_cell_temp_ro_toS(_acu_all_data.core_data.min_cell_temp); + CAN_util::enqueue_msg(&board_temp_msg, &Pack_BMS_ONBOARD_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); + + BMS_ONBOARD_DETAILED_TEMPS_t detailed_board_temp_msg = {}; + detailed_board_temp_msg.ic_id = _curr_data.detailed_temps_board_id; + detailed_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(_acu_all_data.board_temps[_curr_data.detailed_temps_board_id]); + _curr_data.detailed_temps_board_id = (_curr_data.detailed_temps_board_id == (ccu_interface_defaults::NUM_CHIPS - 1)) ? 0 : _curr_data.detailed_temps_board_id+1; + CAN_util::enqueue_msg(&detailed_board_temp_msg, &Pack_BMS_ONBOARD_DETAILED_TEMPS_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); +} -void CCUInterface::handle_enqueue_acu_cell_board_temps_CAN_message( - const celsius* board_temps, - const size_t num_of_boards -) { - BMS_ONBOARD_CURRENT_TEMP_t current_board_temp_msg = {}; - current_board_temp_msg.chip_id = _curr_data.current_temp_board_id; - current_board_temp_msg.temp_0_ro = HYTECH_temp_0_ro_toS(board_temps[_curr_data.current_temp_board_id]); - _increment_and_loop_id(_curr_data.current_temp_board_id, num_of_boards); - CAN_util::enqueue_msg(¤t_board_temp_msg, &Pack_BMS_ONBOARD_CURRENT_TEMP_hytech, ACUCANBuffers::ccu_can_tx_buffer); -} +void CCUInterface::set_system_latch_state(unsigned long curr_millis, bool is_latched) { + _curr_data.charging_requested = is_latched && ((curr_millis - _curr_data.last_time_charging_requested) < _ccu_params.min_charging_enable_threshold); +} -CCUCANInterfaceData_s CCUInterface::get_latest_data() { +CCUCANInterfaceData_s CCUInterface::get_latest_data(unsigned long curr_millis) { return _curr_data; } diff --git a/lib/interfaces/src/EMInterface.cpp b/lib/interfaces/src/EMInterface.cpp index 76827317..a4100a67 100644 --- a/lib/interfaces/src/EMInterface.cpp +++ b/lib/interfaces/src/EMInterface.cpp @@ -1,5 +1,5 @@ #include "EMInterface.h" -#include "ACUCANInterface.h" +#include "ACUCANInterfaceImpl.h" void EMInterface::receive_EM_measurement_message(const CAN_message_t &msg, uint32_t curr_millis) { EM_MEASUREMENT_t em_msg; diff --git a/lib/interfaces/src/SystemTimeInterface.cpp b/lib/interfaces/src/SystemTimeInterface.cpp index 0982341c..5775e599 100644 --- a/lib/interfaces/src/SystemTimeInterface.cpp +++ b/lib/interfaces/src/SystemTimeInterface.cpp @@ -13,14 +13,4 @@ namespace sys_time { return micros(); } - - unsigned long micros_to_millis(unsigned long micros) - { - return micros / MILLIS_TO_MICROS_FACTOR; - } - - unsigned long millis_to_micros(unsigned long millis) - { - return millis * MILLIS_TO_MICROS_FACTOR; - } } \ No newline at end of file diff --git a/lib/interfaces/src/VCRInterface.cpp b/lib/interfaces/src/VCRInterface.cpp index 4bb91303..a0222e85 100644 --- a/lib/interfaces/src/VCRInterface.cpp +++ b/lib/interfaces/src/VCRInterface.cpp @@ -1,7 +1,6 @@ #include "VCRInterface.h" -#include "ACUCANBuffers.h" -#include "ACUCANInterface.h" +#include "ACUCANInterfaceImpl.h" void VCRInterface::set_monitoring_data(bool imd_ok, bool bms_ok, bool latch_ok) { _curr_data.imd_ok = imd_ok; @@ -15,5 +14,5 @@ void VCRInterface::handle_enqueue_acu_ok_CAN_message() msg.imd_ok = _curr_data.imd_ok; msg.bms_ok = _curr_data.bms_ok; msg.latch_ok = _curr_data.latch_ok; - CAN_util::enqueue_msg(&msg, &Pack_ACU_OK_hytech, ACUCANBuffers::ccu_can_tx_buffer); + CAN_util::enqueue_msg(&msg, &Pack_ACU_OK_hytech, ACUCANInterfaceImpl::ccu_can_tx_buffer); } \ No newline at end of file diff --git a/lib/shared_types/shared_types.h b/lib/shared_types/shared_types.h index 0189ab37..f876fc3f 100644 --- a/lib/shared_types/shared_types.h +++ b/lib/shared_types/shared_types.h @@ -3,61 +3,19 @@ #include "SharedFirmwareTypes.h" +template struct BMSCoreData_s { volt min_cell_voltage; volt max_cell_voltage; volt pack_voltage; + std::array voltages; celsius max_cell_temp; celsius min_cell_temp; celsius max_board_temp; + size_t max_consecutive_invalid_packet_count; + bool charging_enabled; }; -/** - * CurrentReadGroup_e - State machine for incremental BMS register group reading - * - * This enum defines the 6-state read cycle used to distribute voltage and GPIO readings - * across multiple read_data() calls. Instead of reading all registers at once (which takes - * significant time), each call reads ONE register group, cycling through all 6 groups. - * - * STATE MACHINE CYCLE: - * - * Call 1 → CURRENT_GROUP_A → Read cells 0-2 (CV Group A) - * Call 2 → CURRENT_GROUP_B → Read cells 3-5 (CV Group B) - * Call 3 → CURRENT_GROUP_C → Read cells 6-8 (CV Group C) - * Call 4 → CURRENT_GROUP_D → Read cells 9-11 (CV Group D) [9-cell chips: skip] - * Call 5 → CURRENT_GROUP_AUX_A → Read GPIO 0-2 (Aux Group A: thermistors 0-2) - * Call 6 → CURRENT_GROUP_AUX_B → Read GPIO 3-5 (Aux Group B: thermistors 3-4, board temp) - * [GOTO Call 1] - * - * HARDWARE MAPPING: - * - Each LTC6811 chip has 12 cell voltage registers divided into 4 groups (A-D) - * - Each group contains 3 consecutive cell readings (6 bytes = 3 × 16-bit values) - * - GPIO registers are divided into 2 groups (AUX_A, AUX_B) - * - GPIO 0-3: Cell thermistors (temperature sensors) - * - GPIO 4: Board temperature sensor (MCP9701) - * - GPIO 5: Not used (padding in AUX_B) - * - * TIMING & FREQUENCY: - * - Original (main): Read all 6 groups at 50 Hz (20ms period) - * - Optimized (this branch): Read 1 group per call at 300 Hz (3ms period) - * - Effective sampling rate per cell: 300 Hz / 6 groups = 50 Hz (same as before) - * - * CHIP ARCHITECTURE NOTES: - * - System has 12 ICs total in pairs: 6 × (12-cell + 9-cell) = 126 cells total - * - Even-indexed chips (0, 2, 4, 6, 8, 10): 12 cells each - * - Odd-indexed chips (1, 3, 5, 7, 9, 11): 9 cells each - * - For 9-cell chips, GROUP_D read is skipped (no cells 10-12) - * - * VALIDATION: - * Each group read has its own validity flag in ValidPacketData_s: - * - CURRENT_GROUP_A → valid_read_cells_1_to_3 - * - CURRENT_GROUP_B → valid_read_cells_4_to_6 - * - CURRENT_GROUP_C → valid_read_cells_7_to_9 - * - CURRENT_GROUP_D → valid_read_cells_10_to_12 - * - CURRENT_GROUP_AUX_A → valid_read_gpios_1_to_3 - * - CURRENT_GROUP_AUX_B → valid_read_gpios_4_to_6 - */ - enum ReadGroup_e { CV_GROUP_A = 0, CV_GROUP_B, CV_GROUP_C, CV_GROUP_D, AUX_GROUP_A, AUX_GROUP_B, NUM_GROUPS diff --git a/lib/systems/include/ACUController.h b/lib/systems/include/ACUController.h index e6f4fc1b..9263baf0 100644 --- a/lib/systems/include/ACUController.h +++ b/lib/systems/include/ACUController.h @@ -21,6 +21,7 @@ namespace acu_controller_default_parameters constexpr const float PACK_MIN_VOLTAGE = 378.0; // from data sheet^ but just assume 126 * 3.0V constexpr const float PACK_INTERNAL_RESISTANCE = 0.246; // Ohms (measured) } +template struct ACUControllerData_s { time_ms last_time_uv_fault_not_present; @@ -37,11 +38,11 @@ struct ACUControllerData_s uint32_t last_bms_not_ok_eval; bool charging_enabled; bool balancing_enabled; + std::array cell_balancing_statuses; }; struct ACUControllerThresholds_s { - volt min_discharge_voltage_thresh = 0; volt cell_overvoltage_thresh_v = 0; volt cell_undervoltage_thresh_v = 0; celsius charging_ot_thresh_c = 0; @@ -64,7 +65,6 @@ struct ACUControllerPackSpecs_s float pack_nominal_capacity = 0; float pack_max_voltage = 0; float pack_min_voltage = 0; - float pack_internal_resistance = 0; }; struct ACUControllerParameters_s @@ -74,9 +74,11 @@ struct ACUControllerParameters_s ACUControllerFaultDurations_s fault_durations; ACUControllerPackSpecs_s pack_specs; }; +template class ACUController { - // using ACUData = etl::singleton>; + using ACUData = etl::singleton>; + using ACUStatus = ACUControllerData_s; public: /** @@ -98,9 +100,8 @@ class ACUController ACUControllerPackSpecs_s pack_specs = { .pack_nominal_capacity = acu_controller_default_parameters::PACK_NOMINAL_CAPACITY_AH, .pack_max_voltage = acu_controller_default_parameters::PACK_MAX_VOLTAGE, - .pack_min_voltage = acu_controller_default_parameters::PACK_MIN_VOLTAGE, - .pack_internal_resistance = acu_controller_default_parameters::PACK_INTERNAL_RESISTANCE - }) : _acu_parameters{thresholds, invalid_packet_count_thresh, fault_durations, pack_specs} {}; + .pack_min_voltage = acu_controller_default_parameters::PACK_MIN_VOLTAGE} + ) : _acu_parameters{thresholds, invalid_packet_count_thresh, fault_durations, pack_specs} {}; /** * @brief Initialize the status time stamps because we don't want accidental sudden faults @@ -112,21 +113,14 @@ class ACUController * @post updates configuration bytes and sends configuration command * @param pack_current current flowing from the pack in amps (negative during discharge, positive during charge) */ - ACUControllerData_s evaluate_accumulator(time_ms current_millis, const BMSCoreData_s &bms_core_data, size_t max_consecutive_invalid_packet_count, float em_current, size_t num_of_voltage_cells); - - /** - * Calculate Cell Balancing values - * @pre cell charging is enabled - * @post output will have the new values - */ - void calculate_cell_balance_statuses(bool* output, const volt* voltages, size_t num_of_voltage_cells, volt min_voltage); + ACUStatus evaluate_accumulator(time_ms current_millis, const BMSCoreData_s &input_state, float em_current); /** * @return state of charge - float from 0.0 to 1.0, representing a percentage from 0 to 100% */ float get_state_of_charge(float em_current, uint32_t delta_time_ms); - ACUControllerData_s get_status() const { return _acu_state; }; + ACUStatus get_status() const { return _acu_state; }; void enableCharging() { @@ -137,6 +131,12 @@ class ACUController _acu_state.charging_enabled = false; } private: + /** + * Calculate Cell Balancing values + * @pre cell charging is enabled + * @post _acu_state.cell_balance_statuses will have the new values + */ + std::array _calculate_cell_balance_statuses(std::array voltages, volt min_voltage); /** * @pre data has been gathered @@ -166,25 +166,27 @@ class ACUController bool _check_invalid_packet_faults(time_ms current_millis); private: - + /** + * @brief Internal resistance per cell (computed from pack resistance divided by number of cells) + */ + static constexpr float CELL_INTERNAL_RESISTANCE = acu_controller_default_parameters::PACK_INTERNAL_RESISTANCE / static_cast(num_cells); /** * @brief ACU State Holder * Most importantly, holding the current cell balances, fault counters, and watchdog HIGH?LOW - * state is packaged this way so that we ican feed it directly into the message interface as a struct + * state is packaged this way so that we can feed it directly into the message interface as a struct */ - ACUControllerData_s _acu_state = {}; + ACUStatus _acu_state = {}; static constexpr uint32_t _bms_not_ok_hold_time_ms = 1000; - static constexpr float _hours_to_ms_factor = 3600000.0f; // hours to milliseconds - - /** * @brief ACU Controller Parameters holder */ const ACUControllerParameters_s _acu_parameters = {}; }; -using ACUControllerInstance = etl::singleton; +template +using ACUControllerInstance = etl::singleton>; +#include "ACUController.tpp" #endif \ No newline at end of file diff --git a/lib/systems/src/ACUController.cpp b/lib/systems/include/ACUController.tpp similarity index 67% rename from lib/systems/src/ACUController.cpp rename to lib/systems/include/ACUController.tpp index 34fe9913..456e11a3 100644 --- a/lib/systems/src/ACUController.cpp +++ b/lib/systems/include/ACUController.tpp @@ -1,7 +1,7 @@ #include "ACUController.h" - -void ACUController::init(time_ms system_start_time, volt pack_voltage) +template +void ACUController::init(time_ms system_start_time, volt pack_voltage) { _acu_state.last_time_ov_fault_not_present = system_start_time; _acu_state.last_time_uv_fault_not_present = system_start_time; @@ -10,25 +10,25 @@ void ACUController::init(time_ms system_start_time, volt pack_voltage) _acu_state.last_time_pack_uv_fault_not_present = system_start_time; _acu_state.last_time_invalid_packet_present = system_start_time; _acu_state.prev_bms_time_stamp = system_start_time; - _acu_state.SoC = (pack_voltage <= _acu_parameters.pack_specs.pack_min_voltage) ? 0.0f : ((pack_voltage - _acu_parameters.pack_specs.pack_min_voltage) / (_acu_parameters.pack_specs.pack_max_voltage - _acu_parameters.pack_specs.pack_min_voltage)); + _acu_state.SoC = (pack_voltage <= _acu_parameters.pack_specs.pack_min_voltage) ? 0.0 : ((pack_voltage - _acu_parameters.pack_specs.pack_min_voltage) / (_acu_parameters.pack_specs.pack_max_voltage - _acu_parameters.pack_specs.pack_min_voltage)); _acu_state.balancing_enabled = false; } - -ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, const BMSCoreData_s &input_state, size_t max_consecutive_invalid_packet_count, float em_current, size_t num_of_voltage_cells) +template +typename ACUController::ACUStatus +ACUController::evaluate_accumulator(time_ms current_millis, const BMSCoreData_s &input_state, float em_current) { // _acu_state.charging_enabled = input_state.charging_enabled; bool has_invalid_packet = false; - if (max_consecutive_invalid_packet_count != 0) + if (input_state.max_consecutive_invalid_packet_count != 0) { // meaning that at least one of the packets is invalid has_invalid_packet = true; } _acu_state.SoC = get_state_of_charge(em_current, current_millis - _acu_state.prev_bms_time_stamp); // Cell balancing calculations - bool previously_balancing = _acu_state.balancing_enabled; bool balance_enableable = ((previously_balancing && (input_state.max_board_temp < _acu_parameters.thresholds.balance_temp_limit_c)) || @@ -39,12 +39,12 @@ ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, if (allow_balancing) { _acu_state.balancing_enabled = true; - // _acu_state.cell_balancing_statuses = _calculate_cell_balance_statuses(input_state.voltages, input_state.min_cell_voltage); + _acu_state.cell_balancing_statuses = _calculate_cell_balance_statuses(input_state.voltages, input_state.min_cell_voltage); } else { // Fill with zeros, no balancing _acu_state.balancing_enabled = false; - // _acu_state.cell_balancing_statuses.fill(0); + _acu_state.cell_balancing_statuses.fill(0); } // Update voltage fault time stamps with IR compensation @@ -56,7 +56,7 @@ ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, if (input_state.max_cell_voltage >= _acu_parameters.thresholds.cell_overvoltage_thresh_v) { // Only calculate IR compensation when approaching OV threshold - internal_resistance_max_cell_voltage = input_state.max_cell_voltage + (_acu_parameters.pack_specs.pack_internal_resistance / static_cast(num_of_voltage_cells) * discharge_current); + internal_resistance_max_cell_voltage = input_state.max_cell_voltage + (CELL_INTERNAL_RESISTANCE * discharge_current); } if (internal_resistance_max_cell_voltage < _acu_parameters.thresholds.cell_overvoltage_thresh_v || has_invalid_packet) { @@ -68,7 +68,7 @@ ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, if (input_state.min_cell_voltage <= _acu_parameters.thresholds.cell_undervoltage_thresh_v) { // Only calculate IR compensation when approaching UV threshold - min_cell_voltage_to_check = input_state.min_cell_voltage + (_acu_parameters.pack_specs.pack_internal_resistance / static_cast(num_of_voltage_cells) * discharge_current); + min_cell_voltage_to_check = input_state.min_cell_voltage + (CELL_INTERNAL_RESISTANCE * discharge_current); } if (min_cell_voltage_to_check > _acu_parameters.thresholds.cell_undervoltage_thresh_v || has_invalid_packet) { @@ -88,7 +88,7 @@ ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, { _acu_state.last_time_cell_ot_fault_not_present = current_millis; } - if (max_consecutive_invalid_packet_count < _acu_parameters.invalid_packet_count_thresh) + if (input_state.max_consecutive_invalid_packet_count < _acu_parameters.invalid_packet_count_thresh) { _acu_state.last_time_invalid_packet_present = current_millis; } @@ -105,27 +105,26 @@ ACUControllerData_s ACUController::evaluate_accumulator(time_ms current_millis, } - -void ACUController::calculate_cell_balance_statuses(bool* output, const volt* voltages, size_t num_of_voltage_cells, volt min_voltage) +template +std::array ACUController::_calculate_cell_balance_statuses(std::array voltages, volt min_voltage) { - for (size_t cell = 0; cell < num_of_voltage_cells; cell++) + std::array cb = {false}; + const volt min_discharge_voltage_thresh = 3.8F; + for (size_t cell = 0; cell < num_cells; cell++) { volt cell_voltage = voltages[cell]; - if ((cell_voltage-min_voltage > _acu_parameters.thresholds.v_diff_to_init_cb) && (cell_voltage > _acu_parameters.thresholds.min_discharge_voltage_thresh)) // && max_voltage - (cell_voltage) < 200 && + if (((cell_voltage)-min_voltage > _acu_parameters.thresholds.v_diff_to_init_cb) && (cell_voltage > min_discharge_voltage_thresh)) // && max_voltage - (cell_voltage) < 200 && { - output[cell] = true; - } else - { - output[cell] = false; + cb[cell] = true; } } + return cb; } - -float ACUController::get_state_of_charge(float em_current, uint32_t delta_time_ms) -{ - - float delta_ah = (em_current) * ((float)(delta_time_ms) / _hours_to_ms_factor); // amp hours +template +float ACUController::get_state_of_charge(float em_current, uint32_t delta_time_ms) +{ + float delta_ah = (em_current) * ((float)(delta_time_ms / 1000.0f) / 3600.0f); // amp hours _acu_state.SoC += delta_ah / _acu_parameters.pack_specs.pack_nominal_capacity; // should be -= but EM inverted if (_acu_state.SoC < 0.0) _acu_state.SoC = 0; @@ -134,8 +133,8 @@ float ACUController::get_state_of_charge(float em_current, uint32_t delta_time_m return _acu_state.SoC; } - -bool ACUController::_check_bms_ok(time_ms current_millis) +template +bool ACUController::_check_bms_ok(time_ms current_millis) { if (_acu_state.has_fault) { _acu_state.bms_ok = !_acu_state.has_fault; @@ -146,14 +145,14 @@ bool ACUController::_check_bms_ok(time_ms current_millis) return _acu_state.bms_ok; } - -bool ACUController::_check_faults(time_ms current_millis) +template +bool ACUController::_check_faults(time_ms current_millis) { return _check_voltage_faults(current_millis) || _check_temperature_faults(current_millis) || _check_invalid_packet_faults(current_millis); } - -bool ACUController::_check_voltage_faults(time_ms current_millis) +template +bool ACUController::_check_voltage_faults(time_ms current_millis) { bool ov_fault = (current_millis - _acu_state.last_time_ov_fault_not_present) > _acu_parameters.fault_durations.max_allowed_voltage_fault_dur; bool uv_fault = (current_millis - _acu_state.last_time_uv_fault_not_present) > _acu_parameters.fault_durations.max_allowed_voltage_fault_dur; @@ -161,16 +160,16 @@ bool ACUController::_check_voltage_faults(time_ms current_millis) return ov_fault || uv_fault || pack_fault; } - -bool ACUController::_check_temperature_faults(time_ms current_millis) +template +bool ACUController::_check_temperature_faults(time_ms current_millis) { bool cell_ot_fault = (current_millis - _acu_state.last_time_cell_ot_fault_not_present) > _acu_parameters.fault_durations.max_allowed_temp_fault_dur; bool board_ot_fault = (current_millis - _acu_state.last_time_board_ot_fault_not_present) > _acu_parameters.fault_durations.max_allowed_temp_fault_dur; return cell_ot_fault || board_ot_fault; } - -bool ACUController::_check_invalid_packet_faults(time_ms current_millis) +template +bool ACUController::_check_invalid_packet_faults(time_ms current_millis) { bool invalid_packet_fault = (current_millis - _acu_state.last_time_invalid_packet_present) > _acu_parameters.fault_durations.max_allowed_invalid_packet_fault_dur; return invalid_packet_fault; diff --git a/platformio.ini b/platformio.ini index 1cd64899..bb64b605 100644 --- a/platformio.ini +++ b/platformio.ini @@ -75,7 +75,7 @@ test_ignore = lib_deps= ${common.lib_deps_shared} https://github.com/ssilverman/QNEthernet#v0.26.0 - https://github.com/hytech-racing/HT_CAN/releases/download/209/can_lib.tar.gz + https://github.com/hytech-racing/HT_CAN/releases/download/192/can_lib.tar.gz https://github.com/hytech-racing/HT_SCHED.git https://github.com/hytech-racing/HT_proto/releases/download/2025-08-27T15_34_50/hytech_msgs_pb_lib.tar.gz https://github.com/hytech-racing/shared_firmware_interfaces.git#5baf17a0f6d83d0a9d571d6bf56f409d2c8ad98a @@ -113,10 +113,10 @@ test_ignore = lib_deps= ${common.lib_deps_shared} https://github.com/ssilverman/QNEthernet#v0.26.0 - https://github.com/hytech-racing/HT_CAN/releases/download/209/can_lib.tar.gz + https://github.com/hytech-racing/HT_CAN/releases/download/192/can_lib.tar.gz https://github.com/hytech-racing/HT_SCHED.git https://github.com/hytech-racing/HT_proto/releases/download/2025-08-27T15_34_50/hytech_msgs_pb_lib.tar.gz - https://github.com/hytech-racing/shared_firmware_interfaces.git#5baf17a0f6d83d0a9d571d6bf56f409d2c8ad98a + https://github.com/hytech-racing/shared_firmware_interfaces.git https://github.com/KSU-MS/pio-git-hash-gen#7998b5b3f8a2464209b0e73338717998bcf511ee Nanopb arkhipenko/TaskScheduler@^3.8.5 diff --git a/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index 53b33ce0..0db1f5c9 100644 --- a/src/ACU_InterfaceTasks.cpp +++ b/src/ACU_InterfaceTasks.cpp @@ -44,7 +44,7 @@ static ACUAllDataType_s make_acu_all_data() out.core_data.min_measured_ts_out_voltage = watchdog.min_measured_ts_out_voltage; out.core_data.min_shdn_out_voltage = watchdog.min_shdn_out_voltage; // SoC/SoH placeholders (leave unchanged here) - out.SoC = ACUControllerInstance::instance().get_status().SoC; + out.SoC = ACUControllerInstance_t::instance().get_status().SoC; return out; } @@ -55,6 +55,7 @@ void initialize_all_interfaces() SPI.setClockDivider(SPI_CLOCK_DIV8); // 16MHz (Arduino Clock Frequency) / 8 = 2MHz -> SPI Clock Serial.begin(ACUInterfaces::SERIAL_BAUDRATE); analogReadResolution(ACUInterfaces::ANALOG_READ_RESOLUTION); + /* Watchdog Interface */ WatchdogInstance::create(WatchdogPinout_s {ACUInterfaces::TEENSY_OK_PIN, ACUInterfaces::WD_KICK_PIN, @@ -66,7 +67,7 @@ void initialize_all_interfaces() FaultLatchManagerInstance::instance().set_shdn_out_latched(true); // Start shdn out latch cleared /* BMS Driver */ - BMSDriverInstance_t::create(ACUConstants::BMS_CHIP_SELECTS); + BMSDriverInstance_t::create(); BMSDriverInstance_t::instance().init(); /* Get Initial Pack Voltage for SoC and SoH Approximations */ auto data = BMSDriverInstance_t::instance().read_data(); @@ -118,18 +119,14 @@ HT_TASK::TaskResponse sample_bms_data(const unsigned long &sysMicros, const HT_T { auto data = BMSDriverInstance_t::instance().read_data(); BMSFaultDataManagerInstance_t::instance().update_from_valid_packets(data.valid_read_packets); - // print_bms_data(data); - /* Store into ACUCoreDataInstance */ + return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse write_cell_balancing_config(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - - auto data = BMSDriverInstance_t::instance().get_bms_data(); - static std::array cell_balancing_statuses; - ACUControllerInstance::instance().calculate_cell_balance_statuses(cell_balancing_statuses.data(), data.voltages.data(), ACUConstants::NUM_VOLTAGE_CELLS, data.min_cell_voltage); + auto cell_balancing_statuses = ACUControllerInstance_t::instance().get_status().cell_balancing_statuses; BMSDriverInstance_t::instance().write_configuration(cell_balancing_statuses.data(), cell_balancing_statuses.size()); return HT_TASK::TaskResponse::YIELD; } @@ -157,63 +154,49 @@ HT_TASK::TaskResponse handle_send_ACU_all_ethernet_data(const unsigned long &sys HT_TASK::TaskResponse handle_send_all_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - ACUCANInterface::send_all_CAN_msgs(ACUCANBuffers::ccu_can_tx_buffer, &ACUCANInterface::CCU_CAN); + CCUInterfaceInstance::instance().set_system_latch_state(sys_time::hal_millis(), ADCInterfaceInstance::instance().read_shdn_out()); + ACUCANInterfaceImpl::send_all_CAN_msgs(ACUCANInterfaceImpl::ccu_can_tx_buffer, &ACUCANInterfaceImpl::CCU_CAN); return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse enqueue_ACU_ok_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { FaultLatchManagerInstance::instance().clear_if_not_faulted(ACUStateMachineInstance::instance().get_state() == ACUState_e::FAULTED); - FaultLatchManagerInstance::instance().update_imd_and_bms_latches(ACUControllerInstance::instance().get_status().bms_ok, ADCInterfaceInstance::instance().read_imd_ok(sys_time::hal_millis())); + FaultLatchManagerInstance::instance().update_imd_and_bms_latches(ADCInterfaceInstance::instance().read_imd_ok(sys_time::hal_millis()), ACUControllerInstance_t::instance().get_status().bms_ok); //TODO: Where should I get veh_shdn_out_latched from? VCRInterfaceInstance::instance().set_monitoring_data(!FaultLatchManagerInstance::instance().get_latches().imd_fault_latched, !FaultLatchManagerInstance::instance().get_latches().bms_fault_latched, FaultLatchManagerInstance::instance().get_latches().shdn_out_latched); VCRInterfaceInstance::instance().handle_enqueue_acu_ok_CAN_message(); - - //TODO: Put this in fault manager - // Reset shdn out latch state - // ACUDataInstance::instance().veh_shdn_out_latched = true; return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse enqueue_ACU_core_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); - CCUInterfaceInstance::instance().handle_enqueue_acu_status_CAN_message(ACUControllerInstance::instance().get_status().charging_enabled); - CCUInterfaceInstance::instance().handle_enqueue_acu_voltage_statistics_CAN_message( - bms_data.max_cell_voltage, - bms_data.min_cell_voltage, - bms_data.total_voltage, - bms_data.avg_cell_voltage - ); - CCUInterfaceInstance::instance().handle_enqueue_acu_temp_statistics_CAN_message( - bms_data.max_board_temp, - bms_data.max_cell_temp, - bms_data.min_cell_temp - ); + auto data = make_acu_all_data(); + CCUInterfaceInstance::instance().set_ACU_data(data); + CCUInterfaceInstance::instance().handle_enqueue_acu_status_CAN_message(); + CCUInterfaceInstance::instance().handle_enqueue_acu_core_voltages_CAN_message(); return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse enqueue_ACU_all_voltages_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); - if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance::instance().handle_enqueue_acu_cell_voltages_CAN_message(bms_data.voltages.data(), ACUConstants::VOLTAGE_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_CHIP_SELECT); + if (CCUInterfaceInstance::instance().is_connected_to_CCU()) { + CCUInterfaceInstance::instance().handle_enqueue_acu_voltages_CAN_message(); } return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse enqueue_ACU_all_temps_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - auto bms_data = BMSDriverInstance_t::instance().get_bms_data(); - if (CCUInterfaceInstance::instance().is_connected_to_CCU(sys_time::micros_to_millis(sysMicros))) { - CCUInterfaceInstance::instance().handle_enqueue_acu_cell_temps_CAN_message(bms_data.cell_temperatures.data(), ACUConstants::TEMP_CELLS_PER_CHIP.data(), ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_CHIP_SELECT); + if (CCUInterfaceInstance::instance().is_connected_to_CCU()) { + CCUInterfaceInstance::instance().handle_enqueue_acu_temps_CAN_message(); } return HT_TASK::TaskResponse::YIELD; } HT_TASK::TaskResponse sample_CAN_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { - etl::delegate main_can_recv = etl::delegate::create(); - process_ring_buffer(ACUCANBuffers::ccu_can_rx_buffer, CANInterfacesInstance::instance(), sys_time::hal_millis(), main_can_recv); - process_ring_buffer(ACUCANBuffers::em_can_rx_buffer, CANInterfacesInstance::instance(), sys_time::hal_millis(), main_can_recv); + etl::delegate main_can_recv = etl::delegate::create(); + process_ring_buffer(ACUCANInterfaceImpl::ccu_can_rx_buffer, CANInterfacesInstance::instance(), sys_time::hal_millis(), main_can_recv); + process_ring_buffer(ACUCANInterfaceImpl::em_can_rx_buffer, CANInterfacesInstance::instance(), sys_time::hal_millis(), main_can_recv); return HT_TASK::TaskResponse::YIELD; } @@ -246,7 +229,7 @@ void print_bms_data(bms_data data) Serial.println(data.max_cell_voltage_id); Serial.print("Average Voltage: "); - Serial.print(data.total_voltage / ACUConstants::NUM_VOLTAGE_CELLS, 4); + Serial.print(data.total_voltage / ACUConstants::NUM_CELLS, 4); Serial.println("V"); Serial.println(); @@ -322,7 +305,7 @@ void print_bms_data(bms_data data) HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - if (ACUControllerInstance::instance().get_status().bms_ok) + if (ACUControllerInstance_t::instance().get_status().bms_ok) { Serial.print("BMS is OK\n"); } @@ -361,15 +344,15 @@ HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK: Serial.print("Maximum Cell Temp: "); Serial.println(BMSDriverInstance_t::instance().get_bms_data().max_cell_temp, 4); - // Serial.printf("Cell Balance Statuses: %d\n", ACUControllerInstance::instance().calculate_cell_balance_statuses()); + Serial.printf("Cell Balance Statuses: %d\n", ACUControllerInstance_t::instance().get_status().cell_balancing_statuses); Serial.print("ACU State: "); Serial.println(static_cast(ACUStateMachineInstance::instance().get_state())); Serial.print("CCU Charging Requested? : "); - Serial.println(CCUInterfaceInstance::instance().is_charging_with_balancing_requested(sys_time::hal_millis()) ? "YES" : "NO"); + Serial.println(CCUInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).charging_requested); Serial.print("State of Charge: "); - Serial.print(ACUControllerInstance::instance().get_status().SoC * 100, 3); + Serial.print(ACUControllerInstance_t::instance().get_status().SoC * 100, 3); Serial.println("%"); Serial.print("Measured GLV: "); Serial.println("V"); diff --git a/src/ACU_SystemTasks.cpp b/src/ACU_SystemTasks.cpp index f8d90274..fe63bc10 100644 --- a/src/ACU_SystemTasks.cpp +++ b/src/ACU_SystemTasks.cpp @@ -3,8 +3,7 @@ bool initialize_all_systems() { // Initialize the ACU Controller - ACUControllerInstance::create(ACUControllerThresholds_s{ ACUSystems::MIN_DISCHARGE_VOLTAGE_THRESH, - ACUSystems::CELL_OVERVOLTAGE_THRESH, + ACUControllerInstance_t::create(ACUControllerThresholds_s{ACUSystems::CELL_OVERVOLTAGE_THRESH, ACUSystems::CELL_UNDERVOLTAGE_THRESH, ACUSystems::CHARGING_OT_THRESH, ACUSystems::RUNNING_OT_THRESH, @@ -12,15 +11,15 @@ bool initialize_all_systems() ACUSystems::VOLTAGE_DIFF_TO_INIT_CB, ACUSystems::BALANCE_TEMP_LIMIT_C, ACUSystems::BALANCE_ENABLE_TEMP_THRESH_C}); - ACUControllerInstance::instance().init(sys_time::hal_millis(), BMSDriverInstance_t::instance().get_bms_data().total_voltage); + ACUControllerInstance_t::instance().init(sys_time::hal_millis(), BMSDriverInstance_t::instance().get_bms_data().total_voltage); /* State Machine Initialization */ /* Delegate Function Definitions */ etl::delegate charge_state_request = etl::delegate::create([]() -> bool - { return CCUInterfaceInstance::instance().is_charging_with_balancing_requested(sys_time::hal_millis()); }); + { return CCUInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).charging_requested; }); etl::delegate has_bms_fault = etl::delegate::create([]() -> bool - { return !ACUControllerInstance::instance().get_status().bms_ok; }); + { return !ACUControllerInstance_t::instance().get_status().bms_ok; }); etl::delegate has_imd_fault = etl::delegate::create([]() -> bool { return !ADCInterfaceInstance::instance().read_imd_ok(sys_time::hal_millis()); }); @@ -28,10 +27,10 @@ bool initialize_all_systems() etl::delegate received_valid_shdn_out = etl::delegate::create(ADCInterfaceInstance::instance()); etl::delegate enable_cell_balancing = etl::delegate::create([]() -> void - { ACUControllerInstance::instance().enableCharging(); }); + { ACUControllerInstance_t::instance().enableCharging(); }); etl::delegate disable_cell_balancing = etl::delegate::create([]() -> void - { ACUControllerInstance::instance().disableCharging(); }); + { ACUControllerInstance_t::instance().disableCharging(); }); etl::delegate disable_watchdog = etl::delegate::create(WatchdogInstance::instance()); etl::delegate reinitialize_watchdog = etl::delegate::create(WatchdogInstance::instance()); @@ -57,12 +56,10 @@ bool initialize_all_systems() HT_TASK::TaskResponse evaluate_accumulator(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { - ACUControllerInstance::instance().evaluate_accumulator( + ACUControllerInstance_t::instance().evaluate_accumulator( sys_time::hal_millis(), BMSDriverInstance_t::instance().get_bms_core_data(), - BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count, - EMInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).em_current, - ACUConstants::NUM_VOLTAGE_CELLS + EMInterfaceInstance::instance().get_latest_data(sys_time::hal_millis()).em_current ); return HT_TASK::TaskResponse::YIELD; } diff --git a/src/main.cpp b/src/main.cpp index 2faa4a56..48754f87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,7 @@ #include #include "BMSDriverGroup.h" #include "WatchdogInterface.h" -#include "ACUCANInterface.h" +#include "ACUCANInterfaceImpl.h" /* System Includes */ #include "ACUController.h" @@ -37,6 +37,9 @@ ::HT_TASK::Task sample_CAN_task(HT_TASK::DUMMY_FUNCTION, sample_CAN_data, ACUCon ::HT_TASK::Task idle_sample_task(HT_TASK::DUMMY_FUNCTION, idle_sample_interfaces, ACUConstants::IDLE_SAMPLE_PRIORITY, ACUConstants::IDLE_SAMPLE_PERIOD_US); ::HT_TASK::Task debug_prints_task(HT_TASK::DUMMY_FUNCTION, debug_print, ACUConstants::DEBUG_PRINT_PRIORITY, ACUConstants::DEBUG_PRINT_PERIOD_US); +FlexCAN_t ACUCANInterfaceImpl::CCU_CAN; +FlexCAN_t ACUCANInterfaceImpl::EM_CAN; + void setup() { /* Interface and System initialization */ @@ -64,8 +67,8 @@ void setup() //scheduler.schedule(debug_prints_task); - handle_CAN_setup(ACUCANInterface::CCU_CAN, ACUConstants::Veh_CAN_baudrate, &ACUCANInterface::on_ccu_can_receive); - handle_CAN_setup(ACUCANInterface::EM_CAN, ACUConstants::EM_CAN_baudrate, &ACUCANInterface::on_em_can_receive); + handle_CAN_setup(ACUCANInterfaceImpl::CCU_CAN, ACUConstants::Veh_CAN_baudrate, &ACUCANInterfaceImpl::on_ccu_can_receive); + handle_CAN_setup(ACUCANInterfaceImpl::EM_CAN, ACUConstants::EM_CAN_baudrate, &ACUCANInterfaceImpl::on_em_can_receive); } void loop() diff --git a/src/main_spi_test.cpp b/src/main_spi_test.cpp index 6258eabf..f1722a22 100644 --- a/src/main_spi_test.cpp +++ b/src/main_spi_test.cpp @@ -55,7 +55,7 @@ uint32_t cycle_count = 0; bool cycle_complete = false; template -void print_voltages(driver_data data, uint32_t read_duration_us, CurrentReadGroup_e current_group) +void print_voltages(driver_data data, uint32_t read_duration_us, ReadGroup_e current_group) { Serial.println("========================================"); Serial.print("Read Group: "); @@ -327,7 +327,7 @@ void loop() timer = 0; // Get the group that WILL BE read by this call - CurrentReadGroup_e group_before_read = BMSGroup.get_current_read_group(); + ReadGroup_e group_before_read = BMSGroup.get_current_read_group(); uint32_t group_index = static_cast(group_before_read); // Start timing the read @@ -350,7 +350,7 @@ void loop() } // Detect cycle completion: we just read AUX_B and driver advanced back to GROUP_A - cycle_complete = (group_before_read == CurrentReadGroup_e::AUX_GROUP_B); + cycle_complete = (group_before_read == ReadGroup_e::AUX_GROUP_B); if (cycle_complete) { cycle_count++; } @@ -364,8 +364,8 @@ void loop() } // Verify state machine advanced correctly - CurrentReadGroup_e expected_next = advance_read_group(group_before_read); - CurrentReadGroup_e actual_next = BMSGroup.get_current_read_group(); + ReadGroup_e expected_next = advance_read_group(group_before_read); + ReadGroup_e actual_next = BMSGroup.get_current_read_group(); if (expected_next != actual_next) { Serial.println("*** ERROR: State machine did not advance correctly! ***"); Serial.print("Expected: "); diff --git a/test/test_systems/test_acu_controller.h b/test/test_systems/test_acu_controller.h index 95b7538d..e3499433 100644 --- a/test/test_systems/test_acu_controller.h +++ b/test/test_systems/test_acu_controller.h @@ -6,35 +6,35 @@ #include "ACU_Constants.h" #include "shared_types.h" -constexpr size_t num_cells = 12; // local test convenience +constexpr size_t num_cells = 12; +constexpr size_t num_chips = 1; +constexpr size_t num_cell_temps = 4; +constexpr size_t num_board_temps = 1; bool charging_enabled; constexpr float ZERO_PACK_CURRENT = 0.0f; // No current flow (idle state) -ACUControllerThresholds_s thresholds = {ACUSystems::MIN_DISCHARGE_VOLTAGE_THRESH, - ACUSystems::CELL_OVERVOLTAGE_THRESH, +ACUControllerThresholds_s thresholds = {ACUSystems::CELL_OVERVOLTAGE_THRESH, ACUSystems::CELL_UNDERVOLTAGE_THRESH, ACUSystems::CHARGING_OT_THRESH, ACUSystems::RUNNING_OT_THRESH, ACUSystems::MIN_PACK_TOTAL_VOLTAGE, ACUSystems::VOLTAGE_DIFF_TO_INIT_CB, ACUSystems::BALANCE_TEMP_LIMIT_C, - ACUSystems::BALANCE_ENABLE_TEMP_THRESH_C - }; + ACUSystems::BALANCE_ENABLE_TEMP_THRESH_C}; TEST(ACUControllerTesting, initial_state) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; + std::array cb = {0}; uint32_t start_time = 0; - controller.init(start_time, 420.0f); - - BMSCoreData_s data{}; // zeros - auto status = controller.evaluate_accumulator(start_time, data, 0, ZERO_PACK_CURRENT, num_cells); + auto status = controller.evaluate_accumulator(start_time, {0}, ZERO_PACK_CURRENT); ASSERT_EQ(status.has_fault, false); + ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, false); ASSERT_EQ(status.last_time_ov_fault_not_present, 0); @@ -46,8 +46,8 @@ TEST(ACUControllerTesting, initial_state) TEST(ACUControllerTesting, charging_state) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = true; std::array cb = {0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0}; // 0b001100010010 @@ -56,32 +56,26 @@ TEST(ACUControllerTesting, charging_state) controller.init(init_time, 430.0); - // Core data used by accumulator (no per-cell array in BMSCoreData_s) - BMSCoreData_s data = { - 3.7f, // min cell v - 3.85f, // max cell v - 430.0f, // pack v - + BMSCoreData_s data= { + 3.7, // min cell v + 3.85, // max cell v + 430.00, // pack v + {3.7, 3.81, 3.7, 3.7, 3.81, 3.76, 3.7, 3.7, 3.84, 3.85, 3.75, 3.75} // individual cell voltage data }; - // Per-cell voltages for balancing calc - std::array cell_voltages = {3.7f, 3.81f, 3.7f, 3.7f, 3.81f, 3.76f, 3.7f, 3.7f, 3.84f, 3.85f, 3.75f, 3.75f}; controller.enableCharging(); + // data.charging_enabled = charging_enabled; - auto status = controller.evaluate_accumulator(init_time, data, 0, ZERO_PACK_CURRENT, num_cells); + auto status = controller.evaluate_accumulator(init_time, data, ZERO_PACK_CURRENT); ASSERT_NEAR(data.min_cell_voltage, 3.7, 0.0001); - status = controller.evaluate_accumulator(start_time, data, 0, ZERO_PACK_CURRENT, num_cells); + status = controller.evaluate_accumulator(start_time, data, ZERO_PACK_CURRENT); ASSERT_EQ(status.has_fault, false); + ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, true); - // Balance calculation moved out of evaluate_accumulator; verify outputs explicitly - std::array calc_cb{}; - controller.calculate_cell_balance_statuses(calc_cb.data(), cell_voltages.data(), num_cells, data.min_cell_voltage); - ASSERT_EQ(calc_cb, cb); - ASSERT_EQ(status.last_time_ov_fault_not_present, start_time); ASSERT_EQ(status.last_time_uv_fault_not_present, start_time); ASSERT_EQ(status.last_time_cell_ot_fault_not_present, start_time); @@ -91,8 +85,8 @@ TEST(ACUControllerTesting, charging_state) TEST(ACUControllerTesting, faulted_state) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; // or true doesn't matter std::array cb = {0}; @@ -101,22 +95,25 @@ TEST(ACUControllerTesting, faulted_state) controller.init(init_time, 430.0); - BMSCoreData_s data= { - 3.03f, // min cell v - 4.21f, // max cell v - 430.0f, // pack v - 70.0f, // max cell temp c - 20.0f, // min cell temp c - 50.0f // board temp c + BMSCoreData_s data= { + 3.03, // min cell v + 4.21, // max cell v + 430.00, // pack v + {3.18, 3.2, 3.03, 3.21, 3.10, 3.12, 3.11, 3.12, 3.18, 3.19, 4.21, 3.06}, // individual cell voltage data + 70, // cell temp c + 50, // board temp c }; - auto status = controller.evaluate_accumulator(init_time, data, 0, ZERO_PACK_CURRENT, num_cells); + data.charging_enabled = charging_enabled; + + auto status = controller.evaluate_accumulator(init_time, data, ZERO_PACK_CURRENT); ASSERT_NEAR(data.min_cell_voltage, 3.03, 0.0001); - status = controller.evaluate_accumulator(start_time, data, 0, ZERO_PACK_CURRENT, num_cells); + status = controller.evaluate_accumulator(start_time, data, ZERO_PACK_CURRENT); ASSERT_EQ(status.has_fault, true); + ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, false); ASSERT_EQ(status.last_time_ov_fault_not_present, init_time); // because they're past thresh... @@ -128,8 +125,8 @@ TEST(ACUControllerTesting, faulted_state) TEST(ACUControllerTesting, ir_compensation_discharge) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; std::array cb = {0}; @@ -144,23 +141,26 @@ TEST(ACUControllerTesting, ir_compensation_discharge) // Without IR comp: would fault immediately // With IR comp: discharge_current = 100A, CELL_INTERNAL_RESISTANCE = 0.246/12 = 0.0205Ω // Internal V = 3.05V + (0.0205Ω × 100A) = 3.05V + 2.05V = 5.10V (should NOT fault) - BMSCoreData_s data = { - 3.05f, // min cell v - EXACTLY at UV threshold to trigger IR compensation - 4.15f, // max cell v - well below OV threshold - 430.0f, // pack v - 40.0f, // cell temp c - normal - 20.0f, // min cell temp c - 35.0f // board temp c - normal + BMSCoreData_s data = { + 3.05, // min cell v - EXACTLY at UV threshold to trigger IR compensation + 4.15, // max cell v - well below OV threshold + 430.00, // pack v + {3.18, 3.2, 3.05, 3.21, 3.10, 3.12, 3.11, 3.12, 3.18, 3.19, 4.15, 3.08}, // individual cell voltage data + 40, // cell temp c - normal + 35, // board temp c - normal }; - auto status = controller.evaluate_accumulator(init_time, data, 0, -100.0f, num_cells); // -100A = discharge + data.charging_enabled = charging_enabled; + + auto status = controller.evaluate_accumulator(init_time, data, -100.0f); // -100A = discharge ASSERT_NEAR(data.min_cell_voltage, 3.05, 0.0001); - status = controller.evaluate_accumulator(start_time, data, 0, -100.0f, num_cells); + status = controller.evaluate_accumulator(start_time, data, -100.0f); // Should NOT fault - IR compensation should prevent false UV fault during high discharge ASSERT_EQ(status.has_fault, false); + ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, false); // All timestamps should be updated (no faults) @@ -173,8 +173,8 @@ TEST(ACUControllerTesting, ir_compensation_discharge) TEST(ACUControllerTesting, ir_compensation_charge) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; // Disable balancing to focus on IR compensation test std::array cb = {0}; // No balancing @@ -189,23 +189,26 @@ TEST(ACUControllerTesting, ir_compensation_charge) // Without IR comp: would fault immediately // With IR comp: discharge_current = -10A, CELL_INTERNAL_RESISTANCE = 0.246/12 = 0.0205Ω // Internal V = 4.2V + (0.0205Ω × -10A) = 4.2V - 0.205V = 3.995V (should NOT fault) - BMSCoreData_s data = { - 4.10f, // min cell v - normal - 4.20f, // max cell v - EXACTLY at OV threshold to trigger IR compensation - 500.0f, // pack v - higher during charge - 40.0f, // cell temp c - normal - 20.0f, // min cell temp c - 35.0f // board temp c - normal + BMSCoreData_s data = { + 4.10, // min cell v - normal + 4.20, // max cell v - EXACTLY at OV threshold to trigger IR compensation + 500.00, // pack v - higher during charge + {4.10, 4.15, 4.12, 4.13, 4.14, 4.11, 4.16, 4.17, 4.18, 4.20, 4.15, 4.14}, // individual cell voltage data + 40, // cell temp c - normal + 35, // board temp c - normal }; - auto status = controller.evaluate_accumulator(init_time, data, 0, 10.0f, num_cells); // +10A = charge + data.charging_enabled = charging_enabled; + + auto status = controller.evaluate_accumulator(init_time, data, 10.0f); // +10A = charge ASSERT_NEAR(data.max_cell_voltage, 4.2, 0.0001); - status = controller.evaluate_accumulator(start_time, data, 0, 10.0f, num_cells); + status = controller.evaluate_accumulator(start_time, data, 10.0f); // Should NOT fault - IR compensation should prevent false OV fault during charging ASSERT_EQ(status.has_fault, false); + ASSERT_EQ(status.cell_balancing_statuses, cb); ASSERT_EQ(status.charging_enabled, false); // All timestamps should be updated (no faults) @@ -219,8 +222,8 @@ TEST(ACUControllerTesting, ir_compensation_charge) // Tests that OV faults require 1000ms persistence before triggering TEST(ACUControllerTesting, cell_overvoltage_fault_persistence) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; std::array cb = {0}; @@ -231,28 +234,30 @@ TEST(ACUControllerTesting, cell_overvoltage_fault_persistence) controller.init(init_time, 430.0); // Cell voltage JUST above OV threshold (4.21V > 4.2V), zero current - BMSCoreData_s data = { + BMSCoreData_s data = { 3.70, // min cell v - normal 4.21, // max cell v - ABOVE OV threshold 500.00, // pack v - normal + {3.70, 3.75, 3.72, 3.71, 3.80, 3.76, 3.74, 3.73, 3.78, 4.21, 3.77, 3.79}, // individual cell voltage data 40, // cell temp c - normal 35, // board temp c - normal }; + data.charging_enabled = charging_enabled; // First evaluation at init_time - establishes OV condition - auto status = controller.evaluate_accumulator(init_time, data, 0, ZERO_PACK_CURRENT, 126); + auto status = controller.evaluate_accumulator(init_time, data, ZERO_PACK_CURRENT); // OV detected, timestamp NOT updated (still at init_time) ASSERT_EQ(status.last_time_ov_fault_not_present, init_time); ASSERT_EQ(status.has_fault, false); // Should NOT fault yet (duration = 0ms < 1000ms) // Second evaluation at 500ms - still within threshold - status = controller.evaluate_accumulator(before_fault_time, data, 0, ZERO_PACK_CURRENT, 126); + status = controller.evaluate_accumulator(before_fault_time, data, ZERO_PACK_CURRENT); ASSERT_EQ(status.last_time_ov_fault_not_present, init_time); // Still stuck at init_time ASSERT_EQ(status.has_fault, false); // 500ms < 1000ms - NO fault yet // Third evaluation at 1100ms - exceeds threshold - status = controller.evaluate_accumulator(after_fault_time, data, 0, ZERO_PACK_CURRENT, 126); + status = controller.evaluate_accumulator(after_fault_time, data, ZERO_PACK_CURRENT); ASSERT_EQ(status.last_time_ov_fault_not_present, init_time); // Still stuck at init_time ASSERT_EQ(status.has_fault, true); // 1100ms > 1000ms - FAULT! } @@ -260,8 +265,8 @@ TEST(ACUControllerTesting, cell_overvoltage_fault_persistence) // Tests that UV faults require 1000ms persistence before triggering TEST(ACUControllerTesting, cell_undervoltage_fault_persistence) { - ACUControllerInstance::create(thresholds); - ACUController controller = ACUControllerInstance::instance(); + ACUControllerInstance::create(thresholds); + ACUController controller = ACUControllerInstance::instance(); charging_enabled = false; std::array cb = {0}; @@ -272,29 +277,30 @@ TEST(ACUControllerTesting, cell_undervoltage_fault_persistence) controller.init(init_time, 430.0); // Cell voltage JUST below UV threshold (3.04V < 3.05V), zero current - BMSCoreData_s data = { - 3.04f, // min cell v - BELOW UV threshold - 4.10f, // max cell v - normal - 380.0f, // pack v - normal - 40.0f, // cell temp c - normal - 20.0f, // min cell temp c - 35.0f // board temp c - normal + BMSCoreData_s data = { + 3.04, // min cell v - BELOW UV threshold + 4.10, // max cell v - normal + 380.00, // pack v - normal + {3.70, 3.75, 3.04, 3.71, 3.80, 3.76, 3.74, 3.73, 3.78, 3.85, 3.77, 3.79}, // individual cell voltage data + 40, // cell temp c - normal + 35, // board temp c - normal }; + data.charging_enabled = charging_enabled; // First evaluation at init_time - establishes UV condition - auto status = controller.evaluate_accumulator(init_time, data, 0, ZERO_PACK_CURRENT, num_cells); + auto status = controller.evaluate_accumulator(init_time, data, ZERO_PACK_CURRENT); // UV detected, timestamp NOT updated (still at init_time) ASSERT_EQ(status.last_time_uv_fault_not_present, init_time); ASSERT_EQ(status.has_fault, false); // Should NOT fault yet (duration = 0ms < 1000ms) // Second evaluation at 500ms - still within threshold - status = controller.evaluate_accumulator(before_fault_time, data, 0, ZERO_PACK_CURRENT, num_cells); + status = controller.evaluate_accumulator(before_fault_time, data, ZERO_PACK_CURRENT); ASSERT_EQ(status.last_time_uv_fault_not_present, init_time); // Still stuck at init_time ASSERT_EQ(status.has_fault, false); // 500ms < 1000ms - NO fault yet // Third evaluation at 1100ms - exceeds threshold - status = controller.evaluate_accumulator(after_fault_time, data, 0, ZERO_PACK_CURRENT, num_cells); + status = controller.evaluate_accumulator(after_fault_time, data, ZERO_PACK_CURRENT); ASSERT_EQ(status.last_time_uv_fault_not_present, init_time); // Still stuck at init_time ASSERT_EQ(status.has_fault, true); // 1100ms > 1000ms - FAULT! } \ No newline at end of file From a4127f553d27731ad4c5152b8f78af6ae3ccb944 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Sun, 30 Nov 2025 21:14:07 -0500 Subject: [PATCH 17/18] debugged and fixed infinite loop issues --- lib/interfaces/include/BMSDriverGroup.tpp | 51 +++++++++++++++++++---- src/ACU_InterfaceTasks.cpp | 47 +++++++++++---------- src/main.cpp | 2 +- 3 files changed, 68 insertions(+), 32 deletions(-) diff --git a/lib/interfaces/include/BMSDriverGroup.tpp b/lib/interfaces/include/BMSDriverGroup.tpp index f76d310d..742fd6a7 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -7,6 +7,8 @@ #include #include +// Debug instrumentation for BMS read path: switched to plain Serial prints. + template BMSDriverGroup::BMSDriverGroup(const ChipSelectConfig_t& chip_select_config = ACUConstants::BMS_CHIP_SELECTS, const BMSDriverGroupConfig_s default_params = { @@ -142,6 +144,8 @@ template ::BMSDriverData_t BMSDriverGroup::read_data() { + //Serial.println("BMS read_data: group="); + //Serial.println(get_current_read_group_name()); BMSDriverData_t bms_data; if constexpr (chip_type == LTC6811_Type_e::LTC6811_1) { @@ -170,7 +174,8 @@ template ::BMSDriverData_t BMSDriverGroup::_read_data_through_broadcast() { - + //Serial.print("Broadcast start, group="); + //Serial.println(get_current_read_group_name()); constexpr size_t chip_select_packet_size = _total_packet_size_bytes * num_chips_per_chip_select; size_t chip_start_voltage_cell_index = 0; size_t chip_start_temperature_cell_index = 0; @@ -178,17 +183,25 @@ BMSDriverGroup cmd_pec; std::array spi_data; // Get buffers for each group we care about, all at once for ONE chip select line + //Serial.print(" wakeup..."); _start_wakeup_protocol(chip_select.cs_pin); + //Serial.println("done"); - cmd_pec = _generate_CMD_PEC(_read_group_to_cmd[_current_read_group], -1); // The address should never be used here + cmd_pec = _generate_CMD_PEC(_read_group_to_cmd[_current_read_group], (size_t)-1); // The address should never be used here + //Serial.print(" SPI read..."); + unsigned long t0 = micros(); spi_data = ltc_spi_interface::read_registers_command(chip_select.cs_pin, cmd_pec); + unsigned long t1 = micros(); + //Serial.print("done (us="); //Serial.print((long)(t1 - t0)); //Serial.println(")"); for (size_t chip_index = 0; chip_index < num_chips_per_chip_select; chip_index++) { Chip_t chip = chip_select.chips[chip_index]; @@ -200,29 +213,41 @@ BMSDriverGroup(_current_read_group)] = current_group_valid; + _bms_data.valid_read_packets[global_chip_index][static_cast(_current_read_group)] = current_group_valid; + //Serial.print(" chip["); //Serial.print(global_chip_index); //Serial.print("] valid="); //Serial.println(current_group_valid ? "Y" : "N"); // Skip processing if current group packet is invalid and skip cells 9-12 for group D cuz they don't exist size_t chip_packet_num_values = chip.read_map.get_num_values_in_group(_current_read_group); size_t chip_packet_size_byte = _total_packet_size_bytes * chip_packet_num_values; + //Serial.print(" values="); //Serial.print(chip_packet_num_values); //Serial.print(", bytes="); //Serial.println(chip_packet_size_byte); // Skip processing if current group packet is invalid and updates indexes accordingly if (!current_group_valid) { + //Serial.println(" skip invalid"); continue; } - + //Serial.println(" process valid"); std::copy_n(spi_data.begin() + (_total_packet_size_bytes * chip_index), chip_packet_size_byte, spi_response.begin()); - std::fill(spi_response.begin() + chip_packet_size_byte, spi_response.end(), 0); // padding - + //Serial.println(" copied response"); + // std::fill(spi_response.begin() + chip_packet_size_byte, spi_response.end(), 0); // padding + //Serial.println(" padded response"); std::array value_buffer; + //Serial.println(" created value buffer"); size_t start_voltage_index = chip_start_voltage_cell_index + chip.read_map.get_group_start_cell_voltage_index(_current_read_group); size_t start_temperature_index = chip_start_temperature_cell_index + chip.read_map.get_group_start_cell_temperature_index(_current_read_group); size_t start_board_temperature_index = chip_start_board_temperature_index + chip.read_map.get_group_start_board_temperature_index(_current_read_group); + //Serial.println(" calculated start indexes"); auto read_group_data_types = chip.read_map.group_data_types[_current_read_group]; + //Serial.println(" got data types"); + + //Serial.print(" start_voltage_index="); //Serial.print(start_voltage_index); + //Serial.print(", start_temperature_index="); //Serial.print(start_temperature_index); + //Serial.print(", start_board_temperature_index="); //Serial.println(start_board_temperature_index); for (size_t i = 0; i < chip_packet_num_values; i++) { std::copy_n(spi_response.begin() + (i * size_of_packet_value_bytes), size_of_packet_value_bytes, value_buffer.begin()); + //Serial.print(" value_buffer["); //Serial.print(i); //Serial.print("]="); switch (read_group_data_types[i]){ case CELL_VOLTAGE: _load_cell_voltages(_bms_data, _max_min_reference, value_buffer, start_voltage_index++); @@ -253,6 +278,7 @@ BMSDriverGroup void BMSDriverGroup::write_configuration(uint8_t dcto_mode, const std::array &cell_balance_statuses) { + //Serial.print("BMS write_configuration: group="); + //Serial.println(get_current_read_group_name()); std::copy(cell_balance_statuses.begin(), cell_balance_statuses.end(), _cell_discharge_en.begin()); std::array buffer_format; // This buffer processing can be seen in more detail on page 62 of the data sheet @@ -464,16 +493,19 @@ void BMSDriverGroup void BMSDriverGroup::_write_config_through_broadcast(uint8_t dcto_mode, std::array buffer_format, const std::array &cell_balance_statuses) { + //Serial.println(" _write_config_through_broadcast"); constexpr size_t data_size = _total_packet_size_bytes * num_chips_per_chip_select; std::array cmd_and_pec = _generate_CMD_PEC(CMD_CODES_e::WRITE_CONFIG, -1); std::array full_buffer; - std::array temp_pec; + std::array temp_pec; // Needs to be sent on each chip select line for (size_t chip_select_index = 0; chip_select_index < num_chip_selects; chip_select_index++) { - for (size_t chip_index = num_chips_per_chip_select - 1; chip_index >= 0; chip_index--) // This needs to be flipped because when writing a command, primary device holds the last bytes + for (int chip_index = static_cast(num_chips_per_chip_select) - 1; chip_index >= 0; chip_index--) + // This needs to be flipped because when writing a command, primary device holds the last bytes { + //Serial.print(" chip_index="); //Serial.println(chip_index); size_t global_chip_index = _chip_select_config.global_chip_index(chip_select_index, chip_index); buffer_format[4] = ((cell_balance_statuses[global_chip_index] & 0x0FF)); buffer_format[5] = ((dcto_mode & 0x0F) << 4) | ((cell_balance_statuses[global_chip_index] & 0xF00) >> 8); @@ -481,6 +513,7 @@ void BMSDriverGroup(_chip_select_config.chip_selects[chip_select_index].cs_pin, cmd_and_pec, full_buffer); } } diff --git a/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index 0db1f5c9..d3efaf0a 100644 --- a/src/ACU_InterfaceTasks.cpp +++ b/src/ACU_InterfaceTasks.cpp @@ -67,8 +67,11 @@ void initialize_all_interfaces() FaultLatchManagerInstance::instance().set_shdn_out_latched(true); // Start shdn out latch cleared /* BMS Driver */ + Serial.println("Initializing BMS Driver..."); BMSDriverInstance_t::create(); + Serial.println("BMS Driver created."); BMSDriverInstance_t::instance().init(); + Serial.println("BMS Driver initialized."); /* Get Initial Pack Voltage for SoC and SoH Approximations */ auto data = BMSDriverInstance_t::instance().read_data(); @@ -118,8 +121,8 @@ HT_TASK::TaskResponse run_kick_watchdog(const unsigned long &sysMicros, const HT HT_TASK::TaskResponse sample_bms_data(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) { auto data = BMSDriverInstance_t::instance().read_data(); - BMSFaultDataManagerInstance_t::instance().update_from_valid_packets(data.valid_read_packets); // print_bms_data(data); + BMSFaultDataManagerInstance_t::instance().update_from_valid_packets(data.valid_read_packets); return HT_TASK::TaskResponse::YIELD; } @@ -360,27 +363,27 @@ HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK: Serial.print("Number of Global Faults: "); Serial.println(BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count); - // Serial.println("Number of Consecutive Faults Per Chip: "); - // for (size_t c = 0; c < ACUConstants::NUM_CHIPS; c++) { - // Serial.print("CHIP "); - // Serial.print(c); - // Serial.print(": "); - // Serial.print(ACUFaultDataInstance::instance().consecutive_invalid_packet_counts[c]); - // Serial.print("\t"); - // Serial.print(ACUFaultDataInstance::instance().chip_invalid_cmd_counts[c].invalid_cell_1_to_3_count); - // Serial.print(" "); - // Serial.print(ACUFaultDataInstance::instance().chip_invalid_cmd_counts[c].invalid_cell_4_to_6_count); - // Serial.print(" "); - // Serial.print(ACUFaultDataInstance::instance().chip_invalid_cmd_counts[c].invalid_cell_7_to_9_count); - // Serial.print(" "); - // Serial.print(ACUFaultDataInstance::instance().chip_invalid_cmd_counts[c].invalid_cell_10_to_12_count); - // Serial.print(" "); - // Serial.print(ACUFaultDataInstance::instance().chip_invalid_cmd_counts[c].invalid_gpio_1_to_3_count); - // Serial.print(" "); - // Serial.print(ACUFaultDataInstance::instance().chip_invalid_cmd_counts[c].invalid_gpio_4_to_6_count); - // Serial.print(" "); - // } - // Serial.println(); + Serial.println("Number of Consecutive Faults Per Chip: "); + for (size_t c = 0; c < 12; c++) { + Serial.print("CHIP "); + Serial.print(c); + Serial.print(": "); + Serial.print(BMSFaultDataManagerInstance_t::instance().get_fault_data().consecutive_invalid_packet_counts[c]); + Serial.print("\t"); + Serial.print(BMSFaultDataManagerInstance_t::instance().get_fault_data().chip_invalid_cmd_counts[c][0]); + Serial.print(" "); + Serial.print(BMSFaultDataManagerInstance_t::instance().get_fault_data().chip_invalid_cmd_counts[c][1]); + Serial.print(" "); + Serial.print(BMSFaultDataManagerInstance_t::instance().get_fault_data().chip_invalid_cmd_counts[c][2]); + Serial.print(" "); + Serial.print(BMSFaultDataManagerInstance_t::instance().get_fault_data().chip_invalid_cmd_counts[c][3]); + Serial.print(" "); + Serial.print(BMSFaultDataManagerInstance_t::instance().get_fault_data().chip_invalid_cmd_counts[c][4]); + Serial.print(" "); + Serial.print(BMSFaultDataManagerInstance_t::instance().get_fault_data().chip_invalid_cmd_counts[c][5]); + Serial.print(" "); + } + Serial.println(); return HT_TASK::TaskResponse::YIELD; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 48754f87..8afebe79 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -65,7 +65,7 @@ void setup() scheduler.schedule(sample_CAN_task); scheduler.schedule(idle_sample_task); - //scheduler.schedule(debug_prints_task); + scheduler.schedule(debug_prints_task); handle_CAN_setup(ACUCANInterfaceImpl::CCU_CAN, ACUConstants::Veh_CAN_baudrate, &ACUCANInterfaceImpl::on_ccu_can_receive); handle_CAN_setup(ACUCANInterfaceImpl::EM_CAN, ACUConstants::EM_CAN_baudrate, &ACUCANInterfaceImpl::on_em_can_receive); From 67893f1d38e1df4a33888cbb239b12b7e0aaf449 Mon Sep 17 00:00:00 2001 From: Advait Vedant Date: Tue, 2 Dec 2025 17:34:36 -0500 Subject: [PATCH 18/18] fixed error --- src/ACU_InterfaceTasks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index d3efaf0a..fe37d979 100644 --- a/src/ACU_InterfaceTasks.cpp +++ b/src/ACU_InterfaceTasks.cpp @@ -364,7 +364,7 @@ HT_TASK::TaskResponse debug_print(const unsigned long &sysMicros, const HT_TASK: Serial.print("Number of Global Faults: "); Serial.println(BMSFaultDataManagerInstance_t::instance().get_fault_data().max_consecutive_invalid_packet_count); Serial.println("Number of Consecutive Faults Per Chip: "); - for (size_t c = 0; c < 12; c++) { + for (size_t c = 0; c < ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_CHIP_SELECT; c++) { Serial.print("CHIP "); Serial.print(c); Serial.print(": ");