diff --git a/include/ACU_Constants.h b/include/ACU_Constants.h index a54b3b8..b80d18e 100644 --- a/include/ACU_Constants.h +++ b/include/ACU_Constants.h @@ -55,17 +55,175 @@ namespace ACUInterfaces { namespace ACUConstants { constexpr size_t NUM_CELLS = 126; - constexpr size_t NUM_CHIPS = 12; - constexpr size_t NUM_CELL_TEMPS = 48; + 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( + 9, + std::array{ + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + 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 + 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{ + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + 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 + 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 + } + ) + }, + } + ) + } + ); + + 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 671b820..d8e2880 100644 --- a/include/ACU_InterfaceTasks.h +++ b/include/ACU_InterfaceTasks.h @@ -22,8 +22,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 5a0f535..385c91e 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(); /* Delegate Functions */ diff --git a/lib/interfaces/include/BMSDriverGroup.h b/lib/interfaces/include/BMSDriverGroup.h index 7d48917..ca5673f 100644 --- a/lib/interfaces/include/BMSDriverGroup.h +++ b/lib/interfaces/include/BMSDriverGroup.h @@ -85,8 +85,8 @@ 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 size_t SIZE_OF_PACKET_VALUE_BYTES = 2; } - namespace ref_max_min_defaults { constexpr const volt TOTAL_VOLTAGE = 0; @@ -97,23 +97,15 @@ namespace ref_max_min_defaults constexpr const celsius MAX_BOARD_TEMP = 0; }; -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 + +template struct BMSData_s { - std::array valid_read_packets; - std::array voltages; - std::array cell_temperatures; - std::array board_temperatures; + std::array, num_chips> valid_read_packets; + std::array voltages; + std::array cell_temperatures; + std::array board_temperatures; volt min_cell_voltage; volt max_cell_voltage; celsius max_cell_temp; @@ -167,28 +159,49 @@ struct BMSDriverGroupConfig_s * @param current The current read group state * @return The next read group, wrapping from CURRENT_GROUP_AUX_B back to CURRENT_GROUP_A */ -constexpr ReadGroup_e advance_read_group(ReadGroup_e current) +constexpr bool advance_read_group(ReadGroup_e* current) { - return static_cast( - (static_cast(current) + 1) % static_cast(ReadGroup_e::NUM_GROUPS) - ); + // Get current as int + int curr = static_cast(*current); + + // Compute next value with wrap-around + int next = (curr + 1) % static_cast(ReadGroup_e::NUM_GROUPS); + + // Detect wrap: we wrapped if next is 0 + bool wrapped = (next == 0); + + // Write back through the pointer + *current = static_cast(next); + + return wrapped; } -template + +template class BMSDriverGroup { public: - 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; - - using BMSDriverData = BMSData_s; - + 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 + }; + + // constexpr static size_t num_cell_temps = (num_chips * 4); + // constexpr static size_t num_board_temps = num_chips; + + 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 std::array& cs, - const std::array& cs_per_chip, - const std::array& addr, + const ChipSelectConfig_t& chip_select_config, const BMSDriverGroupConfig_s default_params ); @@ -213,7 +226,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 @@ -223,7 +236,7 @@ class BMSDriverGroup /** * Getter function to retrieve the BMSDriverData structure */ - BMSDriverData get_bms_data(); + BMSDriverData_t get_bms_data(); /* -------------------- WRITING DATA FUNCTIONS -------------------- */ @@ -232,12 +245,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 -------------------- */ @@ -272,7 +285,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_chip_selects * num_chips_per_chip_select>& get_validity_data() { return _bms_data.valid_read_packets; } @@ -296,8 +309,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; } /** @@ -310,7 +323,6 @@ class BMSDriverGroup } private: - ReadGroup_e _current_read_group = ReadGroup_e::CV_GROUP_A; /** @@ -331,9 +343,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 @@ -357,15 +369,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 @@ -382,21 +394,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_cv_group, - 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, - 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 @@ -412,13 +421,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 @@ -426,7 +435,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 @@ -436,7 +444,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. @@ -450,25 +458,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 @@ -487,11 +479,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 97f4906..7ff3234 100644 --- a/lib/interfaces/include/BMSDriverGroup.tpp +++ b/lib/interfaces/include/BMSDriverGroup.tpp @@ -7,10 +7,10 @@ #include #include -template -BMSDriverGroup::BMSDriverGroup(const std::array& cs, - const std::array& cs_per_chip, - const std::array& addr, +// 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 = { .device_refup_mode = bms_driver_defaults::DEVICE_REFUP_MODE, .adcopt = bms_driver_defaults::ADCOPT, @@ -28,29 +28,25 @@ 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 } - ) : _chip_select(cs), - _chip_select_per_chip(cs_per_chip), - _address(addr), + ) : _chip_select_config(chip_select_config), _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++) + 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); _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; _max_min_reference = { .total_voltage = ref_max_min_defaults::TOTAL_VOLTAGE, @@ -62,34 +58,34 @@ void BMSDriverGroup::init() }; } -template -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 @@ -115,8 +111,8 @@ constexpr std::array BMSDriverGroup -BMSCoreData_s BMSDriverGroup::get_bms_core_data() +template +BMSCoreData_s BMSDriverGroup::get_bms_core_data() { BMSCoreData_s out{}; @@ -133,18 +129,20 @@ BMSCoreData_s BMSDriverGroup::get_bms_co return out; } -template -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; + //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) { bms_data = _read_data_through_broadcast(); @@ -167,244 +165,222 @@ BMSDriverGroup::read_data() return bms_data; } -template -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::_read_data_through_broadcast() + +template +typename BMSDriverGroup::BMSDriverData_t +BMSDriverGroup::_read_data_through_broadcast() { - constexpr size_t data_size = 8 * (num_chips / num_chip_selects); - for (size_t cs = 0; cs < num_chip_selects; cs++) + //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; + 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]; + //Serial.print(" CS["); //Serial.print(chip_select_index); //Serial.print("] pin="); //Serial.println(chip_select.cs_pin); + //Serial.print(" write_cfg dcto="); //Serial.print((int)_config.dcto_read); //Serial.println(""); write_configuration(_config.dcto_read, _cell_discharge_en); + //Serial.println(" write_cfg done"); 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); + //Serial.print(" wakeup..."); + _start_wakeup_protocol(chip_select.cs_pin); + //Serial.println("done"); - 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], (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 = 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, 8 * 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); - _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); - _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); - _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); - _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); - _bms_data.valid_read_packets[chip_index].valid_read_gpios_4_to_6 = 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[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 - if (!current_group_valid || (_current_read_group == ReadGroup_e::CV_GROUP_D && cells_per_chip == 9)) { - continue; - } - 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()); + 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; } - 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); + //Serial.println(" process valid"); + std::copy_n(spi_data.begin() + (_total_packet_size_bytes * chip_index), chip_packet_size_byte, spi_response.begin()); + //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++); + 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.total_voltage = _max_min_reference.total_voltage; - _bms_data.avg_cell_voltage = _bms_data.total_voltage / num_cells; - _bms_data.average_cell_temperature = _max_min_reference.total_thermistor_temps / (4 * num_chips); + _bms_data.avg_cell_voltage = _bms_data.total_voltage / num_voltage_cells; + _bms_data.average_cell_temperature = _max_min_reference.total_thermistor_temps / num_temp_cells; - if(_current_read_group == ReadGroup_e::CV_GROUP_D) { - _bms_data.min_cell_voltage = _max_min_reference.min_cell_voltage; - _bms_data.max_cell_voltage = _max_min_reference.max_cell_voltage; - // Reset max and mins + _bms_data.min_cell_voltage = _max_min_reference.min_cell_voltage; + _bms_data.max_cell_voltage = _max_min_reference.max_cell_voltage; + + _bms_data.max_cell_temp = _max_min_reference.max_cell_temp; + _bms_data.min_cell_temp = _max_min_reference.min_cell_temp; + _bms_data.max_board_temp = _max_min_reference.max_board_temp; + + bool read_last_group = advance_read_group(&_current_read_group); + //Serial.print("Advance group, now="); //Serial.println(get_current_read_group_name()); + if (read_last_group) { + // Reset for next full read cycle _max_min_reference.min_cell_voltage = ref_max_min_defaults::MIN_CELL_VOLTAGE; _max_min_reference.max_cell_voltage = ref_max_min_defaults::MAX_CELL_VOLTAGE; - } - if(_current_read_group == ReadGroup_e::AUX_GROUP_B) { - _bms_data.max_cell_temp = _max_min_reference.max_cell_temp; - _bms_data.min_cell_temp = _max_min_reference.min_cell_temp; - _bms_data.max_board_temp = _max_min_reference.max_board_temp; - // Reset max and mins _max_min_reference.min_cell_temp = ref_max_min_defaults::MIN_CELL_TEMP; _max_min_reference.max_cell_temp = ref_max_min_defaults::MAX_CELL_TEMP; _max_min_reference.max_board_temp = ref_max_min_defaults::MAX_BOARD_TEMP; + //Serial.println("Completed full cycle; reference reset"); } - - _current_read_group = advance_read_group(_current_read_group); return _bms_data; } -template -typename BMSDriverGroup::BMSDriverData -BMSDriverGroup::_read_data_through_address() +template +typename BMSDriverGroup::BMSDriverData_t +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; + // 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 - _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 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 = _total_packet_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 / num_voltage_cells; + + _bms_data.average_cell_temperature = max_min_reference.total_thermistor_temps / total_num_temp_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.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_cv_group, - 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) { - 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()); - 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; - // 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_auxillaries(BMSDriverData& bms_data, ReferenceMaxMin_s &max_min_ref, const std::array &data_in_gpio_group, - uint8_t chip_index, uint8_t start_gpio_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) { - 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); - } + 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::_store_voltage_data(BMSDriverData &bms_data, ReferenceMaxMin_s &max_min_reference, volt voltage_in, uint8_t cell_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) +{ + 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_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; @@ -422,73 +398,74 @@ 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_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 the case for temperature sensor for the BOARD, not the cells. There is 1 per chip + 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 chip has 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) { + //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 @@ -509,37 +486,37 @@ 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 = 8 * (num_chips / num_chip_selects); + //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 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 (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); + 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[cs], cmd_and_pec, full_buffer); + //Serial.print(" write_registers_command on CS pin "); //Serial.println(_chip_select_config.chip_selects[chip_select_index].cs_pin); + 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; @@ -558,8 +535,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; @@ -575,8 +552,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; @@ -593,8 +570,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]}; @@ -604,15 +581,15 @@ void BMSDriverGroup::_start_ADC_conversi std::copy_n(pec.begin(), 2, cmd_and_pec.begin() + 2); // Copy next two bytes (pec) // Needs to be sent on each chip select line - for (size_t cs = 0; cs < num_chip_selects; cs++) { - _start_wakeup_protocol(cs); - ltc_spi_interface::adc_conversion_command(_chip_select[cs], cmd_and_pec, (num_chips / num_chip_selects)); + for (const ChipSelect_t chip_select : _chip_select_config.chip_selects) { + _start_wakeup_protocol(chip_select.cs_pin); + ltc_spi_interface::adc_conversion_command(chip_select.cs_pin, cmd_and_pec, num_chips_per_chip_select); } } /* 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++) @@ -630,8 +607,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; @@ -648,8 +625,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, size_t chip_addr) { std::array cmd; const uint16_t cmd_val = static_cast(command); @@ -661,17 +638,17 @@ std::array BMSDriverGroup::_ } else { - cmd[0] = static_cast(_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) @@ -680,8 +657,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; @@ -694,8 +671,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: @@ -715,32 +692,33 @@ 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++) { + 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) { 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: 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; @@ -749,34 +727,35 @@ 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; // 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) { 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: 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/shared_types/shared_types.h b/lib/shared_types/shared_types.h index 1113686..797aea3 100644 --- a/lib/shared_types/shared_types.h +++ b/lib/shared_types/shared_types.h @@ -10,58 +10,193 @@ struct BMSCoreData_s { 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, NUM_DATA_TYPES, NO_DATA }; + +template +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 index; + } + 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 index; + } + 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 index; + } + +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::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; +}; + +// ----- 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(); + } + + 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 \ No newline at end of file diff --git a/lib/systems/include/BMSFaultDataManager.h b/lib/systems/include/BMSFaultDataManager.h index a9a82bd..6798c9b 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 f65e41c..c4684c6 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/src/ACU_InterfaceTasks.cpp b/src/ACU_InterfaceTasks.cpp index 33e7594..e406a2b 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(); BMSDriverInstance_t::instance().init(); /* Get Initial Pack Voltage for SoC and SoH Approximations */ auto data = BMSDriverInstance_t::instance().read_data(); @@ -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 = 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; } @@ -132,8 +132,9 @@ std::array check_and_get_balancing_status() { } HT_TASK::TaskResponse write_cell_balancing_config(const unsigned long &sysMicros, const HT_TASK::TaskInfo &taskInfo) -{ - BMSDriverInstance_t::instance().write_configuration(check_and_get_balancing_status()); +{ + auto balancing_statuses = check_and_get_balancing_status(); + BMSDriverInstance_t::instance().write_configuration(balancing_statuses.data(), balancing_statuses.size()); return HT_TASK::TaskResponse::YIELD; } @@ -178,7 +179,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 data = make_acu_all_data(); - CCUInterfaceInstance::instance().set_ACU_data(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; @@ -286,7 +287,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_CHIP_SELECT * ACUConstants::NUM_CHIP_SELECTS; c++) { Serial.print("CHIP "); Serial.print(c); Serial.print(": "); @@ -372,27 +373,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 < ACUConstants::NUM_CHIP_SELECTS * ACUConstants::NUM_CHIPS_PER_CHIP_SELECT; 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