From 4c9e1a3169e3002818b4d2b9ee7b5dd47a4826f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 25 Oct 2024 21:56:52 +0300 Subject: [PATCH 01/48] Add iX skeleton --- Software/USER_SETTINGS.h | 1 + Software/src/battery/BATTERIES.h | 4 + Software/src/battery/BMW-IX-BATTERY.cpp | 193 ++++++++++++++++++ Software/src/battery/BMW-IX-BATTERY.h | 17 ++ Software/src/devboard/webserver/webserver.cpp | 3 + 5 files changed, 218 insertions(+) create mode 100644 Software/src/battery/BMW-IX-BATTERY.cpp create mode 100644 Software/src/battery/BMW-IX-BATTERY.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index c5cbd65f..9c127e62 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -10,6 +10,7 @@ /* Select battery used */ //#define BMW_I3_BATTERY +//#define BMW_IX_BATTERY //#define BYD_ATTO_3_BATTERY //#define CHADEMO_BATTERY //NOTE: inherently enables CONTACTOR_CONTROL below //#define IMIEV_CZERO_ION_BATTERY diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 8539c551..d0af768f 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -6,6 +6,10 @@ #include "BMW-I3-BATTERY.h" #endif +#ifdef BMW_IX_BATTERY +#include "BMW-IX-BATTERY.h" +#endif + #ifdef BYD_ATTO_3_BATTERY #include "BYD-ATTO-3-BATTERY.h" #endif diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp new file mode 100644 index 00000000..78559bce --- /dev/null +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -0,0 +1,193 @@ +#include "../include.h" +#ifdef BMW_IX_BATTERY +#include "../datalayer/datalayer.h" +#include "../datalayer/datalayer_extended.h" +#include "../devboard/utils/events.h" +#include "BMW-IX-BATTERY.h" + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send +static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send +static unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was send +static unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was send +static unsigned long previousMillis640 = 0; // will store last time a 600ms CAN Message was send +static unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was send +static unsigned long previousMillis5000 = 0; // will store last time a 5000ms CAN Message was send +static unsigned long previousMillis10000 = 0; // will store last time a 10000ms CAN Message was send + +#define ALIVE_MAX_VALUE 14 // BMW CAN messages contain alive counter, goes from 0...14 + +enum CmdState { SOH, CELL_VOLTAGE_MINMAX, SOC, CELL_VOLTAGE_CELLNO, CELL_VOLTAGE_CELLNO_LAST }; + +static CmdState cmdState = SOC; + +CAN_frame BMW_6F1_CELL = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x6F1, .data = {0x07, 0x03, 0x22, 0xDD, 0xBF}}; +CAN_frame BMW_6F1_SOH = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x6F1, .data = {0x07, 0x03, 0x22, 0x63, 0x35}}; +CAN_frame BMW_6F1_SOC = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x6F1, .data = {0x07, 0x03, 0x22, 0xDD, 0xBC}}; +CAN_frame BMW_6F1_CELL_VOLTAGE_AVG = {.FD = false, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F1, + .data = {0x07, 0x03, 0x22, 0xDF, 0xA0}}; +CAN_frame BMW_6F1_CONTINUE = {.FD = false, .ext_ID = false, .DLC = 4, .ID = 0x6F1, .data = {0x07, 0x30, 0x00, 0x02}}; +CAN_frame BMW_6F4_CELL_VOLTAGE_CELLNO = {.FD = false, + .ext_ID = false, + .DLC = 7, + .ID = 0x6F4, + .data = {0x07, 0x05, 0x31, 0x01, 0xAD, 0x6E, 0x01}}; +CAN_frame BMW_6F4_CELL_CONTINUE = {.FD = false, + .ext_ID = false, + .DLC = 6, + .ID = 0x6F4, + .data = {0x07, 0x04, 0x31, 0x03, 0xAD, 0x6E}}; + +static bool battery_awake = false; + +static uint8_t current_cell_polled = 0; + +static uint8_t increment_alive_counter(uint8_t counter) { + counter++; + if (counter > ALIVE_MAX_VALUE) { + counter = 0; + } + return counter; +} + +void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer + + datalayer.battery.status.real_soc; + + datalayer.battery.status.voltage_dV; + + datalayer.battery.status.current_dA; + + datalayer.battery.info.total_capacity_Wh; + + datalayer.battery.status.remaining_capacity_Wh; + + datalayer.battery.status.soh_pptt; + + datalayer.battery.status.max_discharge_power_W; + + datalayer.battery.status.max_charge_power_W; + + datalayer.battery.status.active_power_W; + + datalayer.battery.status.temperature_min_dC; + + datalayer.battery.status.temperature_max_dC; +} + +void receive_can_battery(CAN_frame rx_frame) { + battery_awake = true; + switch (rx_frame.ID) { + case 0x112: + break; + default: + break; + } +} + +void send_can_battery() { + unsigned long currentMillis = millis(); + + if (battery_awake) { + //Send 20ms message + if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { + // Check if sending of CAN messages has been delayed too much. + if ((currentMillis - previousMillis20 >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20)); + } else { + clear_event(EVENT_CAN_OVERRUN); + } + previousMillis20 = currentMillis; + } + // Send 100ms CAN Message + if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { + previousMillis100 = currentMillis; + } + // Send 200ms CAN Message + if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { + previousMillis200 = currentMillis; + } + // Send 500ms CAN Message + if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { + previousMillis500 = currentMillis; + } + // Send 640ms CAN Message + if (currentMillis - previousMillis640 >= INTERVAL_640_MS) { + previousMillis640 = currentMillis; + } + // Send 1000ms CAN Message + if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { + previousMillis1000 = currentMillis; + + switch (cmdState) { + case SOC: + transmit_can(&BMW_6F1_CELL, can_config.battery); + cmdState = CELL_VOLTAGE_MINMAX; + break; + case CELL_VOLTAGE_MINMAX: + transmit_can(&BMW_6F1_SOH, can_config.battery); + cmdState = SOH; + break; + case SOH: + transmit_can(&BMW_6F1_CELL_VOLTAGE_AVG, can_config.battery); + cmdState = CELL_VOLTAGE_CELLNO; + current_cell_polled = 0; + + break; + case CELL_VOLTAGE_CELLNO: + current_cell_polled++; + if (current_cell_polled > 96) { + datalayer.battery.info.number_of_cells = 97; + cmdState = CELL_VOLTAGE_CELLNO_LAST; + } else { + cmdState = CELL_VOLTAGE_CELLNO; + + BMW_6F4_CELL_VOLTAGE_CELLNO.data.u8[6] = current_cell_polled; + transmit_can(&BMW_6F4_CELL_VOLTAGE_CELLNO, can_config.battery); + } + break; + case CELL_VOLTAGE_CELLNO_LAST: + transmit_can(&BMW_6F1_SOC, can_config.battery); + cmdState = SOC; + break; + } + } + // Send 5000ms CAN Message + if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { + previousMillis5000 = currentMillis; + } + // Send 10000ms CAN Message + if (currentMillis - previousMillis10000 >= INTERVAL_10_S) { + previousMillis10000 = currentMillis; + } + } else { + previousMillis20 = currentMillis; + previousMillis100 = currentMillis; + previousMillis200 = currentMillis; + previousMillis500 = currentMillis; + previousMillis640 = currentMillis; + previousMillis1000 = currentMillis; + previousMillis5000 = currentMillis; + previousMillis10000 = currentMillis; + } +} + +void setup_battery(void) { // Performs one time setup at startup +#ifdef DEBUG_VIA_USB + Serial.println("BMW iX battery selected"); +#endif //DEBUG_VIA_USB + + //Before we have started up and detected which battery is in use, use 60AH values + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; + datalayer.system.status.battery_allows_contactor_closing = true; + + pinMode(WUP_PIN, OUTPUT); + digitalWrite(WUP_PIN, HIGH); // Wake up the battery +} + +#endif diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h new file mode 100644 index 00000000..8c2e24c9 --- /dev/null +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -0,0 +1,17 @@ +#ifndef BMW_IX_BATTERY_H +#define BMW_IX_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED + +#define WUP_PIN 25 +#define MAX_PACK_VOLTAGE_DV 5000 //5000 = 500.0V +#define MIN_PACK_VOLTAGE_DV 3000 +#define MAX_CELL_DEVIATION_MV 500 +#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value +void setup_battery(void); +void transmit_can(CAN_frame* tx_frame, int interface); + +#endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index f1b3230a..ee321d9c 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -513,6 +513,9 @@ String processor(const String& var) { #ifdef BMW_I3_BATTERY content += "BMW i3"; #endif // BMW_I3_BATTERY +#ifdef BMW_IX_BATTERY + content += "BMW iX and i4-7 platform"; +#endif // BMW_IX_BATTERY #ifdef BYD_ATTO_3_BATTERY content += "BYD Atto 3"; #endif // BYD_ATTO_3_BATTERY From 6b823e2c5b2fe40a41634241d3426c00364500f3 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sat, 26 Oct 2024 22:55:00 +0100 Subject: [PATCH 02/48] Update BMW-IX-BATTERY.cpp First functional version - SME wake line can be held high to use. Notes: - Bat capacity max/remain is temp scaled by 0.1 so fits in uint16 - No max charge/discharge power - No SOH - No contactor control --- Software/src/battery/BMW-IX-BATTERY.cpp | 381 ++++++++++++++++++++++-- 1 file changed, 358 insertions(+), 23 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 78559bce..c13d0eb8 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -21,21 +21,149 @@ enum CmdState { SOH, CELL_VOLTAGE_MINMAX, SOC, CELL_VOLTAGE_CELLNO, CELL_VOLTAGE static CmdState cmdState = SOC; -CAN_frame BMW_6F1_CELL = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x6F1, .data = {0x07, 0x03, 0x22, 0xDD, 0xBF}}; -CAN_frame BMW_6F1_SOH = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x6F1, .data = {0x07, 0x03, 0x22, 0x63, 0x35}}; -CAN_frame BMW_6F1_SOC = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x6F1, .data = {0x07, 0x03, 0x22, 0xDD, 0xBC}}; -CAN_frame BMW_6F1_CELL_VOLTAGE_AVG = {.FD = false, +/* +Suspected Vehicle comms required: + + 0x06D DLC? 1000ms - counters? + 0x2F1 DLC? 1000ms during run : 0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x00, 0xF3, 0xFF - at startup 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xF3, 0xFF. Suspect byte [4] is a counter + 0x439 DLC4 1000ms STATIC + 0x0C0 DLC2 200ms needs counter + 0x510 DLC8 100ms STATIC 40 10 40 00 6F DF 19 00 during run - Startup sends this once: 0x40 0x10 0x02 0x00 0x00 0x00 0x00 0x00 + 0x587 DLC8 appears at startup 0x78 0x07 0x00 0x00 0xFF 0xFF 0xFF 0xFF , 0x01 0x03 0x80 0xFF 0xFF 0xFF 0xFF 0xFF, 0x78 0x07 0x00 0x00 0xFF 0xFF 0xFF 0xFF, 0x06 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF, 0x01 0x03 0x82 0xFF 0xFF 0xFF 0xFF 0xFF, 0x01 0x03 0x80 0xFF 0xFF 0xFF 0xFF 0xFF + +No vehicle log available, SME asks for: + 0x125 (CCU) + 0x16 (CCU) + 0x91 (EME1) + 0xAA (EME2) + +SME Output: + + 0x08F DLC48 10ms - Appears to have analog readings like volt/temp/current + 0x1D2 DLC8 1000ms + 0x20B DLC8 1000ms + 0x2E2 DLC16 1000ms + 0x2F1 DLC8 1000ms + 0x31F DLC16 100ms - 2 downward counters? + 0x453 DLC20 200ms + 0x486 DLC48 1000ms + 0x49C DLC8 1000ms + 0x4A1 DLC8 1000ms + 0x4BB DLC64 200ms - seems multplexed on [0] + 0x4D0 DLC64 1000ms - some slow/flickering values + 0x607 UDS Response + + + +UDS Map: + 69 - service disconnect (1 = closed) + c7 - available energy - available energy charged + ce - min avg max SOC + 61 len12 = current sensor + 53 - min and max cell voltage + 4d- main battery voltage + 4a - after contactor voltage + a4 = charnging contactor temp + A3 - MAIN CONTACTOR VOLTAGE + f4 00 0a 62 DD = main battery temp + A7 - T30 12v voltage (SME input voltage) + B6 - T30C 12v voltage (12v pyro sensor) + 51 = release, switch contactors. 1 = control of switch contactors active + CD = charge contactors + + TX 07 03 22 E5 54 - UDS request cell voltages + RX F4 10 E3 62 E5 54 - 16bit cell voltages batch1 (29 cells) + TX 07 30 00 02 - UDS request continue data + RX F4 21 0F - 16bit cell voltages continue2 (31 cells) + RX F4 22 0F - 16bit cell voltages continue3 (31 cells) + RX F4 23 0F - 16bit cell voltages continue4 (17 cells) + + TX 07 03 22 E5 9A - UDS request cell SOC + RX F4 10 E3 62 E5 9A?? - 16bit cell SOC batch1 (29 cells) + + TX 07 03 22 E5 CA - UDS request cell temps + RX F4 10 81 62 E5 CA - 16bit cell temps batch1 + RX F4 21 81 62 E5 CA - 16bit cell temps continue2 + + TX 07 30 00 02 - UDS request continue data + + +*/ + + + +CAN_frame BMWiX_06D = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x06D, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF}}; // 1000ms BDC Output - [0] static [1]-[4] counter x2? is needed? [5-7] static + + +CAN_frame BMWiX_2F1 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x2F1, + .data = {0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x00, 0xF3, 0xFF}}; // 1000ms BDC Output - Static values - varies at startup + + + +CAN_frame BMWiX_439 = {.FD = true, + .ext_ID = false, + .DLC = 4, + .ID = 0x439, + .data = {0xFF, 0xBF, 0xFF, 0xFF}}; // 1000ms BDC Output - Static values + + + +CAN_frame BMWiX_510 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x510, + .data = {0x40, 0x10, 0x40, 0x00, 0x6F, 0xDF, 0x19, 0x00}}; // 100ms BDC Output - Static values + + + +CAN_frame BMWiX_6F4 = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0xC7}}; // UDS Request data from SME. byte 4 selects requested value + + +CAN_frame BMWiX_0C0 = {.FD = true, + .ext_ID = false, + .DLC = 2, + .ID = 0x0C0, + .data = {0xF0, 0x08}}; // Keep Alive 2 BDC>SME 200ms First byte cycles F0 > FE second byte 08 static + + +CAN_frame BMWiX_6F4_CELL_VOLTAGE = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x54}}; +CAN_frame BMWiX_6F4_CELL_SOC = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x9A}}; +CAN_frame BMWiX_6F4_CELL_TEMP = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xCA}}; + +CAN_frame BMWiX_6F4_CONTINUE_DATA = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x6F4, .data = {0x07, 0x30, 0x00, 0x02}}; + +CAN_frame BMW_6F4_CELL = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xDD, 0xBF}};// gives error F4 03 7F 22 31 +CAN_frame BMW_6F4_SOH = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0x63, 0x35}}; // gives error F4 03 7F 22 31 +CAN_frame BMW_6F4_SOC = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xDD, 0xBC}}; // gives blanks + +CAN_frame BMW_10B = {.FD = true, + .ext_ID = false, + .DLC = 3, + .ID = 0x10B, + .data = {0xCD, 0x00, 0xFC}}; // Contactor closing command + +CAN_frame BMW_6F4_CELL_VOLTAGE_AVG = {.FD = true, .ext_ID = false, .DLC = 5, - .ID = 0x6F1, + .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xDF, 0xA0}}; -CAN_frame BMW_6F1_CONTINUE = {.FD = false, .ext_ID = false, .DLC = 4, .ID = 0x6F1, .data = {0x07, 0x30, 0x00, 0x02}}; CAN_frame BMW_6F4_CELL_VOLTAGE_CELLNO = {.FD = false, .ext_ID = false, .DLC = 7, .ID = 0x6F4, - .data = {0x07, 0x05, 0x31, 0x01, 0xAD, 0x6E, 0x01}}; -CAN_frame BMW_6F4_CELL_CONTINUE = {.FD = false, + .data = {0x07, 0x05, 0x31, 0x01, 0xAD, 0x6E, 0x01}}; // gives error +CAN_frame BMW_6F4_CELL_CONTINUE = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, @@ -43,8 +171,37 @@ CAN_frame BMW_6F4_CELL_CONTINUE = {.FD = false, static bool battery_awake = false; +//iX Intermediate vars +static int32_t battery_current = 0; +static int16_t battery_voltage = 0; +static int16_t battery_voltage_after_contactor = 0; +static int16_t min_soc_state = 0; +static int16_t avg_soc_state = 0; +static int16_t max_soc_state = 0; +static int16_t remaining_capacity = 0; +static int16_t max_capacity = 0; +static int16_t min_battery_temperature = 0; +static int16_t avg_battery_temperature = 0; +static int16_t max_battery_temperature = 0; +static int16_t main_contactor_temperature = 0; +static int16_t min_cell_voltage = 0; +static int16_t max_cell_voltage = 0; +static int16_t battery_power = 0; +static uint8_t uds_req_id_counter = 0; +static byte iX_0C0_counter = 0xF0; // Initialize to 0xF0 + +//End iX Intermediate vars + static uint8_t current_cell_polled = 0; +static uint8_t increment_uds_req_id_counter(uint8_t counter) { + counter++; + if (counter > 7) { + counter = 0; + } + return counter; +} + static uint8_t increment_alive_counter(uint8_t counter) { counter++; if (counter > ALIVE_MAX_VALUE) { @@ -53,29 +210,48 @@ static uint8_t increment_alive_counter(uint8_t counter) { return counter; } +static byte increment_0C0_counter(byte counter) { + counter++; + // Reset to 0xF0 if it exceeds 0xFE + if (counter > 0xFE) { + counter = 0xF0; + } + return counter; +} + void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer - datalayer.battery.status.real_soc; + datalayer.battery.status.real_soc = avg_soc_state; - datalayer.battery.status.voltage_dV; + datalayer.battery.status.voltage_dV = battery_voltage; - datalayer.battery.status.current_dA; + datalayer.battery.status.current_dA = battery_current; - datalayer.battery.info.total_capacity_Wh; + datalayer.battery.info.total_capacity_Wh = max_capacity; - datalayer.battery.status.remaining_capacity_Wh; + datalayer.battery.status.remaining_capacity_Wh = remaining_capacity; - datalayer.battery.status.soh_pptt; + datalayer.battery.status.soh_pptt = 9900; - datalayer.battery.status.max_discharge_power_W; + datalayer.battery.status.max_discharge_power_W = 6000; - datalayer.battery.status.max_charge_power_W; + datalayer.battery.status.max_charge_power_W = 6000; - datalayer.battery.status.active_power_W; + battery_power = (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); - datalayer.battery.status.temperature_min_dC; + datalayer.battery.status.active_power_W = battery_power; - datalayer.battery.status.temperature_max_dC; + datalayer.battery.status.temperature_min_dC = min_battery_temperature; + + datalayer.battery.status.temperature_max_dC = max_battery_temperature; + + datalayer.battery.status.cell_min_voltage_mV = min_cell_voltage; + + datalayer.battery.status.cell_max_voltage_mV = max_cell_voltage; + + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + + datalayer.battery.info.number_of_cells = 108; //Hardcoded for the SE26 battery until values found } void receive_can_battery(CAN_frame rx_frame) { @@ -83,6 +259,101 @@ void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x112: break; + case 0x607: //SME responds to UDS requests on 0x607 + + if (rx_frame.DLC > 6 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x10 && rx_frame.data.u8[2] == 0xE3 && rx_frame.data.u8[3] == 0x62 && rx_frame.data.u8[4] == 0xE5){ + //First of multi frame data - Parse the first frame + if (rx_frame.DLC = 64 && rx_frame.data.u8[5] == 0x54) { //Individual Cell Voltages - First Frame + int start_index = 6; //Data starts here + int voltage_index = 0; //Start cell ID + int num_voltages = 29; // number of voltage readings to get + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { + uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; + datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + } + } + + //Frame has continued data - so request it + transmit_can(&BMWiX_6F4_CONTINUE_DATA, can_config.battery); + } + + if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x21){ //Individual Cell Voltages - 1st Continue frame + int start_index = 2; //Data starts here + int voltage_index = 29; //Start cell ID + int num_voltages = 31; // number of voltage readings to get + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { + uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; + datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + } + } + + if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x22){ //Individual Cell Voltages - 2nd Continue frame + int start_index = 2; //Data starts here + int voltage_index = 60; //Start cell ID + int num_voltages = 31; // number of voltage readings to get + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { + uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; + datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + } + } + + if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x23){ //Individual Cell Voltages - 3rd Continue frame + int start_index = 2; //Data starts here + int voltage_index = 91; //Start cell ID + int num_voltages = 17; // number of voltage readings to get + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { + uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; + datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + } + } + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0x4D) { //Main Battery Voltage (Pre Contactor) + battery_voltage = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6])/10; + } + + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0x4A) { //Main Battery Voltage (After Contactor) + battery_voltage_after_contactor = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); + } + + + if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x61) { //Current amps 32bit signed MSB. dA . negative is discharge + battery_current = (int32_t)((rx_frame.data.u8[5] << 24) | + (rx_frame.data.u8[6] << 16) | + (rx_frame.data.u8[7] << 8) | + rx_frame.data.u8[8]); + } + + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0xCE) { //Min/Avg/Max SOC% + min_soc_state = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); + avg_soc_state = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); + max_soc_state = (rx_frame.data.u8[10] <<8 |rx_frame.data.u8[11]); + } + + if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0xC7) { //Current and max capacity kWh. Stored in kWh as 0.01 scale with -50 bias + remaining_capacity = ((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) *1) -5000; + max_capacity = ((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) *1) -5000; //uint16 limits to 65 + #ifdef DEBUG_VIA_USB + Serial.print("Remaining Capacty: "); + Serial.println( remaining_capacity); + Serial.print("Max Capacty: "); + Serial.println(max_capacity); + #endif //DEBUG_VIA_USB + } + + if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x53) { //Min and max cell voltage + min_cell_voltage = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); + max_cell_voltage = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); + } + + if (rx_frame.DLC = 16 && rx_frame.data.u8[4] == 0xDD && rx_frame.data.u8[5] == 0xC0) { //Battery Temperature + min_battery_temperature = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7])/10; + avg_battery_temperature = (rx_frame.data.u8[10] <<8 | rx_frame.data.u8[11])/10; + max_battery_temperature = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9])/10; + } + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA3) { //Main Contactor Temperature CHECK FINGERPRINT 2 LEVEL + main_contactor_temperature = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); + + } + break; default: break; } @@ -105,10 +376,58 @@ void send_can_battery() { // Send 100ms CAN Message if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; + + uds_req_id_counter = increment_uds_req_id_counter(uds_req_id_counter); + switch (uds_req_id_counter){ + case 0: + //BMWiX_6F4.data.u8[3] = 0x22; + BMWiX_6F4.data.u8[3] = 0xDD; + BMWiX_6F4.data.u8[4] = 0xC0; + transmit_can(&BMWiX_6F4, can_config.battery); + break; + case 1: + BMWiX_6F4.data.u8[3] = 0xE5; + BMWiX_6F4.data.u8[4] = 0xCE; + transmit_can(&BMWiX_6F4, can_config.battery); + break; + case 2: + BMWiX_6F4.data.u8[4] = 0xC7; + transmit_can(&BMWiX_6F4, can_config.battery); + break; + case 3: + BMWiX_6F4.data.u8[4] = 0x53; + transmit_can(&BMWiX_6F4, can_config.battery); + break; + case 4: + BMWiX_6F4.data.u8[4] = 0x4A; + transmit_can(&BMWiX_6F4, can_config.battery); + break; + case 5: + BMWiX_6F4.data.u8[4] = 0x4D; + transmit_can(&BMWiX_6F4, can_config.battery); + break; + case 6: + BMWiX_6F4.data.u8[4] = 0x61; + transmit_can(&BMWiX_6F4, can_config.battery); + break; + case 7: + BMWiX_6F4.data.u8[4] = 0x54; + transmit_can(&BMWiX_6F4, can_config.battery); + break; + } + + + //Send SME Keep alive values 100ms + transmit_can(&BMWiX_510, can_config.battery); + } // Send 200ms CAN Message if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { previousMillis200 = currentMillis; + + //Send SME Keep alive values 200ms + BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 + transmit_can(&BMWiX_0C0, can_config.battery); } // Send 500ms CAN Message if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { @@ -122,17 +441,22 @@ void send_can_battery() { if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { previousMillis1000 = currentMillis; + //Send SME Keep alive values 1000ms + transmit_can(&BMWiX_06D, can_config.battery); + transmit_can(&BMWiX_2F1, can_config.battery); + transmit_can(&BMWiX_439, can_config.battery); + switch (cmdState) { case SOC: - transmit_can(&BMW_6F1_CELL, can_config.battery); + transmit_can(&BMW_6F4_CELL, can_config.battery); cmdState = CELL_VOLTAGE_MINMAX; break; case CELL_VOLTAGE_MINMAX: - transmit_can(&BMW_6F1_SOH, can_config.battery); + transmit_can(&BMW_6F4_SOH, can_config.battery); cmdState = SOH; break; case SOH: - transmit_can(&BMW_6F1_CELL_VOLTAGE_AVG, can_config.battery); + transmit_can(&BMW_6F4_CELL_VOLTAGE_AVG, can_config.battery); cmdState = CELL_VOLTAGE_CELLNO; current_cell_polled = 0; @@ -150,7 +474,7 @@ void send_can_battery() { } break; case CELL_VOLTAGE_CELLNO_LAST: - transmit_can(&BMW_6F1_SOC, can_config.battery); + transmit_can(&BMW_6F4_SOC, can_config.battery); cmdState = SOC; break; } @@ -188,6 +512,17 @@ void setup_battery(void) { // Performs one time setup at startup pinMode(WUP_PIN, OUTPUT); digitalWrite(WUP_PIN, HIGH); // Wake up the battery + + //Wake Battery + //Send SME Keep alive values 100ms + transmit_can(&BMWiX_510, can_config.battery); + //Send SME Keep alive values 200ms + BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 + transmit_can(&BMWiX_0C0, can_config.battery); + //Send SME Keep alive values 1000ms + transmit_can(&BMWiX_06D, can_config.battery); + transmit_can(&BMWiX_2F1, can_config.battery); + transmit_can(&BMWiX_439, can_config.battery); } #endif From 61616628551a0d5ef6af3c5afcf54ad78b8575ea Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 27 Oct 2024 11:31:22 +0000 Subject: [PATCH 03/48] Update BMW-IX-BATTERY.cpp Fix max/available capacity - now shows correct values. --- Software/src/battery/BMW-IX-BATTERY.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index c13d0eb8..ae17575e 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -36,6 +36,7 @@ No vehicle log available, SME asks for: 0x16 (CCU) 0x91 (EME1) 0xAA (EME2) + 0x?? Suspect there is a drive mode flag somewhere - balancing might only be active in some modes SME Output: @@ -178,8 +179,8 @@ static int16_t battery_voltage_after_contactor = 0; static int16_t min_soc_state = 0; static int16_t avg_soc_state = 0; static int16_t max_soc_state = 0; -static int16_t remaining_capacity = 0; -static int16_t max_capacity = 0; +static int32_t remaining_capacity = 0; +static int32_t max_capacity = 0; static int16_t min_battery_temperature = 0; static int16_t avg_battery_temperature = 0; static int16_t max_battery_temperature = 0; @@ -251,7 +252,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - datalayer.battery.info.number_of_cells = 108; //Hardcoded for the SE26 battery until values found + datalayer.battery.info.number_of_cells = 108; //Hardcoded for the 108S SE27 battery. SE26 96S TODO } void receive_can_battery(CAN_frame rx_frame) { @@ -329,8 +330,8 @@ void receive_can_battery(CAN_frame rx_frame) { } if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0xC7) { //Current and max capacity kWh. Stored in kWh as 0.01 scale with -50 bias - remaining_capacity = ((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) *1) -5000; - max_capacity = ((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) *1) -5000; //uint16 limits to 65 + remaining_capacity = ((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) *10) -50000; + max_capacity = ((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) *10) -50000; #ifdef DEBUG_VIA_USB Serial.print("Remaining Capacty: "); Serial.println( remaining_capacity); From f3f10b1db13577df1f4808cc66f218853f2b69d9 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 27 Oct 2024 11:36:15 +0000 Subject: [PATCH 04/48] Removed some debugging (max/remain capacity fixed) --- Software/src/battery/BMW-IX-BATTERY.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index ae17575e..c7d59f41 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -332,12 +332,6 @@ void receive_can_battery(CAN_frame rx_frame) { if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0xC7) { //Current and max capacity kWh. Stored in kWh as 0.01 scale with -50 bias remaining_capacity = ((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) *10) -50000; max_capacity = ((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) *10) -50000; - #ifdef DEBUG_VIA_USB - Serial.print("Remaining Capacty: "); - Serial.println( remaining_capacity); - Serial.print("Max Capacty: "); - Serial.println(max_capacity); - #endif //DEBUG_VIA_USB } if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x53) { //Min and max cell voltage From adfa9f13e7ba14474c8705678b2ad3ac277f3f43 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 27 Oct 2024 12:29:19 +0000 Subject: [PATCH 05/48] iX Advanced Info support addition --- Software/src/devboard/webserver/advanced_battery_html.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index e8001d0c..99ff2201 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -16,6 +16,11 @@ String advanced_battery_processor(const String& var) { // Start a new block with a specific background color content += "
"; + +#ifdef BMW_IX_BATTERY + content += "

T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + "mV

"; +#endif //BMW_IX_BATTERY + #ifdef BMW_I3_BATTERY content += "

SOC raw: " + String(datalayer_extended.bmwi3.SOC_raw) + "

"; content += "

SOC dash: " + String(datalayer_extended.bmwi3.SOC_dash) + "

"; @@ -152,7 +157,7 @@ String advanced_battery_processor(const String& var) { #endif #if !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && \ - !defined(BMW_I3_BATTERY) //Only the listed types have extra info + !defined(BMW_I3_BATTERY)&& !defined(BMW_IX_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif From 4c15d35144b73393d4be5f05486916843795f0fe Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 27 Oct 2024 12:29:53 +0000 Subject: [PATCH 06/48] Add iX advanced values support --- Software/src/datalayer/datalayer_extended.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 96bd5e07..aecbed70 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -3,6 +3,15 @@ #include "../include.h" +typedef struct { + /** uint16_t */ + /** Terminal 30 - 12V SME Supply Voltage */ + uint16_t T30_Voltage = 0; + /** Status HVIL, 1 HVIL OK, 0 HVIL disconnected*/ + uint8_t HVIL_Status= 0; +} DATALAYER_INFO_BMWIX; + + typedef struct { /** uint16_t */ /** SOC% raw battery value. Might not always reach 100% */ @@ -118,6 +127,7 @@ typedef struct { class DataLayerExtended { public: + DATALAYER_INFO_BMWIX bmwix; DATALAYER_INFO_BMWI3 bmwi3; DATALAYER_INFO_TESLA tesla; DATALAYER_INFO_NISSAN_LEAF nissanleaf; From 8fbc4d829ea4f790c847e2d4d8681feee40ac1be Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 27 Oct 2024 12:32:44 +0000 Subject: [PATCH 07/48] IX Advanced values support - Battery module Adds support for showing advanced values - T30 voltage (12v SME Supply) --- Software/src/battery/BMW-IX-BATTERY.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index c7d59f41..0b0b5a69 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -33,7 +33,10 @@ Suspected Vehicle comms required: No vehicle log available, SME asks for: 0x125 (CCU) - 0x16 (CCU) + 0x16E (CCU) + 0x340 (CCU) + 0x4F8 (CCU) + 0x188 (CCU) 0x91 (EME1) 0xAA (EME2) 0x?? Suspect there is a drive mode flag somewhere - balancing might only be active in some modes @@ -175,6 +178,7 @@ static bool battery_awake = false; //iX Intermediate vars static int32_t battery_current = 0; static int16_t battery_voltage = 0; +static int16_t terminal30_12v_voltage = 0; static int16_t battery_voltage_after_contactor = 0; static int16_t min_soc_state = 0; static int16_t avg_soc_state = 0; @@ -197,7 +201,7 @@ static uint8_t current_cell_polled = 0; static uint8_t increment_uds_req_id_counter(uint8_t counter) { counter++; - if (counter > 7) { + if (counter > 8) { counter = 0; } return counter; @@ -253,6 +257,8 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; datalayer.battery.info.number_of_cells = 108; //Hardcoded for the 108S SE27 battery. SE26 96S TODO + + datalayer_extended.bmwix.T30_Voltage = terminal30_12v_voltage; } void receive_can_battery(CAN_frame rx_frame) { @@ -346,7 +352,9 @@ void receive_can_battery(CAN_frame rx_frame) { } if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA3) { //Main Contactor Temperature CHECK FINGERPRINT 2 LEVEL main_contactor_temperature = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); - + } + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA7) { //Terminal 30 Voltage (12V SME supply) + terminal30_12v_voltage = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); } break; default: @@ -409,6 +417,10 @@ void send_can_battery() { BMWiX_6F4.data.u8[4] = 0x54; transmit_can(&BMWiX_6F4, can_config.battery); break; + case 8: + BMWiX_6F4.data.u8[4] = 0xA7; //Terminal 30 12v voltage + transmit_can(&BMWiX_6F4, can_config.battery); + break; } From 774c544bca3093c47cb78b56f4932fab7ced9edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 29 Oct 2024 20:38:24 +0200 Subject: [PATCH 08/48] Add contactor opening incase of FAULT --- Software/src/battery/TESLA-BATTERY.cpp | 33 ++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index a35751d9..3eac62cc 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -22,7 +22,7 @@ CAN_frame TESLA_221_2 = { .DLC = 8, .ID = 0x221, .data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive - +static uint16_t sendContactorClosingMessagesStill = 300; static uint32_t battery_total_discharge = 0; static uint32_t battery_total_charge = 0; static uint16_t battery_volts = 0; // V @@ -1003,7 +1003,7 @@ unsigned long lastSend118 = 0; int index_1CF = 0; int index_118 = 0; -#endif +#endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) void send_can_battery() { /*From bielec: My fist 221 message, to close the contactors is 0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96 and then, @@ -1014,13 +1014,13 @@ the first, for a few cycles, then stop all messages which causes the contactor unsigned long currentMillis = millis(); #if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) - if (datalayer.system.status.inverter_allows_contactor_closing) { + if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { if (currentMillis - lastSend1CF >= 10) { transmit_can(&can_msg_1CF[index_1CF], can_config.battery); #ifdef DOUBLE_BATTERY transmit_can(&can_msg_1CF[index_1CF], can_config.battery_double); -#endif +#endif // DOUBLE_BATTERY index_1CF = (index_1CF + 1) % 8; lastSend1CF = currentMillis; @@ -1030,7 +1030,7 @@ the first, for a few cycles, then stop all messages which causes the contactor transmit_can(&can_msg_118[index_118], can_config.battery); #ifdef DOUBLE_BATTERY transmit_can(&can_msg_1CF[index_1CF], can_config.battery_double); -#endif +#endif //DOUBLE_BATTERY index_118 = (index_118 + 1) % 16; lastSend118 = currentMillis; @@ -1039,7 +1039,7 @@ the first, for a few cycles, then stop all messages which causes the contactor index_1CF = 0; index_118 = 0; } -#endif +#endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) //Send 30ms message if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { @@ -1051,15 +1051,26 @@ the first, for a few cycles, then stop all messages which causes the contactor } previousMillis30 = currentMillis; - if (datalayer.system.status.inverter_allows_contactor_closing) { + if ((datalayer.system.status.inverter_allows_contactor_closing == true) && + (datalayer.battery.status.bms_status != FAULT)) { + sendContactorClosingMessagesStill = 300; transmit_can(&TESLA_221_1, can_config.battery); transmit_can(&TESLA_221_2, can_config.battery); #ifdef DOUBLE_BATTERY if (datalayer.system.status.battery2_allows_contactor_closing) { - transmit_can(&TESLA_221_1, can_config.battery_double); // CAN2 connected to battery 2 + transmit_can(&TESLA_221_1, can_config.battery_double); transmit_can(&TESLA_221_2, can_config.battery_double); } +#endif //DOUBLE_BATTERY + } else { // Faulted state, or inverter blocks contactor closing + if (sendContactorClosingMessagesStill > 0) { + transmit_can(&TESLA_221_1, can_config.battery); + sendContactorClosingMessagesStill--; + +#ifdef DOUBLE_BATTERY + transmit_can(&TESLA_221_1, can_config.battery_double); #endif //DOUBLE_BATTERY + } } } } @@ -1091,7 +1102,8 @@ void printFaultCodesIfActive() { } if (datalayer.system.status.inverter_allows_contactor_closing == false) { Serial.println( - "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter OR " + "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter " + "OR " "disable the inverter protocol to proceed with contactor closing"); } // Check each symbol and print debug information if its value is 1 @@ -1166,7 +1178,8 @@ void printFaultCodesIfActive_battery2() { } if (datalayer.system.status.inverter_allows_contactor_closing == false) { Serial.println( - "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter OR " + "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter " + "OR " "disable the inverter protocol to proceed with contactor closing"); } // Check each symbol and print debug information if its value is 1 From 280ac3cbee51e6ac371c32b0a50048d2ec38507f Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:40:04 +0000 Subject: [PATCH 09/48] 0.2alpha version - Update BMW-IX-BATTERY.h --- Software/src/battery/BMW-IX-BATTERY.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 8c2e24c9..46ea9820 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -5,8 +5,8 @@ #define BATTERY_SELECTED -#define WUP_PIN 25 -#define MAX_PACK_VOLTAGE_DV 5000 //5000 = 500.0V +//#define WUP_PIN 25 //Not used +#define MAX_PACK_VOLTAGE_DV 4600 //4600 = 460.0V #define MIN_PACK_VOLTAGE_DV 3000 #define MAX_CELL_DEVIATION_MV 500 #define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value From 9ea8458bf7d4a14080695cf283e4c7455dc05166 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:40:25 +0000 Subject: [PATCH 10/48] 0.2alpha version - Update BMW-IX-BATTERY.cpp --- Software/src/battery/BMW-IX-BATTERY.cpp | 503 +++++++++++++----------- 1 file changed, 270 insertions(+), 233 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 0b0b5a69..4f4627f8 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -23,14 +23,29 @@ static CmdState cmdState = SOC; /* Suspected Vehicle comms required: - 0x06D DLC? 1000ms - counters? 0x2F1 DLC? 1000ms during run : 0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x00, 0xF3, 0xFF - at startup 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xF3, 0xFF. Suspect byte [4] is a counter 0x439 DLC4 1000ms STATIC 0x0C0 DLC2 200ms needs counter - 0x510 DLC8 100ms STATIC 40 10 40 00 6F DF 19 00 during run - Startup sends this once: 0x40 0x10 0x02 0x00 0x00 0x00 0x00 0x00 0x587 DLC8 appears at startup 0x78 0x07 0x00 0x00 0xFF 0xFF 0xFF 0xFF , 0x01 0x03 0x80 0xFF 0xFF 0xFF 0xFF 0xFF, 0x78 0x07 0x00 0x00 0xFF 0xFF 0xFF 0xFF, 0x06 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF, 0x01 0x03 0x82 0xFF 0xFF 0xFF 0xFF 0xFF, 0x01 0x03 0x80 0xFF 0xFF 0xFF 0xFF 0xFF +SME Output: + 0x08F DLC48 10ms - Appears to have analog readings like volt/temp/current + 0x12B8D087 5000ms - Extended ID + 0x1D2 DLC8 1000ms + 0x20B DLC8 1000ms + 0x2E2 DLC16 1000ms + 0x2F1 DLC8 1000ms + 0x31F DLC16 100ms - 2 downward counters? + 0x453 DLC20 200ms + 0x486 DLC48 1000ms + 0x49C DLC8 1000ms + 0x4A1 DLC8 1000ms + 0x4BB DLC64 200ms - seems multplexed on [0] + 0x4D0 DLC64 1000ms - some slow/flickering values - possible change during fault + 0x510 DLC8 100ms STATIC 40 10 40 00 6F DF 19 00 during run - Startup sends this once: 0x40 0x10 0x02 0x00 0x00 0x00 0x00 0x00 + 0x607 UDS Response + No vehicle log available, SME asks for: 0x125 (CCU) 0x16E (CCU) @@ -41,148 +56,120 @@ No vehicle log available, SME asks for: 0xAA (EME2) 0x?? Suspect there is a drive mode flag somewhere - balancing might only be active in some modes -SME Output: - - 0x08F DLC48 10ms - Appears to have analog readings like volt/temp/current - 0x1D2 DLC8 1000ms - 0x20B DLC8 1000ms - 0x2E2 DLC16 1000ms - 0x2F1 DLC8 1000ms - 0x31F DLC16 100ms - 2 downward counters? - 0x453 DLC20 200ms - 0x486 DLC48 1000ms - 0x49C DLC8 1000ms - 0x4A1 DLC8 1000ms - 0x4BB DLC64 200ms - seems multplexed on [0] - 0x4D0 DLC64 1000ms - some slow/flickering values - 0x607 UDS Response +TODO -UDS Map: - 69 - service disconnect (1 = closed) - c7 - available energy - available energy charged - ce - min avg max SOC - 61 len12 = current sensor - 53 - min and max cell voltage - 4d- main battery voltage - 4a - after contactor voltage - a4 = charnging contactor temp - A3 - MAIN CONTACTOR VOLTAGE - f4 00 0a 62 DD = main battery temp - A7 - T30 12v voltage (SME input voltage) - B6 - T30C 12v voltage (12v pyro sensor) - 51 = release, switch contactors. 1 = control of switch contactors active - CD = charge contactors - - TX 07 03 22 E5 54 - UDS request cell voltages - RX F4 10 E3 62 E5 54 - 16bit cell voltages batch1 (29 cells) - TX 07 30 00 02 - UDS request continue data - RX F4 21 0F - 16bit cell voltages continue2 (31 cells) - RX F4 22 0F - 16bit cell voltages continue3 (31 cells) - RX F4 23 0F - 16bit cell voltages continue4 (17 cells) - - TX 07 03 22 E5 9A - UDS request cell SOC - RX F4 10 E3 62 E5 9A?? - 16bit cell SOC batch1 (29 cells) - - TX 07 03 22 E5 CA - UDS request cell temps - RX F4 10 81 62 E5 CA - 16bit cell temps batch1 - RX F4 21 81 62 E5 CA - 16bit cell temps continue2 - - TX 07 30 00 02 - UDS request continue data - +- Request batt serial number on F1 8C (already parsing RX) +- Check PWM required from ACSM +- Use voltage qualifier for extended data? +- More Balancing values +- Check for stale min/max values +- Prevent fault state on SME reset */ +//Vehicle CAN START +CAN_frame BMWiX_06D = {.FD = true, .ext_ID = false, .DLC = 8, .ID = 0x06D, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF}}; // 1000ms BDC Output - [0] static [1,2][3,4] counter x2. 3,4 is 9 higher than 1,2 is needed? [5-7] static +CAN_frame BMWiX_0C0 = {.FD = true, .ext_ID = false, .DLC = 2, .ID = 0x0C0, + .data = {0xF0, 0x08}}; // Keep Alive 2 BDC>SME 200ms First byte cycles F0 > FE second byte 08 static - MINIMUM ID TO KEEP SME AWAKE -CAN_frame BMWiX_06D = {.FD = true, - .ext_ID = false, - .DLC = 8, - .ID = 0x06D, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF}}; // 1000ms BDC Output - [0] static [1]-[4] counter x2? is needed? [5-7] static +CAN_frame BMWiX_276 = {.FD = true, .ext_ID = false, .DLC = 8, .ID = 0x476, + .data = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC}}; // 5000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED - -CAN_frame BMWiX_2F1 = {.FD = true, - .ext_ID = false, - .DLC = 8, - .ID = 0x2F1, +CAN_frame BMWiX_2F1 = {.FD = true, .ext_ID = false, .DLC = 8, .ID = 0x2F1, .data = {0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x00, 0xF3, 0xFF}}; // 1000ms BDC Output - Static values - varies at startup - - -CAN_frame BMWiX_439 = {.FD = true, - .ext_ID = false, - .DLC = 4, - .ID = 0x439, +CAN_frame BMWiX_439 = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x439, .data = {0xFF, 0xBF, 0xFF, 0xFF}}; // 1000ms BDC Output - Static values +CAN_frame BMWiX_486 = {.FD = true, .ext_ID = false, .DLC = 48, .ID = 0x486, + .data = {0xFE, 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFF , 0x7F , 0x33 , 0xFD , 0xFD , 0xFD , 0xFD , 0xC0 , 0x41 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF}}; // 1000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED +CAN_frame BMWiX_49C = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x49C, + .data = {0xD2, 0xF2, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; // 1000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED -CAN_frame BMWiX_510 = {.FD = true, - .ext_ID = false, - .DLC = 8, - .ID = 0x510, +CAN_frame BMWiX_510 = {.FD = true, .ext_ID = false, .DLC = 8, .ID = 0x510, .data = {0x40, 0x10, 0x40, 0x00, 0x6F, 0xDF, 0x19, 0x00}}; // 100ms BDC Output - Static values +CAN_frame BMWiX_12B8D087 = {.FD = true, .ext_ID = true, .DLC = 2, .ID = 0x12B8D087, + .data = {0xFC, 0xFF}}; // 5000ms SME Output - Static values +//Vehicle CAN END - -CAN_frame BMWiX_6F4 = {.FD = true, - .ext_ID = false, - .DLC = 5, - .ID = 0x6F4, - .data = {0x07, 0x03, 0x22, 0xE5, 0xC7}}; // UDS Request data from SME. byte 4 selects requested value - - -CAN_frame BMWiX_0C0 = {.FD = true, - .ext_ID = false, - .DLC = 2, - .ID = 0x0C0, - .data = {0xF0, 0x08}}; // Keep Alive 2 BDC>SME 200ms First byte cycles F0 > FE second byte 08 static - - -CAN_frame BMWiX_6F4_CELL_VOLTAGE = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x54}}; -CAN_frame BMWiX_6F4_CELL_SOC = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x9A}}; -CAN_frame BMWiX_6F4_CELL_TEMP = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xCA}}; +//Request Data CAN START +CAN_frame BMWiX_6F4 = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xC7}}; // Generic UDS Request data from SME. byte 4 selects requested value +CAN_frame BMWiX_6F4_REQUEST_SLEEPMODE = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x6F4, .data = {0x07, 0x02, 0x11, 0x04}}; // UDS Request Request BMS/SME goes to Sleep Mode +CAN_frame BMWiX_6F4_REQUEST_HARD_RESET = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x6F4, .data = {0x07, 0x02, 0x11, 0x01}}; // UDS Request Hard reset of BMS/SME +CAN_frame BMWiX_6F4_REQUEST_CELL_TEMP = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xDD, 0xC0}}; // UDS Request Cell Temperatures +CAN_frame BMWiX_6F4_REQUEST_SOC = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xCE}}; // Min/Avg/Max SOC% +CAN_frame BMWiX_6F4_REQUEST_CAPACITY = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xC7}}; //Current and max capacity kWh. Stored in kWh as 0.01 scale with -50 bias +CAN_frame BMWiX_6F4_REQUEST_MINMAXCELLV = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x53}}; //Min and max cell voltage 10V = Qualifier Invalid +CAN_frame BMWiX_6F4_REQUEST_MAINVOLTAGE_POSTCONTACTOR = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4A}}; //Main Battery Voltage (After Contactor) +CAN_frame BMWiX_6F4_REQUEST_MAINVOLTAGE_PRECONTACTOR = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4D}}; //Main Battery Voltage (Pre Contactor) +CAN_frame BMWiX_6F4_REQUEST_BATTERYCURRENT = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x61}}; //Current amps 32bit signed MSB. dA . negative is discharge +CAN_frame BMWiX_6F4_REQUEST_CELL_VOLTAGE = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x54}}; //MultiFrameIndividual Cell Voltages +CAN_frame BMWiX_6F4_REQUEST_T30VOLTAGE = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xA7}}; //Terminal 30 Voltage (12V SME supply) +CAN_frame BMWiX_6F4_REQUEST_EOL_ISO = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xA8, 0x60}}; //Request EOL Reading including ISO +CAN_frame BMWiX_6F4_REQUEST_SOH = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x45}}; //SOH Max Min Mean Request +CAN_frame BMWiX_6F4_REQUEST_DATASUMMARY = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x45}}; //MultiFrame Summary Request, includes SOC/SOH/MinMax/MaxCapac/RemainCapac/max v and t at last charge. slow refreshrate +CAN_frame BMWiX_6F4_REQUEST_PYRO = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xAC, 0x93}}; //Pyro Status +CAN_frame BMWiX_6F4_REQUEST_UPTIME = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE4, 0xC0}}; // Uptime and Vehicle Time Status +CAN_frame BMWiX_6F4_REQUEST_HVIL = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x69}}; // Request HVIL State +CAN_frame BMWiX_6F4_REQUEST_BALANCINGSTATUS = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE4, 0xCA}}; // Request Balancing Data +CAN_frame BMWiX_6F4_REQUEST_MAX_CHARGE_DISCHARGE_AMPS = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x62}}; // Request allowable charge discharge amps +CAN_frame BMWiX_6F4_REQUEST_QUALIFIER_CHECK = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4B}}; // Request HV Voltage Qualifier +CAN_frame BMWiX_6F4_REQUEST_CONTACTORS_CLOSE = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x51, 0x01}}; // Request Contactors Close - Unconfirmed +CAN_frame BMWiX_6F4_REQUEST_CONTACTORS_OPEN = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x51, 0x01}}; // Request Contactors Open - Unconfirmed +CAN_frame BMWiX_6F4_REQUEST_BALANCING_START = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0xF4, 0x04, 0x71, 0x01, 0xAE, 0x77}}; // Request Balancing command? CAN_frame BMWiX_6F4_CONTINUE_DATA = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x6F4, .data = {0x07, 0x30, 0x00, 0x02}}; -CAN_frame BMW_6F4_CELL = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xDD, 0xBF}};// gives error F4 03 7F 22 31 -CAN_frame BMW_6F4_SOH = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0x63, 0x35}}; // gives error F4 03 7F 22 31 -CAN_frame BMW_6F4_SOC = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xDD, 0xBC}}; // gives blanks +//Action Requests: +CAN_frame BMW_10B = {.FD = true, .ext_ID = false, .DLC = 3, .ID = 0x10B, .data = {0xCD, 0x00, 0xFC}}; // Contactor closing command? -CAN_frame BMW_10B = {.FD = true, - .ext_ID = false, - .DLC = 3, - .ID = 0x10B, - .data = {0xCD, 0x00, 0xFC}}; // Contactor closing command - -CAN_frame BMW_6F4_CELL_VOLTAGE_AVG = {.FD = true, - .ext_ID = false, - .DLC = 5, - .ID = 0x6F4, - .data = {0x07, 0x03, 0x22, 0xDF, 0xA0}}; -CAN_frame BMW_6F4_CELL_VOLTAGE_CELLNO = {.FD = false, - .ext_ID = false, - .DLC = 7, - .ID = 0x6F4, - .data = {0x07, 0x05, 0x31, 0x01, 0xAD, 0x6E, 0x01}}; // gives error -CAN_frame BMW_6F4_CELL_CONTINUE = {.FD = true, - .ext_ID = false, - .DLC = 6, - .ID = 0x6F4, - .data = {0x07, 0x04, 0x31, 0x03, 0xAD, 0x6E}}; +CAN_frame BMWiX_6F4_CELL_SOC = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x9A}}; +CAN_frame BMWiX_6F4_CELL_TEMP = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xCA}}; +//Request Data CAN End static bool battery_awake = false; +//Setup UDS values to poll for +CAN_frame* UDS_REQUESTS100MS[] = { + &BMWiX_6F4_REQUEST_CELL_TEMP, + &BMWiX_6F4_REQUEST_SOC, + &BMWiX_6F4_REQUEST_CAPACITY, + &BMWiX_6F4_REQUEST_MINMAXCELLV, + &BMWiX_6F4_REQUEST_MAINVOLTAGE_POSTCONTACTOR, + &BMWiX_6F4_REQUEST_MAINVOLTAGE_PRECONTACTOR, + &BMWiX_6F4_REQUEST_BATTERYCURRENT, + &BMWiX_6F4_REQUEST_CELL_VOLTAGE, + &BMWiX_6F4_REQUEST_T30VOLTAGE, + &BMWiX_6F4_REQUEST_SOH, + &BMWiX_6F4_REQUEST_UPTIME, + &BMWiX_6F4_REQUEST_PYRO, + &BMWiX_6F4_REQUEST_EOL_ISO, + &BMWiX_6F4_REQUEST_HVIL, + &BMWiX_6F4_REQUEST_MAX_CHARGE_DISCHARGE_AMPS, + &BMWiX_6F4_REQUEST_BALANCINGSTATUS + }; +int numUDSreqs = sizeof(UDS_REQUESTS100MS) / sizeof(UDS_REQUESTS100MS[0]); // Number of elements in the array + //iX Intermediate vars +static uint32_t battery_serial_number = 0; static int32_t battery_current = 0; -static int16_t battery_voltage = 0; +static int16_t battery_voltage = 370; static int16_t terminal30_12v_voltage = 0; static int16_t battery_voltage_after_contactor = 0; -static int16_t min_soc_state = 0; -static int16_t avg_soc_state = 0; -static int16_t max_soc_state = 0; +static int16_t min_soc_state = 50; +static int16_t avg_soc_state = 50; +static int16_t max_soc_state = 50; +static int16_t min_soh_state = 99;// Uses E5 45, also available in 78 73 +static int16_t avg_soh_state = 99;// Uses E5 45, also available in 78 73 +static int16_t max_soh_state = 99;// Uses E5 45, also available in 78 73 +static uint16_t battery_max_charge_voltage = 0; +static uint16_t battery_min_discharge_voltage = 0; static int32_t remaining_capacity = 0; static int32_t max_capacity = 0; static int16_t min_battery_temperature = 0; @@ -191,20 +178,41 @@ static int16_t max_battery_temperature = 0; static int16_t main_contactor_temperature = 0; static int16_t min_cell_voltage = 0; static int16_t max_cell_voltage = 0; +static unsigned min_cell_voltage_lastreceived = 0; +static unsigned max_cell_voltage_lastreceived = 0; static int16_t battery_power = 0; +static uint32_t sme_uptime = 0; //Uses E4 C0 +static int16_t allowable_charge_amps = 0; //E5 62 +static int16_t allowable_discharge_amps = 0; //E5 62 +static int32_t iso_safety_positive = 0; //Uses A8 60 +static int32_t iso_safety_negative = 0; //Uses A8 60 +static int32_t iso_safety_parallel = 0; //Uses A8 60 +static int16_t count_full_charges = 0; //TODO 42 +static int16_t count_charges = 0; //TODO 42 +static int16_t hvil_status = 0; +static int16_t voltage_qualifier_status = 0; //0 = Valid, 1 = Invalid +static int16_t balancing_status = 0; //4 = not active +static uint8_t contactors_closed = 0; //TODO E5 BF or E5 51 +static uint8_t contactor_status_precharge = 0; //TODO E5 BF +static uint8_t contactor_status_negative = 0; //TODO E5 BF +static uint8_t contactor_status_positive = 0; //TODO E5 BF +static uint8_t pyro_status_pss1 = 0; //Using AC 93 +static uint8_t pyro_status_pss4 = 0; //Using AC 93 +static uint8_t pyro_status_pss6 = 0; //Using AC 93 static uint8_t uds_req_id_counter = 0; + static byte iX_0C0_counter = 0xF0; // Initialize to 0xF0 //End iX Intermediate vars static uint8_t current_cell_polled = 0; -static uint8_t increment_uds_req_id_counter(uint8_t counter) { - counter++; - if (counter > 8) { - counter = 0; +static uint8_t increment_uds_req_id_counter(uint8_t index) { + index++; + if (index >= numUDSreqs) { + index = 0; } - return counter; + return index; } static uint8_t increment_alive_counter(uint8_t counter) { @@ -236,11 +244,11 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.remaining_capacity_Wh = remaining_capacity; - datalayer.battery.status.soh_pptt = 9900; + datalayer.battery.status.soh_pptt = min_soh_state; - datalayer.battery.status.max_discharge_power_W = 6000; + datalayer.battery.status.max_discharge_power_W = 10000; //Aux HV Port has 100A Fuse - datalayer.battery.status.max_charge_power_W = 6000; + datalayer.battery.status.max_charge_power_W = 10000; //Aux HV Port has 100A Fuse battery_power = (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); @@ -256,11 +264,34 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - datalayer.battery.info.number_of_cells = 108; //Hardcoded for the 108S SE27 battery. SE26 96S TODO + datalayer.battery.info.number_of_cells = 108; //init with 108S before autodetection datalayer_extended.bmwix.T30_Voltage = terminal30_12v_voltage; -} + datalayer_extended.bmwix.hvil_status= hvil_status; + + datalayer_extended.bmwix.bms_uptime = sme_uptime; + + datalayer_extended.bmwix.pyro_status_pss1 = pyro_status_pss1; + + datalayer_extended.bmwix.pyro_status_pss4 = pyro_status_pss4; + + datalayer_extended.bmwix.pyro_status_pss6 = pyro_status_pss6; + + datalayer_extended.bmwix.iso_safety_positive = iso_safety_positive; + + datalayer_extended.bmwix.iso_safety_negative = iso_safety_negative; + + datalayer_extended.bmwix.iso_safety_parallel= iso_safety_parallel; + + datalayer_extended.bmwix.allowable_charge_amps = allowable_charge_amps; + + datalayer_extended.bmwix.allowable_discharge_amps= allowable_discharge_amps; + + datalayer_extended.bmwix.balancing_status = balancing_status; + + +} void receive_can_battery(CAN_frame rx_frame) { battery_awake = true; switch (rx_frame.ID) { @@ -276,7 +307,10 @@ void receive_can_battery(CAN_frame rx_frame) { int num_voltages = 29; // number of voltage readings to get for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; - datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + if (voltage < 10000) { //Check reading is plausible - otherwise ignore + datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; + } + voltage_index++; } } @@ -290,7 +324,10 @@ void receive_can_battery(CAN_frame rx_frame) { int num_voltages = 31; // number of voltage readings to get for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; - datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + if (voltage < 10000) { //Check reading is plausible - otherwise ignore + datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; + } + voltage_index++; } } @@ -300,14 +337,25 @@ void receive_can_battery(CAN_frame rx_frame) { int num_voltages = 31; // number of voltage readings to get for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; - datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + if (voltage < 10000) { //Check reading is plausible - otherwise ignore + datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; + } + voltage_index++; } } if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x23){ //Individual Cell Voltages - 3rd Continue frame int start_index = 2; //Data starts here int voltage_index = 91; //Start cell ID - int num_voltages = 17; // number of voltage readings to get + int num_voltages; + if (rx_frame.data.u8[12] == 0xFF && rx_frame.data.u8[13]== 0xFF){ //97th cell is blank - assume 96S Battery + num_voltages = 5; // number of voltage readings to get - 6 more to get on 96S + datalayer.battery.info.number_of_cells = 96; + } else { //We have data in 97th cell, assume 108S Battery + num_voltages = 17; // number of voltage readings to get - 17 more to get on 108S + datalayer.battery.info.number_of_cells = 108; + } + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; @@ -329,6 +377,9 @@ void receive_can_battery(CAN_frame rx_frame) { rx_frame.data.u8[8]); } + if (rx_frame.DLC = 64 && rx_frame.data.u8[4] == 0xE4 && rx_frame.data.u8[5] == 0xCA) { //Balancing Data + balancing_status = ( rx_frame.data.u8[6]); //4 = No symmetry mode active, invalid qualifier + } if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0xCE) { //Min/Avg/Max SOC% min_soc_state = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); avg_soc_state = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); @@ -340,12 +391,52 @@ void receive_can_battery(CAN_frame rx_frame) { max_capacity = ((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) *10) -50000; } - if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x53) { //Min and max cell voltage - min_cell_voltage = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); - max_cell_voltage = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); + if (rx_frame.DLC = 20 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x45) { //SOH Max Min Mean Request + min_soh_state = ((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9])); + avg_soh_state = ((rx_frame.data.u8[10] <<8 | rx_frame.data.u8[11])); + max_soh_state = ((rx_frame.data.u8[12] <<8 | rx_frame.data.u8[13])); } - if (rx_frame.DLC = 16 && rx_frame.data.u8[4] == 0xDD && rx_frame.data.u8[5] == 0xC0) { //Battery Temperature + if (rx_frame.DLC = 10 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x62) { //Max allowed charge and discharge current - Signed 16bit + allowable_charge_amps = (int16_t)((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7])); + allowable_discharge_amps = (int16_t)((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9])); + } + + if (rx_frame.DLC = 9 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x4B) { //Max allowed charge and discharge current - Signed 16bit + voltage_qualifier_status = ( rx_frame.data.u8[8]); // Request HV Voltage Qualifier + } + + if (rx_frame.DLC = 48 && rx_frame.data.u8[4] == 0xA8 && rx_frame.data.u8[5] == 0x60) { // Safety Isolation Measurements + iso_safety_positive = (rx_frame.data.u8[34] << 24) | (rx_frame.data.u8[35] << 16) | (rx_frame.data.u8[36] << 8) |rx_frame.data.u8[37]; //Assuming 32bit + iso_safety_negative = (rx_frame.data.u8[38] << 24) | (rx_frame.data.u8[39] << 16) | (rx_frame.data.u8[40] << 8) |rx_frame.data.u8[41]; //Assuming 32bit + iso_safety_parallel = (rx_frame.data.u8[42] << 24) | (rx_frame.data.u8[43] << 16) | (rx_frame.data.u8[44] << 8) |rx_frame.data.u8[45]; //Assuming 32bit + } + + + if (rx_frame.DLC = 48 && rx_frame.data.u8[4] == 0xE4 && rx_frame.data.u8[5] == 0xC0) { // Uptime and Vehicle Time Status + sme_uptime = (rx_frame.data.u8[10] << 24) | (rx_frame.data.u8[11] << 16) | (rx_frame.data.u8[12] << 8) |rx_frame.data.u8[13]; //Assuming 32bit + } + + if (rx_frame.DLC = 8 && rx_frame.data.u8[3] == 0xAC && rx_frame.data.u8[4] == 0x93) { // Pyro Status + pyro_status_pss1 = (rx_frame.data.u8[5]); + pyro_status_pss4 = (rx_frame.data.u8[6]); + pyro_status_pss6 = (rx_frame.data.u8[7]); + } + + if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x53) { //Min and max cell voltage 10V = Qualifier Invalid + if((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) == 10000 && (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) == 10000){ //Qualifier Invalid Mode - Request Reboot + #ifdef DEBUG_VIA_USB + Serial.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); + #endif + set_event(EVENT_SOC_UNAVAILABLE, (millis())); + transmit_can(&BMWiX_6F4_REQUEST_HARD_RESET, can_config.battery); + } else{ //Only ingest values if they are not the 10V Error state + min_cell_voltage = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); + max_cell_voltage = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); + } + } + + if (rx_frame.DLC = 16 && rx_frame.data.u8[4] == 0xDD && rx_frame.data.u8[5] == 0xC0) { //Battery Temperature min_battery_temperature = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7])/10; avg_battery_temperature = (rx_frame.data.u8[10] <<8 | rx_frame.data.u8[11])/10; max_battery_temperature = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9])/10; @@ -356,6 +447,19 @@ void receive_can_battery(CAN_frame rx_frame) { if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA7) { //Terminal 30 Voltage (12V SME supply) terminal30_12v_voltage = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); } + if (rx_frame.DLC = 6 && rx_frame.data.u8[3] == 0xE5 && rx_frame.data.u8[4] == 0x69) { //HVIL Status + hvil_status = ( rx_frame.data.u8[5]); + } + if (rx_frame.DLC = 16 && rx_frame.data.u8[3] == 0xF1 && rx_frame.data.u8[4] == 0x8C ) { //Battery Serial Number + //Convert hex bytes to ASCII characters and combine them into a string + char numberString[11]; // 10 characters + null terminator + for (int i = 0; i < 10; i++) { + numberString[i] = char(rx_frame.data.u8[i+6]); + } + numberString[10] = '\0'; // Null-terminate the string + // Step 3: Convert the string to an unsigned long integer + battery_serial_number = strtoul(numberString, NULL, 10); + } break; default: break; @@ -365,7 +469,7 @@ void receive_can_battery(CAN_frame rx_frame) { void send_can_battery() { unsigned long currentMillis = millis(); - if (battery_awake) { + //if (battery_awake) { //We can always send CAN as the iX BMS will wake up on vehicle comms //Send 20ms message if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { // Check if sending of CAN messages has been delayed too much. @@ -380,61 +484,22 @@ void send_can_battery() { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; - uds_req_id_counter = increment_uds_req_id_counter(uds_req_id_counter); - switch (uds_req_id_counter){ - case 0: - //BMWiX_6F4.data.u8[3] = 0x22; - BMWiX_6F4.data.u8[3] = 0xDD; - BMWiX_6F4.data.u8[4] = 0xC0; - transmit_can(&BMWiX_6F4, can_config.battery); - break; - case 1: - BMWiX_6F4.data.u8[3] = 0xE5; - BMWiX_6F4.data.u8[4] = 0xCE; - transmit_can(&BMWiX_6F4, can_config.battery); - break; - case 2: - BMWiX_6F4.data.u8[4] = 0xC7; - transmit_can(&BMWiX_6F4, can_config.battery); - break; - case 3: - BMWiX_6F4.data.u8[4] = 0x53; - transmit_can(&BMWiX_6F4, can_config.battery); - break; - case 4: - BMWiX_6F4.data.u8[4] = 0x4A; - transmit_can(&BMWiX_6F4, can_config.battery); - break; - case 5: - BMWiX_6F4.data.u8[4] = 0x4D; - transmit_can(&BMWiX_6F4, can_config.battery); - break; - case 6: - BMWiX_6F4.data.u8[4] = 0x61; - transmit_can(&BMWiX_6F4, can_config.battery); - break; - case 7: - BMWiX_6F4.data.u8[4] = 0x54; - transmit_can(&BMWiX_6F4, can_config.battery); - break; - case 8: - BMWiX_6F4.data.u8[4] = 0xA7; //Terminal 30 12v voltage - transmit_can(&BMWiX_6F4, can_config.battery); - break; - } + //Loop through and send a different UDS request each cycle + uds_req_id_counter = increment_uds_req_id_counter(uds_req_id_counter); + transmit_can(UDS_REQUESTS100MS[uds_req_id_counter], can_config.battery); - //Send SME Keep alive values 100ms - transmit_can(&BMWiX_510, can_config.battery); + //Send SME Keep alive values 100ms + transmit_can(&BMWiX_510, can_config.battery); } // Send 200ms CAN Message if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { previousMillis200 = currentMillis; - //Send SME Keep alive values 200ms - BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 - transmit_can(&BMWiX_0C0, can_config.battery); + //Send SME Keep alive values 200ms + BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 + transmit_can(&BMWiX_0C0, can_config.battery); } // Send 500ms CAN Message if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { @@ -448,43 +513,11 @@ void send_can_battery() { if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { previousMillis1000 = currentMillis; - //Send SME Keep alive values 1000ms - transmit_can(&BMWiX_06D, can_config.battery); - transmit_can(&BMWiX_2F1, can_config.battery); - transmit_can(&BMWiX_439, can_config.battery); + //Send SME Keep alive values 1000ms + //test disable transmit_can(&BMWiX_06D, can_config.battery); + //test disable transmit_can(&BMWiX_2F1, can_config.battery); + //test disable transmit_can(&BMWiX_439, can_config.battery); - switch (cmdState) { - case SOC: - transmit_can(&BMW_6F4_CELL, can_config.battery); - cmdState = CELL_VOLTAGE_MINMAX; - break; - case CELL_VOLTAGE_MINMAX: - transmit_can(&BMW_6F4_SOH, can_config.battery); - cmdState = SOH; - break; - case SOH: - transmit_can(&BMW_6F4_CELL_VOLTAGE_AVG, can_config.battery); - cmdState = CELL_VOLTAGE_CELLNO; - current_cell_polled = 0; - - break; - case CELL_VOLTAGE_CELLNO: - current_cell_polled++; - if (current_cell_polled > 96) { - datalayer.battery.info.number_of_cells = 97; - cmdState = CELL_VOLTAGE_CELLNO_LAST; - } else { - cmdState = CELL_VOLTAGE_CELLNO; - - BMW_6F4_CELL_VOLTAGE_CELLNO.data.u8[6] = current_cell_polled; - transmit_can(&BMW_6F4_CELL_VOLTAGE_CELLNO, can_config.battery); - } - break; - case CELL_VOLTAGE_CELLNO_LAST: - transmit_can(&BMW_6F4_SOC, can_config.battery); - cmdState = SOC; - break; - } } // Send 5000ms CAN Message if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { @@ -494,31 +527,33 @@ void send_can_battery() { if (currentMillis - previousMillis10000 >= INTERVAL_10_S) { previousMillis10000 = currentMillis; } - } else { - previousMillis20 = currentMillis; - previousMillis100 = currentMillis; - previousMillis200 = currentMillis; - previousMillis500 = currentMillis; - previousMillis640 = currentMillis; - previousMillis1000 = currentMillis; - previousMillis5000 = currentMillis; - previousMillis10000 = currentMillis; } -} + //We can always send CAN as the iX BMS will wake up on vehicle comms + // else { + // previousMillis20 = currentMillis; + // previousMillis100 = currentMillis; + // previousMillis200 = currentMillis; + // previousMillis500 = currentMillis; + // previousMillis640 = currentMillis; + // previousMillis1000 = currentMillis; + // previousMillis5000 = currentMillis; + // previousMillis10000 = currentMillis; + // } +//} //We can always send CAN as the iX BMS will wake up on vehicle comms void setup_battery(void) { // Performs one time setup at startup #ifdef DEBUG_VIA_USB Serial.println("BMW iX battery selected"); #endif //DEBUG_VIA_USB - //Before we have started up and detected which battery is in use, use 60AH values + //Before we have started up and detected which battery is in use, use 108S values datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; datalayer.system.status.battery_allows_contactor_closing = true; - pinMode(WUP_PIN, OUTPUT); - digitalWrite(WUP_PIN, HIGH); // Wake up the battery + //pinMode(WUP_PIN, OUTPUT); // Not needed - can hold WUP pin High with iX BMS + //digitalWrite(WUP_PIN, HIGH); // Wake up the battery // Not needed - can hold WUP pin High with iX BMS //Wake Battery //Send SME Keep alive values 100ms @@ -526,10 +561,12 @@ void setup_battery(void) { // Performs one time setup at startup //Send SME Keep alive values 200ms BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 transmit_can(&BMWiX_0C0, can_config.battery); + + //Send SME Keep alive values 1000ms - transmit_can(&BMWiX_06D, can_config.battery); - transmit_can(&BMWiX_2F1, can_config.battery); - transmit_can(&BMWiX_439, can_config.battery); + //test disable transmit_can(&BMWiX_06D, can_config.battery); + //test disable transmit_can(&BMWiX_2F1, can_config.battery); + //test disable transmit_can(&BMWiX_439, can_config.battery); } #endif From 17a7e90b3d36ff46f79d31fb6d9288dc193e7497 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:40:45 +0000 Subject: [PATCH 11/48] 0.2alpha version - Update datalayer_extended.h --- Software/src/datalayer/datalayer_extended.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index aecbed70..18fd8f4e 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -8,7 +8,21 @@ typedef struct { /** Terminal 30 - 12V SME Supply Voltage */ uint16_t T30_Voltage = 0; /** Status HVIL, 1 HVIL OK, 0 HVIL disconnected*/ - uint8_t HVIL_Status= 0; + uint8_t hvil_status= 0; + /** Min/Max Cell SOH*/ + uint16_t min_soh_state = 0; + uint16_t max_soh_state=0; + uint32_t bms_uptime=0; + uint8_t pyro_status_pss1=0; + uint8_t pyro_status_pss4=0; + uint8_t pyro_status_pss6=0; + int32_t iso_safety_positive=0; + int32_t iso_safety_negative=0; + int32_t iso_safety_parallel=0; + int32_t allowable_charge_amps = 0; + int32_t allowable_discharge_amps = 0; + int16_t balancing_status = 0; + } DATALAYER_INFO_BMWIX; From 450d690edf34f84a59f9cf2e30a9d9e55edbdf95 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:41:11 +0000 Subject: [PATCH 12/48] 0.2alpha version - Update advanced_battery_html.cpp --- .../webserver/advanced_battery_html.cpp | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 99ff2201..8a018ce7 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -18,7 +18,29 @@ String advanced_battery_processor(const String& var) { #ifdef BMW_IX_BATTERY - content += "

T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + "mV

"; + content += "

T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + " mV

"; + content += "

Detected Cell Count: " + String(datalayer.battery.info.number_of_cells) + "

"; + static const char* balanceText[5] = {"0 No balancing mode active", + "1 Voltage-Controlled Balancing Mode", + "2 Time-Controlled Balancing Mode with Demand Calculation at End of Charging" , + "3 Time-Controlled Balancing Mode with Demand Calculation at Resting Voltage" , + "4 No balancing mode active, qualifier invalid" + }; + content += "

Balancing Status: " + String((balanceText[datalayer_extended.bmwix.balancing_status])) + "

"; + static const char* hvilText[2] = {"Error (Loop Open)", + "OK (Loop Closed)"}; + content += "

HVIL Status: " + String(hvilText[datalayer_extended.bmwix.hvil_status]) + "

"; + content += "

BMS Uptime: " + String(datalayer_extended.bmwix.bms_uptime) + " seconds

"; + content += "

BMS Allowed Charge Amps: " + String(datalayer_extended.bmwix.allowable_charge_amps) + " A

"; + content += "

BMS Allowed Disharge Amps: " + String(datalayer_extended.bmwix.allowable_discharge_amps) + " A

"; + content += "
"; + content += "

HV Isolation (2147483647kOhm = maximum/invalid)

"; + content += "

Isolation Positive: " + String(datalayer_extended.bmwix.iso_safety_positive) + " kOhm

"; + content += "

Isolation Negative: " + String(datalayer_extended.bmwix.iso_safety_negative) + " kOhm

"; + content += "

Isolation Parallel: " + String(datalayer_extended.bmwix.iso_safety_parallel) + " kOhm

"; + content += "

Pyro Status PSS1: " + String(datalayer_extended.bmwix.pyro_status_pss1) + "

"; + content += "

Pyro Status PSS4: " + String(datalayer_extended.bmwix.pyro_status_pss4) + "

"; + content += "

Pyro Status PSS6: " + String(datalayer_extended.bmwix.pyro_status_pss6) + "

"; #endif //BMW_IX_BATTERY #ifdef BMW_I3_BATTERY From 0cc490481b00ab7ab9da3f403de6e96b50cda897 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 3 Nov 2024 21:25:26 +0000 Subject: [PATCH 13/48] 0.3alpha - Update BMW-IX-BATTERY.h Added more values including pack min/max. min/max cell voltage is now monitored for ensure it's changing (an extra safety check in case it goes stale) --- Software/src/battery/BMW-IX-BATTERY.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 46ea9820..657811c8 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -6,11 +6,15 @@ #define BATTERY_SELECTED //#define WUP_PIN 25 //Not used -#define MAX_PACK_VOLTAGE_DV 4600 //4600 = 460.0V +#define MAX_PACK_VOLTAGE_DV 4650 //4650 = 465.0V #define MIN_PACK_VOLTAGE_DV 3000 -#define MAX_CELL_DEVIATION_MV 500 -#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value -#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value +#define MAX_CELL_DEVIATION_MV 250 +#define MAX_CELL_VOLTAGE_MV 4300 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 2800 //Battery is put into emergency stop if one cell goes below this value +#define MAX_CHARGE_POWER_ALLOWED_W 5000 +#define MAX_CHARGE_POWER_WHEN_TOPBALANCING_W 500 +#define RAMPDOWN_SOC 9000 // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00% +#define STALE_PERIOD_CONFIG 180000; //Number of milliseconds before critical values are classed as stale/stuck 180000 = 180 seconds void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); From f1491dbe8177173195270818710e580bab939828 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 3 Nov 2024 21:26:02 +0000 Subject: [PATCH 14/48] 0.3alpha - Update BMW-IX-BATTERY.cpp Added more values including pack min/max. min/max cell voltage is now monitored for ensure it's changing (an extra safety check in case it goes stale) --- Software/src/battery/BMW-IX-BATTERY.cpp | 153 ++++++++++++++++++------ 1 file changed, 117 insertions(+), 36 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 4f4627f8..f7569277 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -56,16 +56,11 @@ No vehicle log available, SME asks for: 0xAA (EME2) 0x?? Suspect there is a drive mode flag somewhere - balancing might only be active in some modes - - TODO - - Request batt serial number on F1 8C (already parsing RX) -- Check PWM required from ACSM -- Use voltage qualifier for extended data? +- Check PWM state required from ACSM - More Balancing values -- Check for stale min/max values -- Prevent fault state on SME reset +- MIN /max cell voltag e- implement safety limits? */ @@ -119,10 +114,12 @@ CAN_frame BMWiX_6F4_REQUEST_UPTIME = {.FD = true, .ext_ID = false, .DLC = 5, .ID CAN_frame BMWiX_6F4_REQUEST_HVIL = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x69}}; // Request HVIL State CAN_frame BMWiX_6F4_REQUEST_BALANCINGSTATUS = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE4, 0xCA}}; // Request Balancing Data CAN_frame BMWiX_6F4_REQUEST_MAX_CHARGE_DISCHARGE_AMPS = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x62}}; // Request allowable charge discharge amps -CAN_frame BMWiX_6F4_REQUEST_QUALIFIER_CHECK = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4B}}; // Request HV Voltage Qualifier +CAN_frame BMWiX_6F4_REQUEST_VOLTAGE_QUALIFIER_CHECK = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4B}}; // Request HV Voltage Qualifier CAN_frame BMWiX_6F4_REQUEST_CONTACTORS_CLOSE = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x51, 0x01}}; // Request Contactors Close - Unconfirmed CAN_frame BMWiX_6F4_REQUEST_CONTACTORS_OPEN = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x51, 0x01}}; // Request Contactors Open - Unconfirmed CAN_frame BMWiX_6F4_REQUEST_BALANCING_START = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0xF4, 0x04, 0x71, 0x01, 0xAE, 0x77}}; // Request Balancing command? +CAN_frame BMWiX_6F4_REQUEST_PACK_VOLTAGE_LIMITS = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4C}}; // Request pack voltage limits + CAN_frame BMWiX_6F4_CONTINUE_DATA = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x6F4, .data = {0x07, 0x30, 0x00, 0x02}}; @@ -152,11 +149,13 @@ CAN_frame* UDS_REQUESTS100MS[] = { &BMWiX_6F4_REQUEST_EOL_ISO, &BMWiX_6F4_REQUEST_HVIL, &BMWiX_6F4_REQUEST_MAX_CHARGE_DISCHARGE_AMPS, - &BMWiX_6F4_REQUEST_BALANCINGSTATUS + &BMWiX_6F4_REQUEST_BALANCINGSTATUS, + &BMWiX_6F4_REQUEST_PACK_VOLTAGE_LIMITS }; int numUDSreqs = sizeof(UDS_REQUESTS100MS) / sizeof(UDS_REQUESTS100MS[0]); // Number of elements in the array //iX Intermediate vars +static bool battery_info_available = false; static uint32_t battery_serial_number = 0; static int32_t battery_current = 0; static int16_t battery_voltage = 370; @@ -168,8 +167,8 @@ static int16_t max_soc_state = 50; static int16_t min_soh_state = 99;// Uses E5 45, also available in 78 73 static int16_t avg_soh_state = 99;// Uses E5 45, also available in 78 73 static int16_t max_soh_state = 99;// Uses E5 45, also available in 78 73 -static uint16_t battery_max_charge_voltage = 0; -static uint16_t battery_min_discharge_voltage = 0; +static uint16_t max_design_voltage = 0; +static uint16_t min_design_voltage = 0; static int32_t remaining_capacity = 0; static int32_t max_capacity = 0; static int16_t min_battery_temperature = 0; @@ -178,6 +177,8 @@ static int16_t max_battery_temperature = 0; static int16_t main_contactor_temperature = 0; static int16_t min_cell_voltage = 0; static int16_t max_cell_voltage = 0; +static unsigned long min_cell_voltage_lastchanged = 0; +static unsigned long max_cell_voltage_lastchanged = 0; static unsigned min_cell_voltage_lastreceived = 0; static unsigned max_cell_voltage_lastreceived = 0; static int16_t battery_power = 0; @@ -200,6 +201,9 @@ static uint8_t pyro_status_pss1 = 0; //Using AC 93 static uint8_t pyro_status_pss4 = 0; //Using AC 93 static uint8_t pyro_status_pss6 = 0; //Using AC 93 static uint8_t uds_req_id_counter = 0; +const unsigned long STALE_PERIOD = STALE_PERIOD_CONFIG ; // Time in milliseconds to check for staleness (e.g., 5000 ms = 5 seconds) + + static byte iX_0C0_counter = 0xF0; // Initialize to 0xF0 @@ -207,6 +211,22 @@ static byte iX_0C0_counter = 0xF0; // Initialize to 0xF0 static uint8_t current_cell_polled = 0; +// Function to check if a value has gone stale over a specified time period +bool isStale(int16_t currentValue, uint16_t &lastValue, unsigned long &lastChangeTime) { + unsigned long currentTime = millis(); + + // Check if the value has changed + if (currentValue != lastValue) { + // Update the last change time and value + lastChangeTime = currentTime; + lastValue = currentValue; + return false; // Value is fresh because it has changed + } + + // Check if the value has stayed the same for the specified staleness period + return (currentTime - lastChangeTime >= STALE_PERIOD); +} + static uint8_t increment_uds_req_id_counter(uint8_t index) { index++; if (index >= numUDSreqs) { @@ -246,9 +266,23 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.soh_pptt = min_soh_state; - datalayer.battery.status.max_discharge_power_W = 10000; //Aux HV Port has 100A Fuse + datalayer.battery.status.max_discharge_power_W = 3200; //10000; //Aux HV Port has 100A Fuse + + //datalayer.battery.status.max_charge_power_W = 3200; //10000; //Aux HV Port has 100A Fuse Moved to Ramping + + + // Charge power is set in .h file + if (datalayer.battery.status.real_soc > 9900) { + datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_WHEN_TOPBALANCING_W; + } else if (datalayer.battery.status.real_soc > RAMPDOWN_SOC) { + // When real SOC is between RAMPDOWN_SOC-99%, ramp the value between Max<->0 + datalayer.battery.status.max_charge_power_W = + MAX_CHARGE_POWER_ALLOWED_W * + (1 - (datalayer.battery.status.real_soc - RAMPDOWN_SOC) / (10000.0 - RAMPDOWN_SOC)); + } else { // No limits, max charging power allowed + datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_ALLOWED_W; + } - datalayer.battery.status.max_charge_power_W = 10000; //Aux HV Port has 100A Fuse battery_power = (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); @@ -258,11 +292,31 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.temperature_max_dC = max_battery_temperature; - datalayer.battery.status.cell_min_voltage_mV = min_cell_voltage; - - datalayer.battery.status.cell_max_voltage_mV = max_cell_voltage; - datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + + if (isStale(min_cell_voltage, datalayer.battery.status.cell_min_voltage_mV, min_cell_voltage_lastchanged)) {//TODO prevent flipflop after error + Serial.println("min_cell_voltage has gone stale."); + datalayer.battery.status.cell_min_voltage_mV = 9999; //Stale values force stop + set_event(EVENT_CAN_RX_FAILURE,0); + } else { + datalayer.battery.status.cell_min_voltage_mV = min_cell_voltage; //Value is alive + } + + if (isStale(max_cell_voltage, datalayer.battery.status.cell_max_voltage_mV, max_cell_voltage_lastchanged)) { //TODO prevent flipflop after error + Serial.println("max_cell_voltage has gone stale."); + datalayer.battery.status.cell_max_voltage_mV = 9999; //Stale values force stop + set_event(EVENT_CAN_RX_FAILURE,0); + } else { + datalayer.battery.status.cell_max_voltage_mV = max_cell_voltage; //Value is alive + } + + datalayer_extended.bmwix.min_cell_voltage_data_age = (millis() - min_cell_voltage_lastchanged); + + datalayer_extended.bmwix.max_cell_voltage_data_age = (millis() - max_cell_voltage_lastchanged); + + datalayer.battery.info.max_design_voltage_dV = max_design_voltage; + + datalayer.battery.info.min_design_voltage_dV = min_design_voltage; datalayer.battery.info.number_of_cells = 108; //init with 108S before autodetection @@ -282,7 +336,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.bmwix.iso_safety_negative = iso_safety_negative; - datalayer_extended.bmwix.iso_safety_parallel= iso_safety_parallel; + datalayer_extended.bmwix.iso_safety_parallel = iso_safety_parallel; datalayer_extended.bmwix.allowable_charge_amps = allowable_charge_amps; @@ -290,6 +344,20 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.bmwix.balancing_status = balancing_status; + datalayer_extended.bmwix.battery_voltage_after_contactor = battery_voltage_after_contactor; + + + + + + if (battery_info_available) { + // If we have data from battery - override the defaults to suit + datalayer.battery.info.max_design_voltage_dV = max_design_voltage; + datalayer.battery.info.min_design_voltage_dV = min_design_voltage; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + } + } void receive_can_battery(CAN_frame rx_frame) { @@ -366,15 +434,15 @@ void receive_can_battery(CAN_frame rx_frame) { } if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0x4A) { //Main Battery Voltage (After Contactor) - battery_voltage_after_contactor = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); + battery_voltage_after_contactor = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6])/10; } if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x61) { //Current amps 32bit signed MSB. dA . negative is discharge - battery_current = (int32_t)((rx_frame.data.u8[5] << 24) | - (rx_frame.data.u8[6] << 16) | - (rx_frame.data.u8[7] << 8) | - rx_frame.data.u8[8]); + battery_current = ((int32_t)((rx_frame.data.u8[6] << 24) | + (rx_frame.data.u8[7] << 16) | + (rx_frame.data.u8[8] << 8) | + rx_frame.data.u8[9]))*0.1; } if (rx_frame.DLC = 64 && rx_frame.data.u8[4] == 0xE4 && rx_frame.data.u8[5] == 0xCA) { //Balancing Data @@ -398,8 +466,8 @@ void receive_can_battery(CAN_frame rx_frame) { } if (rx_frame.DLC = 10 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x62) { //Max allowed charge and discharge current - Signed 16bit - allowable_charge_amps = (int16_t)((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7])); - allowable_discharge_amps = (int16_t)((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9])); + allowable_charge_amps = (int16_t)((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]))/10; + allowable_discharge_amps = (int16_t)((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]))/10; } if (rx_frame.DLC = 9 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x4B) { //Max allowed charge and discharge current - Signed 16bit @@ -424,6 +492,9 @@ void receive_can_battery(CAN_frame rx_frame) { } if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x53) { //Min and max cell voltage 10V = Qualifier Invalid + + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //This is the most important safety values, if we receive this we reset CAN alive counter. + if((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) == 10000 && (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) == 10000){ //Qualifier Invalid Mode - Request Reboot #ifdef DEBUG_VIA_USB Serial.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); @@ -447,9 +518,18 @@ void receive_can_battery(CAN_frame rx_frame) { if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA7) { //Terminal 30 Voltage (12V SME supply) terminal30_12v_voltage = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); } - if (rx_frame.DLC = 6 && rx_frame.data.u8[3] == 0xE5 && rx_frame.data.u8[4] == 0x69) { //HVIL Status + if (rx_frame.DLC = 6 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x04 && rx_frame.data.u8[2] == 0x62 && rx_frame.data.u8[3] == 0xE5 && rx_frame.data.u8[4] == 0x69) { //HVIL Status hvil_status = ( rx_frame.data.u8[5]); } + + if (rx_frame.DLC = 12 && rx_frame.data.u8[2] == 0x07 && rx_frame.data.u8[3] == 0x62 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x4C) { //Pack Voltage Limits + if ((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) < 4700 && (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) > 2600) { //Make sure values are plausible + battery_info_available = true; + max_design_voltage = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); + min_design_voltage = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); + } + } + if (rx_frame.DLC = 16 && rx_frame.data.u8[3] == 0xF1 && rx_frame.data.u8[4] == 0x8C ) { //Battery Serial Number //Convert hex bytes to ASCII characters and combine them into a string char numberString[11]; // 10 characters + null terminator @@ -549,24 +629,25 @@ void setup_battery(void) { // Performs one time setup at startup //Before we have started up and detected which battery is in use, use 108S values datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; datalayer.system.status.battery_allows_contactor_closing = true; - //pinMode(WUP_PIN, OUTPUT); // Not needed - can hold WUP pin High with iX BMS - //digitalWrite(WUP_PIN, HIGH); // Wake up the battery // Not needed - can hold WUP pin High with iX BMS + //pinMode(WUP_PIN, OUTPUT); // Not needed - can hold WUP pin High with iX BMS + //digitalWrite(WUP_PIN, HIGH); // Wake up the battery // Not needed - can hold WUP pin High with iX BMS - //Wake Battery - //Send SME Keep alive values 100ms + + //Send SME Keep alive values 100ms transmit_can(&BMWiX_510, can_config.battery); - //Send SME Keep alive values 200ms + //Send SME Keep alive values 200ms BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 transmit_can(&BMWiX_0C0, can_config.battery); - - //Send SME Keep alive values 1000ms - //test disable transmit_can(&BMWiX_06D, can_config.battery); - //test disable transmit_can(&BMWiX_2F1, can_config.battery); - //test disable transmit_can(&BMWiX_439, can_config.battery); + //Send SME Keep alive values 1000ms + //Not needed transmit_can(&BMWiX_06D, can_config.battery); + //Not needed transmit_can(&BMWiX_2F1, can_config.battery); + //Not needed transmit_can(&BMWiX_439, can_config.battery); } #endif From ed05b7602ab35eb616a82e424c52458810f0ed0f Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 3 Nov 2024 21:26:33 +0000 Subject: [PATCH 15/48] 0.3alpha - Update datalayer_extended.h Added more values including pack min/max. min/max cell voltage is now monitored for ensure it's changing (an extra safety check in case it goes stale) --- Software/src/datalayer/datalayer_extended.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 18fd8f4e..0608b2cc 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -22,6 +22,9 @@ typedef struct { int32_t allowable_charge_amps = 0; int32_t allowable_discharge_amps = 0; int16_t balancing_status = 0; + int16_t battery_voltage_after_contactor = 0; + unsigned long min_cell_voltage_data_age = 0; + unsigned long max_cell_voltage_data_age = 0; } DATALAYER_INFO_BMWIX; From 724efbc5c5ac0272170c04235a04da1d5a435515 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 3 Nov 2024 21:27:15 +0000 Subject: [PATCH 16/48] 0.3alpha - Update advanced_battery_html.cpp Added more values including pack min/max. min/max cell voltage is now monitored for ensure it's changing (an extra safety check in case it goes stale) --- .../webserver/advanced_battery_html.cpp | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 8a018ce7..eff6900e 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -18,7 +18,16 @@ String advanced_battery_processor(const String& var) { #ifdef BMW_IX_BATTERY - content += "

T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + " mV

"; + content += "

Battery Voltage after Contactor: " + String(datalayer_extended.bmwix.battery_voltage_after_contactor) + " dV

"; + content += "

Max Design Voltage: " + String(datalayer.battery.info.max_design_voltage_dV) + " dV

"; + content += "

Min Design Voltage: " + String(datalayer.battery.info.min_design_voltage_dV) + " dV

"; + content += "

Max Cell Design Voltage: " + String(datalayer.battery.info.max_cell_voltage_mV) + " mV

"; + content += "

Min Cell Design Voltage: " + String(datalayer.battery.info.min_cell_voltage_mV) + " mV

"; + content += "

Min Cell Voltage Data Age: " + String(datalayer_extended.bmwix.min_cell_voltage_data_age) + " ms

"; + content += "

Max Cell Voltage Data Age: " + String(datalayer_extended.bmwix.max_cell_voltage_data_age) + " ms

"; + content += "

Currently allowed Discharge Power: " + String(datalayer.battery.status.max_discharge_power_W) + " W

"; + content += "

Currently allowed Charge Power: " + String(datalayer.battery.status.max_charge_power_W) + " W

"; + content += "

T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + " mV

"; content += "

Detected Cell Count: " + String(datalayer.battery.info.number_of_cells) + "

"; static const char* balanceText[5] = {"0 No balancing mode active", "1 Voltage-Controlled Balancing Mode", @@ -38,9 +47,15 @@ String advanced_battery_processor(const String& var) { content += "

Isolation Positive: " + String(datalayer_extended.bmwix.iso_safety_positive) + " kOhm

"; content += "

Isolation Negative: " + String(datalayer_extended.bmwix.iso_safety_negative) + " kOhm

"; content += "

Isolation Parallel: " + String(datalayer_extended.bmwix.iso_safety_parallel) + " kOhm

"; - content += "

Pyro Status PSS1: " + String(datalayer_extended.bmwix.pyro_status_pss1) + "

"; - content += "

Pyro Status PSS4: " + String(datalayer_extended.bmwix.pyro_status_pss4) + "

"; - content += "

Pyro Status PSS6: " + String(datalayer_extended.bmwix.pyro_status_pss6) + "

"; + static const char* pyroText[5] = {"0 Value Invalid", + "1 Successfully Blown", + "2 Disconnected" , + "3 Not Activated - Pyro Intact" , + "4 Unknown" + }; + content += "

Pyro Status PSS1: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss1])) + "

"; + content += "

Pyro Status PSS4: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss4])) + "

"; + content += "

Pyro Status PSS6: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss6])) + "

"; #endif //BMW_IX_BATTERY #ifdef BMW_I3_BATTERY From 9051293c43887253f7f8fec256e9bc7460c7864a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 6 Nov 2024 15:57:20 +0200 Subject: [PATCH 17/48] Update BYD FW to 3.29 --- Software/src/inverter/BYD-CAN.cpp | 14 +++++++------- Software/src/inverter/BYD-CAN.h | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 82527469..a2cf2d44 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -15,13 +15,13 @@ static uint8_t char5_151 = 0; static uint8_t char6_151 = 0; static uint8_t char7_151 = 0; -CAN_frame BYD_250 = { - .FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x250, - .data = {0x03, 0x16, 0x00, 0x66, (uint8_t)((BATTERY_WH_MAX / 100) >> 8), (uint8_t)(BATTERY_WH_MAX / 100), 0x02, - 0x09}}; //3.16 FW , Capacity kWh byte4&5 (example 24kWh = 240) +CAN_frame BYD_250 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x250, + .data = {FW_MAJOR_VERSION, FW_MINOR_VERSION, 0x00, 0x66, (uint8_t)((BATTERY_WH_MAX / 100) >> 8), + (uint8_t)(BATTERY_WH_MAX / 100), 0x02, + 0x09}}; //0-1 FW version , Capacity kWh byte4&5 (example 24kWh = 240) CAN_frame BYD_290 = {.FD = false, .ext_ID = false, .DLC = 8, diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index 198f10bb..6a45317b 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -3,6 +3,8 @@ #include "../include.h" #define CAN_INVERTER_SELECTED +#define FW_MAJOR_VERSION 0x03 +#define FW_MINOR_VERSION 0x29 void send_intial_data(); void transmit_can(CAN_frame* tx_frame, int interface); From e293d5dcce9145a6650080fee82870b046fe6e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 8 Nov 2024 10:11:31 +0200 Subject: [PATCH 18/48] Add initial HAL for v0.1 3LB --- Software/USER_SETTINGS.h | 1 + Software/src/devboard/hal/hal.h | 4 +- Software/src/devboard/hal/hw_3LB.h | 106 ++++++++++++++++++ Software/src/devboard/webserver/webserver.cpp | 3 + 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 Software/src/devboard/hal/hw_3LB.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 242c1264..8085999f 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -49,6 +49,7 @@ /* Select hardware used for Battery-Emulator */ #define HW_LILYGO //#define HW_STARK +//#define HW_3LB /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) diff --git a/Software/src/devboard/hal/hal.h b/Software/src/devboard/hal/hal.h index 5e904d89..dc3240ce 100644 --- a/Software/src/devboard/hal/hal.h +++ b/Software/src/devboard/hal/hal.h @@ -7,8 +7,8 @@ #include "hw_lilygo.h" #elif defined(HW_STARK) #include "hw_stark.h" -#elif defined(HW_SJB_V1) -#include "hw_sjb_v1.h" +#elif defined(HW_3LB) +#include "hw_3LB.h" #endif #endif diff --git a/Software/src/devboard/hal/hw_3LB.h b/Software/src/devboard/hal/hw_3LB.h new file mode 100644 index 00000000..137d83f3 --- /dev/null +++ b/Software/src/devboard/hal/hw_3LB.h @@ -0,0 +1,106 @@ +#ifndef __HW_3LB_H__ +#define __HW_3LB_H__ + +// Board boot-up time +#define BOOTUP_TIME 1000 // Time in ms it takes before system is considered fully started up + +// Core assignment +#define CORE_FUNCTION_CORE 1 +#define MODBUS_CORE 0 +#define WIFI_CORE 0 + +// RS485 +//#define PIN_5V_EN 16 +//#define RS485_EN_PIN 17 // 17 /RE +#define RS485_TX_PIN 1 // 21 +#define RS485_RX_PIN 3 // 22 +//#define RS485_SE_PIN 19 // 22 /SHDN + +// CAN settings. CAN_2 is not defined as it can be either MCP2515 or MCP2517, defined by the user settings +#define CAN_1_TYPE ESP32CAN + +// CAN1 PIN mappings, do not change these unless you are adding on extra hardware to the PCB +#define CAN_TX_PIN GPIO_NUM_27 +#define CAN_RX_PIN GPIO_NUM_26 +//#define CAN_SE_PIN 23 + +// CAN2 defines below + +// DUAL_CAN defines +#define MCP2515_SCK 12 // SCK input of MCP2515 +#define MCP2515_MOSI 5 // SDI input of MCP2515 +#define MCP2515_MISO 34 // SDO output of MCP2515 | Pin 34 is input only, without pullup/down resistors +#define MCP2515_CS 18 // CS input of MCP2515 +#define MCP2515_INT 35 // INT output of MCP2515 | | Pin 35 is input only, without pullup/down resistors + +// CAN_FD defines +#define MCP2517_SCK 17 // SCK input of MCP2517 +#define MCP2517_SDI 23 // SDI input of MCP2517 +#define MCP2517_SDO 39 // SDO output of MCP2517 +#define MCP2517_CS 21 // CS input of MCP2517 //21 or 22 +#define MCP2517_INT 34 // INT output of MCP2517 //34 or 35 + +// CHAdeMO support pin dependencies +#define CHADEMO_PIN_2 12 +#define CHADEMO_PIN_10 5 +#define CHADEMO_PIN_7 34 +#define CHADEMO_PIN_4 35 +#define CHADEMO_LOCK 18 + +// Contactor handling +#define POSITIVE_CONTACTOR_PIN 32 +#define NEGATIVE_CONTACTOR_PIN 33 +#define PRECHARGE_PIN 25 + +#define 2ND_POSITIVE_CONTACTOR_PIN 13 +#define 2ND_NEGATIVE_CONTACTOR_PIN 16 +#define 2ND_PRECHARGE_PIN 18 + +// SMA CAN contactor pins +#define INVERTER_CONTACTOR_ENABLE_PIN 36 + +// SD card +//#define SD_MISO_PIN 2 +//#define SD_MOSI_PIN 15 +//#define SD_SCLK_PIN 14 +//#define SD_CS_PIN 13 + +// LED +#define LED_PIN 4 +#define LED_MAX_BRIGHTNESS 40 + +// Equipment stop pin +#define EQUIPMENT_STOP_PIN 35 + +/* ----- Error checks below, don't change (can't be moved to separate file) ----- */ +#ifndef HW_CONFIGURED +#define HW_CONFIGURED +#else +#error Multiple HW defined! Please select a single HW +#endif + +#ifdef CHADEMO_BATTERY +#ifdef DUAL_CAN +#error CHADEMO and DUAL_CAN cannot coexist due to overlapping GPIO pin usage +#endif +#endif + +#ifdef EQUIPMENT_STOP_BUTTON +#ifdef DUAL_CAN +#error EQUIPMENT_STOP_BUTTON and DUAL_CAN cannot coexist due to overlapping GPIO pin usage +#endif +#ifdef CAN_FD +#error EQUIPMENT_STOP_BUTTON and CAN_FD cannot coexist due to overlapping GPIO pin usage +#endif +#ifdef CHADEMO_BATTERY +#error EQUIPMENT_STOP_BUTTON and CHADEMO_BATTERY cannot coexist due to overlapping GPIO pin usage +#endif +#endif + +#ifdef BMW_I3_BATTERY +#ifdef CONTACTOR_CONTROL +#error GPIO PIN 25 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL +#endif +#endif + +#endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 3f6bfbf5..cf33bbf0 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -415,6 +415,9 @@ String get_firmware_info_processor(const String& var) { #ifdef HW_STARK doc["hardware"] = "Stark CMR Module"; #endif // HW_STARK +#ifdef HW_3LB + doc["hardware"] = "3LB board"; +#endif // HW_STARK doc["firmware"] = String(version_number); serializeJson(doc, content); From 5dd30f7d33cf97cfd3ea8983572f08f743b63f1d Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 10:55:07 +0000 Subject: [PATCH 19/48] Update advanced_battery_html.cpp --- .../webserver/advanced_battery_html.cpp | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 5e6557e8..ddad0304 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -16,6 +16,47 @@ String advanced_battery_processor(const String& var) { // Start a new block with a specific background color content += "
"; +#ifdef BMW_IX_BATTERY + content += "

Battery Voltage after Contactor: " + String(datalayer_extended.bmwix.battery_voltage_after_contactor) + " dV

"; + content += "

Max Design Voltage: " + String(datalayer.battery.info.max_design_voltage_dV) + " dV

"; + content += "

Min Design Voltage: " + String(datalayer.battery.info.min_design_voltage_dV) + " dV

"; + content += "

Max Cell Design Voltage: " + String(datalayer.battery.info.max_cell_voltage_mV) + " mV

"; + content += "

Min Cell Design Voltage: " + String(datalayer.battery.info.min_cell_voltage_mV) + " mV

"; + content += "

Min Cell Voltage Data Age: " + String(datalayer_extended.bmwix.min_cell_voltage_data_age) + " ms

"; + content += "

Max Cell Voltage Data Age: " + String(datalayer_extended.bmwix.max_cell_voltage_data_age) + " ms

"; + content += "

Allowed Discharge Power: " + String(datalayer.battery.status.max_discharge_power_W) + " W

"; + content += "

Allowed Charge Power: " + String(datalayer.battery.status.max_charge_power_W) + " W

"; + content += "

T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + " mV

"; + content += "

Detected Cell Count: " + String(datalayer.battery.info.number_of_cells) + "

"; + static const char* balanceText[5] = {"0 No balancing mode active", + "1 Voltage-Controlled Balancing Mode", + "2 Time-Controlled Balancing Mode with Demand Calculation at End of Charging" , + "3 Time-Controlled Balancing Mode with Demand Calculation at Resting Voltage" , + "4 No balancing mode active, qualifier invalid" + }; + content += "

Balancing: " + String((balanceText[datalayer_extended.bmwix.balancing_status])) + "

"; + static const char* hvilText[2] = {"Error (Loop Open)", + "OK (Loop Closed)"}; + content += "

HVIL Status: " + String(hvilText[datalayer_extended.bmwix.hvil_status]) + "

"; + content += "

BMS Uptime: " + String(datalayer_extended.bmwix.bms_uptime) + " seconds

"; + content += "

BMS Allowed Charge Amps: " + String(datalayer_extended.bmwix.allowable_charge_amps) + " A

"; + content += "

BMS Allowed Disharge Amps: " + String(datalayer_extended.bmwix.allowable_discharge_amps) + " A

"; + content += "
"; + content += "

HV Isolation (2147483647kOhm = maximum/invalid)

"; + content += "

Isolation Positive: " + String(datalayer_extended.bmwix.iso_safety_positive) + " kOhm

"; + content += "

Isolation Negative: " + String(datalayer_extended.bmwix.iso_safety_negative) + " kOhm

"; + content += "

Isolation Parallel: " + String(datalayer_extended.bmwix.iso_safety_parallel) + " kOhm

"; + static const char* pyroText[5] = {"0 Value Invalid", + "1 Successfully Blown", + "2 Disconnected" , + "3 Not Activated - Pyro Intact" , + "4 Unknown" + }; + content += "

Pyro Status PSS1: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss1])) + "

"; + content += "

Pyro Status PSS4: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss4])) + "

"; + content += "

Pyro Status PSS6: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss6])) + "

"; +#endif //BMW_IX_BATTERY + #ifdef BMW_I3_BATTERY content += "

SOC raw: " + String(datalayer_extended.bmwi3.SOC_raw) + "

"; content += "

SOC dash: " + String(datalayer_extended.bmwi3.SOC_dash) + "

"; From f22806fd23720c161864ffc3bc9235ed2e48c933 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:04:53 +0000 Subject: [PATCH 20/48] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f4dd4582..76d87ea2 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ compile.bat # Ignore binary files *.bin +Software/USER_SETTINGS.h +Software/USER_SETTINGS.cpp From c50fd918c12a6608f7abe2be9ec6059074afcfca Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:07:30 +0000 Subject: [PATCH 21/48] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 76d87ea2..ea0bcd5a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ compile.bat *.bin Software/USER_SETTINGS.h Software/USER_SETTINGS.cpp +Software/USER_SETTINGS.h +Software/USER_SETTINGS.cpp From 23a6abfec20a247055f4d6c59062ce77ad3635cc Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:25:21 +0000 Subject: [PATCH 22/48] Update BMW-IX-BATTERY.cpp --- Software/src/battery/BMW-IX-BATTERY.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index f7569277..c0880c2f 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -58,9 +58,6 @@ No vehicle log available, SME asks for: TODO - Request batt serial number on F1 8C (already parsing RX) -- Check PWM state required from ACSM -- More Balancing values -- MIN /max cell voltag e- implement safety limits? */ From ae50634ee8fd808e222225a60302acf9e0b9856a Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:29:44 +0000 Subject: [PATCH 23/48] Update .gitignore --- .gitignore | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitignore b/.gitignore index ea0bcd5a..f4dd4582 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,3 @@ compile.bat # Ignore binary files *.bin -Software/USER_SETTINGS.h -Software/USER_SETTINGS.cpp -Software/USER_SETTINGS.h -Software/USER_SETTINGS.cpp From 00f78ce76cf0682704779d57b3743709c8332ce5 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:08:08 +0000 Subject: [PATCH 24/48] Update formatting --- Software/src/battery/BMW-IX-BATTERY.cpp | 913 ++++++++++++++---------- Software/src/battery/BMW-IX-BATTERY.h | 5 +- 2 files changed, 550 insertions(+), 368 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index c0880c2f..37110fb7 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -62,94 +62,269 @@ TODO */ //Vehicle CAN START -CAN_frame BMWiX_06D = {.FD = true, .ext_ID = false, .DLC = 8, .ID = 0x06D, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF}}; // 1000ms BDC Output - [0] static [1,2][3,4] counter x2. 3,4 is 9 higher than 1,2 is needed? [5-7] static +CAN_frame BMWiX_06D = { + .FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x06D, + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0xFF}}; // 1000ms BDC Output - [0] static [1,2][3,4] counter x2. 3,4 is 9 higher than 1,2 is needed? [5-7] static -CAN_frame BMWiX_0C0 = {.FD = true, .ext_ID = false, .DLC = 2, .ID = 0x0C0, - .data = {0xF0, 0x08}}; // Keep Alive 2 BDC>SME 200ms First byte cycles F0 > FE second byte 08 static - MINIMUM ID TO KEEP SME AWAKE +CAN_frame BMWiX_0C0 = { + .FD = true, + .ext_ID = false, + .DLC = 2, + .ID = 0x0C0, + .data = { + 0xF0, + 0x08}}; // Keep Alive 2 BDC>SME 200ms First byte cycles F0 > FE second byte 08 static - MINIMUM ID TO KEEP SME AWAKE -CAN_frame BMWiX_276 = {.FD = true, .ext_ID = false, .DLC = 8, .ID = 0x476, - .data = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC}}; // 5000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED +CAN_frame BMWiX_276 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x476, + .data = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFC}}; // 5000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED -CAN_frame BMWiX_2F1 = {.FD = true, .ext_ID = false, .DLC = 8, .ID = 0x2F1, - .data = {0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x00, 0xF3, 0xFF}}; // 1000ms BDC Output - Static values - varies at startup +CAN_frame BMWiX_2F1 = { + .FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x2F1, + .data = {0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x00, 0xF3, 0xFF}}; // 1000ms BDC Output - Static values - varies at startup -CAN_frame BMWiX_439 = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x439, - .data = {0xFF, 0xBF, 0xFF, 0xFF}}; // 1000ms BDC Output - Static values +CAN_frame BMWiX_439 = {.FD = true, + .ext_ID = false, + .DLC = 4, + .ID = 0x439, + .data = {0xFF, 0xBF, 0xFF, 0xFF}}; // 1000ms BDC Output - Static values -CAN_frame BMWiX_486 = {.FD = true, .ext_ID = false, .DLC = 48, .ID = 0x486, - .data = {0xFE, 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFE , 0xFF , 0xFF , 0x7F , 0x33 , 0xFD , 0xFD , 0xFD , 0xFD , 0xC0 , 0x41 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF}}; // 1000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED +CAN_frame + BMWiX_486 = + { + .FD = true, + .ext_ID = false, + .DLC = 48, + .ID = 0x486, + .data = + { + 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, + 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, + 0xFE, 0xFF, 0xFF, 0x7F, 0x33, 0xFD, 0xFD, 0xFD, 0xFD, 0xC0, 0x41, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; // 1000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED -CAN_frame BMWiX_49C = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x49C, - .data = {0xD2, 0xF2, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; // 1000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED +CAN_frame BMWiX_49C = {.FD = true, + .ext_ID = false, + .DLC = 4, + .ID = 0x49C, + .data = {0xD2, 0xF2, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF}}; // 1000ms BDC Output - Suspected keep alive Static CONFIRM NEEDED -CAN_frame BMWiX_510 = {.FD = true, .ext_ID = false, .DLC = 8, .ID = 0x510, - .data = {0x40, 0x10, 0x40, 0x00, 0x6F, 0xDF, 0x19, 0x00}}; // 100ms BDC Output - Static values +CAN_frame BMWiX_510 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x510, + .data = {0x40, 0x10, 0x40, 0x00, 0x6F, 0xDF, 0x19, 0x00}}; // 100ms BDC Output - Static values -CAN_frame BMWiX_12B8D087 = {.FD = true, .ext_ID = true, .DLC = 2, .ID = 0x12B8D087, - .data = {0xFC, 0xFF}}; // 5000ms SME Output - Static values +CAN_frame BMWiX_12B8D087 = {.FD = true, + .ext_ID = true, + .DLC = 2, + .ID = 0x12B8D087, + .data = {0xFC, 0xFF}}; // 5000ms SME Output - Static values //Vehicle CAN END //Request Data CAN START -CAN_frame BMWiX_6F4 = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xC7}}; // Generic UDS Request data from SME. byte 4 selects requested value -CAN_frame BMWiX_6F4_REQUEST_SLEEPMODE = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x6F4, .data = {0x07, 0x02, 0x11, 0x04}}; // UDS Request Request BMS/SME goes to Sleep Mode -CAN_frame BMWiX_6F4_REQUEST_HARD_RESET = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x6F4, .data = {0x07, 0x02, 0x11, 0x01}}; // UDS Request Hard reset of BMS/SME -CAN_frame BMWiX_6F4_REQUEST_CELL_TEMP = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xDD, 0xC0}}; // UDS Request Cell Temperatures -CAN_frame BMWiX_6F4_REQUEST_SOC = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xCE}}; // Min/Avg/Max SOC% -CAN_frame BMWiX_6F4_REQUEST_CAPACITY = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xC7}}; //Current and max capacity kWh. Stored in kWh as 0.01 scale with -50 bias -CAN_frame BMWiX_6F4_REQUEST_MINMAXCELLV = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x53}}; //Min and max cell voltage 10V = Qualifier Invalid -CAN_frame BMWiX_6F4_REQUEST_MAINVOLTAGE_POSTCONTACTOR = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4A}}; //Main Battery Voltage (After Contactor) -CAN_frame BMWiX_6F4_REQUEST_MAINVOLTAGE_PRECONTACTOR = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4D}}; //Main Battery Voltage (Pre Contactor) -CAN_frame BMWiX_6F4_REQUEST_BATTERYCURRENT = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x61}}; //Current amps 32bit signed MSB. dA . negative is discharge -CAN_frame BMWiX_6F4_REQUEST_CELL_VOLTAGE = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x54}}; //MultiFrameIndividual Cell Voltages -CAN_frame BMWiX_6F4_REQUEST_T30VOLTAGE = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xA7}}; //Terminal 30 Voltage (12V SME supply) -CAN_frame BMWiX_6F4_REQUEST_EOL_ISO = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xA8, 0x60}}; //Request EOL Reading including ISO -CAN_frame BMWiX_6F4_REQUEST_SOH = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x45}}; //SOH Max Min Mean Request -CAN_frame BMWiX_6F4_REQUEST_DATASUMMARY = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x45}}; //MultiFrame Summary Request, includes SOC/SOH/MinMax/MaxCapac/RemainCapac/max v and t at last charge. slow refreshrate -CAN_frame BMWiX_6F4_REQUEST_PYRO = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xAC, 0x93}}; //Pyro Status -CAN_frame BMWiX_6F4_REQUEST_UPTIME = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE4, 0xC0}}; // Uptime and Vehicle Time Status -CAN_frame BMWiX_6F4_REQUEST_HVIL = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x69}}; // Request HVIL State -CAN_frame BMWiX_6F4_REQUEST_BALANCINGSTATUS = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE4, 0xCA}}; // Request Balancing Data -CAN_frame BMWiX_6F4_REQUEST_MAX_CHARGE_DISCHARGE_AMPS = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x62}}; // Request allowable charge discharge amps -CAN_frame BMWiX_6F4_REQUEST_VOLTAGE_QUALIFIER_CHECK = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4B}}; // Request HV Voltage Qualifier -CAN_frame BMWiX_6F4_REQUEST_CONTACTORS_CLOSE = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x51, 0x01}}; // Request Contactors Close - Unconfirmed -CAN_frame BMWiX_6F4_REQUEST_CONTACTORS_OPEN = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x51, 0x01}}; // Request Contactors Open - Unconfirmed -CAN_frame BMWiX_6F4_REQUEST_BALANCING_START = {.FD = true, .ext_ID = false, .DLC = 6, .ID = 0x6F4, .data = {0xF4, 0x04, 0x71, 0x01, 0xAE, 0x77}}; // Request Balancing command? -CAN_frame BMWiX_6F4_REQUEST_PACK_VOLTAGE_LIMITS = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x4C}}; // Request pack voltage limits +CAN_frame BMWiX_6F4 = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0xC7}}; // Generic UDS Request data from SME. byte 4 selects requested value +CAN_frame BMWiX_6F4_REQUEST_SLEEPMODE = { + .FD = true, + .ext_ID = false, + .DLC = 4, + .ID = 0x6F4, + .data = {0x07, 0x02, 0x11, 0x04}}; // UDS Request Request BMS/SME goes to Sleep Mode +CAN_frame BMWiX_6F4_REQUEST_HARD_RESET = {.FD = true, + .ext_ID = false, + .DLC = 4, + .ID = 0x6F4, + .data = {0x07, 0x02, 0x11, 0x01}}; // UDS Request Hard reset of BMS/SME +CAN_frame BMWiX_6F4_REQUEST_CELL_TEMP = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xDD, 0xC0}}; // UDS Request Cell Temperatures +CAN_frame BMWiX_6F4_REQUEST_SOC = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0xCE}}; // Min/Avg/Max SOC% +CAN_frame BMWiX_6F4_REQUEST_CAPACITY = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0xC7}}; //Current and max capacity kWh. Stored in kWh as 0.01 scale with -50 bias +CAN_frame BMWiX_6F4_REQUEST_MINMAXCELLV = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x53}}; //Min and max cell voltage 10V = Qualifier Invalid +CAN_frame BMWiX_6F4_REQUEST_MAINVOLTAGE_POSTCONTACTOR = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x4A}}; //Main Battery Voltage (After Contactor) +CAN_frame BMWiX_6F4_REQUEST_MAINVOLTAGE_PRECONTACTOR = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x4D}}; //Main Battery Voltage (Pre Contactor) +CAN_frame BMWiX_6F4_REQUEST_BATTERYCURRENT = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x61}}; //Current amps 32bit signed MSB. dA . negative is discharge +CAN_frame BMWiX_6F4_REQUEST_CELL_VOLTAGE = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x54}}; //MultiFrameIndividual Cell Voltages +CAN_frame BMWiX_6F4_REQUEST_T30VOLTAGE = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0xA7}}; //Terminal 30 Voltage (12V SME supply) +CAN_frame BMWiX_6F4_REQUEST_EOL_ISO = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xA8, 0x60}}; //Request EOL Reading including ISO +CAN_frame BMWiX_6F4_REQUEST_SOH = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x45}}; //SOH Max Min Mean Request +CAN_frame BMWiX_6F4_REQUEST_DATASUMMARY = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = { + 0x07, 0x03, 0x22, 0xE5, + 0x45}}; //MultiFrame Summary Request, includes SOC/SOH/MinMax/MaxCapac/RemainCapac/max v and t at last charge. slow refreshrate +CAN_frame BMWiX_6F4_REQUEST_PYRO = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xAC, 0x93}}; //Pyro Status +CAN_frame BMWiX_6F4_REQUEST_UPTIME = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE4, 0xC0}}; // Uptime and Vehicle Time Status +CAN_frame BMWiX_6F4_REQUEST_HVIL = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x69}}; // Request HVIL State +CAN_frame BMWiX_6F4_REQUEST_BALANCINGSTATUS = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE4, 0xCA}}; // Request Balancing Data +CAN_frame BMWiX_6F4_REQUEST_MAX_CHARGE_DISCHARGE_AMPS = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x62}}; // Request allowable charge discharge amps +CAN_frame BMWiX_6F4_REQUEST_VOLTAGE_QUALIFIER_CHECK = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x4B}}; // Request HV Voltage Qualifier +CAN_frame BMWiX_6F4_REQUEST_CONTACTORS_CLOSE = { + .FD = true, + .ext_ID = false, + .DLC = 6, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x51, 0x01}}; // Request Contactors Close - Unconfirmed +CAN_frame BMWiX_6F4_REQUEST_CONTACTORS_OPEN = { + .FD = true, + .ext_ID = false, + .DLC = 6, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x51, 0x01}}; // Request Contactors Open - Unconfirmed +CAN_frame BMWiX_6F4_REQUEST_BALANCING_START = { + .FD = true, + .ext_ID = false, + .DLC = 6, + .ID = 0x6F4, + .data = {0xF4, 0x04, 0x71, 0x01, 0xAE, 0x77}}; // Request Balancing command? +CAN_frame BMWiX_6F4_REQUEST_PACK_VOLTAGE_LIMITS = { + .FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x4C}}; // Request pack voltage limits - -CAN_frame BMWiX_6F4_CONTINUE_DATA = {.FD = true, .ext_ID = false, .DLC = 4, .ID = 0x6F4, .data = {0x07, 0x30, 0x00, 0x02}}; +CAN_frame BMWiX_6F4_CONTINUE_DATA = {.FD = true, + .ext_ID = false, + .DLC = 4, + .ID = 0x6F4, + .data = {0x07, 0x30, 0x00, 0x02}}; //Action Requests: -CAN_frame BMW_10B = {.FD = true, .ext_ID = false, .DLC = 3, .ID = 0x10B, .data = {0xCD, 0x00, 0xFC}}; // Contactor closing command? +CAN_frame BMW_10B = {.FD = true, + .ext_ID = false, + .DLC = 3, + .ID = 0x10B, + .data = {0xCD, 0x00, 0xFC}}; // Contactor closing command? -CAN_frame BMWiX_6F4_CELL_SOC = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0x9A}}; -CAN_frame BMWiX_6F4_CELL_TEMP = {.FD = true, .ext_ID = false, .DLC = 5, .ID = 0x6F4, .data = {0x07, 0x03, 0x22, 0xE5, 0xCA}}; +CAN_frame BMWiX_6F4_CELL_SOC = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0x9A}}; +CAN_frame BMWiX_6F4_CELL_TEMP = {.FD = true, + .ext_ID = false, + .DLC = 5, + .ID = 0x6F4, + .data = {0x07, 0x03, 0x22, 0xE5, 0xCA}}; //Request Data CAN End static bool battery_awake = false; //Setup UDS values to poll for -CAN_frame* UDS_REQUESTS100MS[] = { - &BMWiX_6F4_REQUEST_CELL_TEMP, - &BMWiX_6F4_REQUEST_SOC, - &BMWiX_6F4_REQUEST_CAPACITY, - &BMWiX_6F4_REQUEST_MINMAXCELLV, - &BMWiX_6F4_REQUEST_MAINVOLTAGE_POSTCONTACTOR, - &BMWiX_6F4_REQUEST_MAINVOLTAGE_PRECONTACTOR, - &BMWiX_6F4_REQUEST_BATTERYCURRENT, - &BMWiX_6F4_REQUEST_CELL_VOLTAGE, - &BMWiX_6F4_REQUEST_T30VOLTAGE, - &BMWiX_6F4_REQUEST_SOH, - &BMWiX_6F4_REQUEST_UPTIME, - &BMWiX_6F4_REQUEST_PYRO, - &BMWiX_6F4_REQUEST_EOL_ISO, - &BMWiX_6F4_REQUEST_HVIL, - &BMWiX_6F4_REQUEST_MAX_CHARGE_DISCHARGE_AMPS, - &BMWiX_6F4_REQUEST_BALANCINGSTATUS, - &BMWiX_6F4_REQUEST_PACK_VOLTAGE_LIMITS - }; -int numUDSreqs = sizeof(UDS_REQUESTS100MS) / sizeof(UDS_REQUESTS100MS[0]); // Number of elements in the array +CAN_frame* UDS_REQUESTS100MS[] = {&BMWiX_6F4_REQUEST_CELL_TEMP, + &BMWiX_6F4_REQUEST_SOC, + &BMWiX_6F4_REQUEST_CAPACITY, + &BMWiX_6F4_REQUEST_MINMAXCELLV, + &BMWiX_6F4_REQUEST_MAINVOLTAGE_POSTCONTACTOR, + &BMWiX_6F4_REQUEST_MAINVOLTAGE_PRECONTACTOR, + &BMWiX_6F4_REQUEST_BATTERYCURRENT, + &BMWiX_6F4_REQUEST_CELL_VOLTAGE, + &BMWiX_6F4_REQUEST_T30VOLTAGE, + &BMWiX_6F4_REQUEST_SOH, + &BMWiX_6F4_REQUEST_UPTIME, + &BMWiX_6F4_REQUEST_PYRO, + &BMWiX_6F4_REQUEST_EOL_ISO, + &BMWiX_6F4_REQUEST_HVIL, + &BMWiX_6F4_REQUEST_MAX_CHARGE_DISCHARGE_AMPS, + &BMWiX_6F4_REQUEST_BALANCINGSTATUS, + &BMWiX_6F4_REQUEST_PACK_VOLTAGE_LIMITS}; +int numUDSreqs = sizeof(UDS_REQUESTS100MS) / sizeof(UDS_REQUESTS100MS[0]); // Number of elements in the array //iX Intermediate vars static bool battery_info_available = false; @@ -161,9 +336,9 @@ static int16_t battery_voltage_after_contactor = 0; static int16_t min_soc_state = 50; static int16_t avg_soc_state = 50; static int16_t max_soc_state = 50; -static int16_t min_soh_state = 99;// Uses E5 45, also available in 78 73 -static int16_t avg_soh_state = 99;// Uses E5 45, also available in 78 73 -static int16_t max_soh_state = 99;// Uses E5 45, also available in 78 73 +static int16_t min_soh_state = 99; // Uses E5 45, also available in 78 73 +static int16_t avg_soh_state = 99; // Uses E5 45, also available in 78 73 +static int16_t max_soh_state = 99; // Uses E5 45, also available in 78 73 static uint16_t max_design_voltage = 0; static uint16_t min_design_voltage = 0; static int32_t remaining_capacity = 0; @@ -179,37 +354,36 @@ static unsigned long max_cell_voltage_lastchanged = 0; static unsigned min_cell_voltage_lastreceived = 0; static unsigned max_cell_voltage_lastreceived = 0; static int16_t battery_power = 0; -static uint32_t sme_uptime = 0; //Uses E4 C0 -static int16_t allowable_charge_amps = 0; //E5 62 -static int16_t allowable_discharge_amps = 0; //E5 62 -static int32_t iso_safety_positive = 0; //Uses A8 60 -static int32_t iso_safety_negative = 0; //Uses A8 60 -static int32_t iso_safety_parallel = 0; //Uses A8 60 -static int16_t count_full_charges = 0; //TODO 42 -static int16_t count_charges = 0; //TODO 42 -static int16_t hvil_status = 0; -static int16_t voltage_qualifier_status = 0; //0 = Valid, 1 = Invalid -static int16_t balancing_status = 0; //4 = not active -static uint8_t contactors_closed = 0; //TODO E5 BF or E5 51 -static uint8_t contactor_status_precharge = 0; //TODO E5 BF -static uint8_t contactor_status_negative = 0; //TODO E5 BF -static uint8_t contactor_status_positive = 0; //TODO E5 BF -static uint8_t pyro_status_pss1 = 0; //Using AC 93 -static uint8_t pyro_status_pss4 = 0; //Using AC 93 -static uint8_t pyro_status_pss6 = 0; //Using AC 93 +static uint32_t sme_uptime = 0; //Uses E4 C0 +static int16_t allowable_charge_amps = 0; //E5 62 +static int16_t allowable_discharge_amps = 0; //E5 62 +static int32_t iso_safety_positive = 0; //Uses A8 60 +static int32_t iso_safety_negative = 0; //Uses A8 60 +static int32_t iso_safety_parallel = 0; //Uses A8 60 +static int16_t count_full_charges = 0; //TODO 42 +static int16_t count_charges = 0; //TODO 42 +static int16_t hvil_status = 0; +static int16_t voltage_qualifier_status = 0; //0 = Valid, 1 = Invalid +static int16_t balancing_status = 0; //4 = not active +static uint8_t contactors_closed = 0; //TODO E5 BF or E5 51 +static uint8_t contactor_status_precharge = 0; //TODO E5 BF +static uint8_t contactor_status_negative = 0; //TODO E5 BF +static uint8_t contactor_status_positive = 0; //TODO E5 BF +static uint8_t pyro_status_pss1 = 0; //Using AC 93 +static uint8_t pyro_status_pss4 = 0; //Using AC 93 +static uint8_t pyro_status_pss6 = 0; //Using AC 93 static uint8_t uds_req_id_counter = 0; -const unsigned long STALE_PERIOD = STALE_PERIOD_CONFIG ; // Time in milliseconds to check for staleness (e.g., 5000 ms = 5 seconds) +const unsigned long STALE_PERIOD = + STALE_PERIOD_CONFIG; // Time in milliseconds to check for staleness (e.g., 5000 ms = 5 seconds) - - -static byte iX_0C0_counter = 0xF0; // Initialize to 0xF0 +static byte iX_0C0_counter = 0xF0; // Initialize to 0xF0 //End iX Intermediate vars static uint8_t current_cell_polled = 0; // Function to check if a value has gone stale over a specified time period -bool isStale(int16_t currentValue, uint16_t &lastValue, unsigned long &lastChangeTime) { +bool isStale(int16_t currentValue, uint16_t& lastValue, unsigned long& lastChangeTime) { unsigned long currentTime = millis(); // Check if the value has changed @@ -244,7 +418,7 @@ static byte increment_0C0_counter(byte counter) { counter++; // Reset to 0xF0 if it exceeds 0xFE if (counter > 0xFE) { - counter = 0xF0; + counter = 0xF0; } return counter; } @@ -263,12 +437,11 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.soh_pptt = min_soh_state; - datalayer.battery.status.max_discharge_power_W = 3200; //10000; //Aux HV Port has 100A Fuse + datalayer.battery.status.max_discharge_power_W = 3200; //10000; //Aux HV Port has 100A Fuse //datalayer.battery.status.max_charge_power_W = 3200; //10000; //Aux HV Port has 100A Fuse Moved to Ramping - - // Charge power is set in .h file + // Charge power is set in .h file if (datalayer.battery.status.real_soc > 9900) { datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_WHEN_TOPBALANCING_W; } else if (datalayer.battery.status.real_soc > RAMPDOWN_SOC) { @@ -280,7 +453,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_ALLOWED_W; } - battery_power = (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); datalayer.battery.status.active_power_W = battery_power; @@ -289,22 +461,22 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.temperature_max_dC = max_battery_temperature; - - - if (isStale(min_cell_voltage, datalayer.battery.status.cell_min_voltage_mV, min_cell_voltage_lastchanged)) {//TODO prevent flipflop after error + if (isStale(min_cell_voltage, datalayer.battery.status.cell_min_voltage_mV, + min_cell_voltage_lastchanged)) { //TODO prevent flipflop after error Serial.println("min_cell_voltage has gone stale."); - datalayer.battery.status.cell_min_voltage_mV = 9999; //Stale values force stop - set_event(EVENT_CAN_RX_FAILURE,0); + datalayer.battery.status.cell_min_voltage_mV = 9999; //Stale values force stop + set_event(EVENT_CAN_RX_FAILURE, 0); } else { - datalayer.battery.status.cell_min_voltage_mV = min_cell_voltage; //Value is alive + datalayer.battery.status.cell_min_voltage_mV = min_cell_voltage; //Value is alive } - if (isStale(max_cell_voltage, datalayer.battery.status.cell_max_voltage_mV, max_cell_voltage_lastchanged)) { //TODO prevent flipflop after error + if (isStale(max_cell_voltage, datalayer.battery.status.cell_max_voltage_mV, + max_cell_voltage_lastchanged)) { //TODO prevent flipflop after error Serial.println("max_cell_voltage has gone stale."); - datalayer.battery.status.cell_max_voltage_mV = 9999; //Stale values force stop - set_event(EVENT_CAN_RX_FAILURE,0); + datalayer.battery.status.cell_max_voltage_mV = 9999; //Stale values force stop + set_event(EVENT_CAN_RX_FAILURE, 0); } else { - datalayer.battery.status.cell_max_voltage_mV = max_cell_voltage; //Value is alive + datalayer.battery.status.cell_max_voltage_mV = max_cell_voltage; //Value is alive } datalayer_extended.bmwix.min_cell_voltage_data_age = (millis() - min_cell_voltage_lastchanged); @@ -315,11 +487,11 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.info.min_design_voltage_dV = min_design_voltage; - datalayer.battery.info.number_of_cells = 108; //init with 108S before autodetection + datalayer.battery.info.number_of_cells = 108; //init with 108S before autodetection datalayer_extended.bmwix.T30_Voltage = terminal30_12v_voltage; - datalayer_extended.bmwix.hvil_status= hvil_status; + datalayer_extended.bmwix.hvil_status = hvil_status; datalayer_extended.bmwix.bms_uptime = sme_uptime; @@ -337,25 +509,19 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.bmwix.allowable_charge_amps = allowable_charge_amps; - datalayer_extended.bmwix.allowable_discharge_amps= allowable_discharge_amps; + datalayer_extended.bmwix.allowable_discharge_amps = allowable_discharge_amps; datalayer_extended.bmwix.balancing_status = balancing_status; datalayer_extended.bmwix.battery_voltage_after_contactor = battery_voltage_after_contactor; - - - - if (battery_info_available) { // If we have data from battery - override the defaults to suit - datalayer.battery.info.max_design_voltage_dV = max_design_voltage; - datalayer.battery.info.min_design_voltage_dV = min_design_voltage; - datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; - datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + datalayer.battery.info.max_design_voltage_dV = max_design_voltage; + datalayer.battery.info.min_design_voltage_dV = min_design_voltage; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; } - - } void receive_can_battery(CAN_frame rx_frame) { battery_awake = true; @@ -364,179 +530,198 @@ void receive_can_battery(CAN_frame rx_frame) { break; case 0x607: //SME responds to UDS requests on 0x607 - if (rx_frame.DLC > 6 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x10 && rx_frame.data.u8[2] == 0xE3 && rx_frame.data.u8[3] == 0x62 && rx_frame.data.u8[4] == 0xE5){ - //First of multi frame data - Parse the first frame - if (rx_frame.DLC = 64 && rx_frame.data.u8[5] == 0x54) { //Individual Cell Voltages - First Frame - int start_index = 6; //Data starts here - int voltage_index = 0; //Start cell ID - int num_voltages = 29; // number of voltage readings to get - for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { - uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; - if (voltage < 10000) { //Check reading is plausible - otherwise ignore - datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; - } - voltage_index++; - } + if (rx_frame.DLC > 6 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x10 && + rx_frame.data.u8[2] == 0xE3 && rx_frame.data.u8[3] == 0x62 && rx_frame.data.u8[4] == 0xE5) { + //First of multi frame data - Parse the first frame + if (rx_frame.DLC = 64 && rx_frame.data.u8[5] == 0x54) { //Individual Cell Voltages - First Frame + int start_index = 6; //Data starts here + int voltage_index = 0; //Start cell ID + int num_voltages = 29; // number of voltage readings to get + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { + uint16_t voltage = (rx_frame.data.u8[i] << 8) | rx_frame.data.u8[i + 1]; + if (voltage < 10000) { //Check reading is plausible - otherwise ignore + datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; } - + voltage_index++; + } + } + //Frame has continued data - so request it transmit_can(&BMWiX_6F4_CONTINUE_DATA, can_config.battery); } - if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x21){ //Individual Cell Voltages - 1st Continue frame - int start_index = 2; //Data starts here - int voltage_index = 29; //Start cell ID - int num_voltages = 31; // number of voltage readings to get - for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { - uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; - if (voltage < 10000) { //Check reading is plausible - otherwise ignore - datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; - } - voltage_index++; - } + if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && + rx_frame.data.u8[1] == 0x21) { //Individual Cell Voltages - 1st Continue frame + int start_index = 2; //Data starts here + int voltage_index = 29; //Start cell ID + int num_voltages = 31; // number of voltage readings to get + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { + uint16_t voltage = (rx_frame.data.u8[i] << 8) | rx_frame.data.u8[i + 1]; + if (voltage < 10000) { //Check reading is plausible - otherwise ignore + datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; + } + voltage_index++; + } } - if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x22){ //Individual Cell Voltages - 2nd Continue frame - int start_index = 2; //Data starts here - int voltage_index = 60; //Start cell ID - int num_voltages = 31; // number of voltage readings to get - for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { - uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; - if (voltage < 10000) { //Check reading is plausible - otherwise ignore - datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; - } - voltage_index++; - } - } - - if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x23){ //Individual Cell Voltages - 3rd Continue frame - int start_index = 2; //Data starts here - int voltage_index = 91; //Start cell ID - int num_voltages; - if (rx_frame.data.u8[12] == 0xFF && rx_frame.data.u8[13]== 0xFF){ //97th cell is blank - assume 96S Battery - num_voltages = 5; // number of voltage readings to get - 6 more to get on 96S - datalayer.battery.info.number_of_cells = 96; - } else { //We have data in 97th cell, assume 108S Battery - num_voltages = 17; // number of voltage readings to get - 17 more to get on 108S - datalayer.battery.info.number_of_cells = 108; - } - - for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { - uint16_t voltage = (rx_frame.data.u8[i] <<8) | rx_frame.data.u8[i + 1]; - datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; - } - } - if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0x4D) { //Main Battery Voltage (Pre Contactor) - battery_voltage = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6])/10; - } - - if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0x4A) { //Main Battery Voltage (After Contactor) - battery_voltage_after_contactor = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6])/10; - } - - - if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x61) { //Current amps 32bit signed MSB. dA . negative is discharge - battery_current = ((int32_t)((rx_frame.data.u8[6] << 24) | - (rx_frame.data.u8[7] << 16) | - (rx_frame.data.u8[8] << 8) | - rx_frame.data.u8[9]))*0.1; - } - - if (rx_frame.DLC = 64 && rx_frame.data.u8[4] == 0xE4 && rx_frame.data.u8[5] == 0xCA) { //Balancing Data - balancing_status = ( rx_frame.data.u8[6]); //4 = No symmetry mode active, invalid qualifier - } - if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0xCE) { //Min/Avg/Max SOC% - min_soc_state = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); - avg_soc_state = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); - max_soc_state = (rx_frame.data.u8[10] <<8 |rx_frame.data.u8[11]); - } - - if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0xC7) { //Current and max capacity kWh. Stored in kWh as 0.01 scale with -50 bias - remaining_capacity = ((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) *10) -50000; - max_capacity = ((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) *10) -50000; - } - - if (rx_frame.DLC = 20 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x45) { //SOH Max Min Mean Request - min_soh_state = ((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9])); - avg_soh_state = ((rx_frame.data.u8[10] <<8 | rx_frame.data.u8[11])); - max_soh_state = ((rx_frame.data.u8[12] <<8 | rx_frame.data.u8[13])); - } - - if (rx_frame.DLC = 10 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x62) { //Max allowed charge and discharge current - Signed 16bit - allowable_charge_amps = (int16_t)((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]))/10; - allowable_discharge_amps = (int16_t)((rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]))/10; - } - - if (rx_frame.DLC = 9 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x4B) { //Max allowed charge and discharge current - Signed 16bit - voltage_qualifier_status = ( rx_frame.data.u8[8]); // Request HV Voltage Qualifier - } - - if (rx_frame.DLC = 48 && rx_frame.data.u8[4] == 0xA8 && rx_frame.data.u8[5] == 0x60) { // Safety Isolation Measurements - iso_safety_positive = (rx_frame.data.u8[34] << 24) | (rx_frame.data.u8[35] << 16) | (rx_frame.data.u8[36] << 8) |rx_frame.data.u8[37]; //Assuming 32bit - iso_safety_negative = (rx_frame.data.u8[38] << 24) | (rx_frame.data.u8[39] << 16) | (rx_frame.data.u8[40] << 8) |rx_frame.data.u8[41]; //Assuming 32bit - iso_safety_parallel = (rx_frame.data.u8[42] << 24) | (rx_frame.data.u8[43] << 16) | (rx_frame.data.u8[44] << 8) |rx_frame.data.u8[45]; //Assuming 32bit - } - - - if (rx_frame.DLC = 48 && rx_frame.data.u8[4] == 0xE4 && rx_frame.data.u8[5] == 0xC0) { // Uptime and Vehicle Time Status - sme_uptime = (rx_frame.data.u8[10] << 24) | (rx_frame.data.u8[11] << 16) | (rx_frame.data.u8[12] << 8) |rx_frame.data.u8[13]; //Assuming 32bit - } - - if (rx_frame.DLC = 8 && rx_frame.data.u8[3] == 0xAC && rx_frame.data.u8[4] == 0x93) { // Pyro Status - pyro_status_pss1 = (rx_frame.data.u8[5]); - pyro_status_pss4 = (rx_frame.data.u8[6]); - pyro_status_pss6 = (rx_frame.data.u8[7]); - } - - if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x53) { //Min and max cell voltage 10V = Qualifier Invalid - - datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //This is the most important safety values, if we receive this we reset CAN alive counter. - - if((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) == 10000 && (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) == 10000){ //Qualifier Invalid Mode - Request Reboot - #ifdef DEBUG_VIA_USB - Serial.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); - #endif - set_event(EVENT_SOC_UNAVAILABLE, (millis())); - transmit_can(&BMWiX_6F4_REQUEST_HARD_RESET, can_config.battery); - } else{ //Only ingest values if they are not the 10V Error state - min_cell_voltage = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); - max_cell_voltage = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); - } - } - - if (rx_frame.DLC = 16 && rx_frame.data.u8[4] == 0xDD && rx_frame.data.u8[5] == 0xC0) { //Battery Temperature - min_battery_temperature = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7])/10; - avg_battery_temperature = (rx_frame.data.u8[10] <<8 | rx_frame.data.u8[11])/10; - max_battery_temperature = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9])/10; - } - if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA3) { //Main Contactor Temperature CHECK FINGERPRINT 2 LEVEL - main_contactor_temperature = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); - } - if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA7) { //Terminal 30 Voltage (12V SME supply) - terminal30_12v_voltage = (rx_frame.data.u8[5] <<8 | rx_frame.data.u8[6]); - } - if (rx_frame.DLC = 6 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x04 && rx_frame.data.u8[2] == 0x62 && rx_frame.data.u8[3] == 0xE5 && rx_frame.data.u8[4] == 0x69) { //HVIL Status - hvil_status = ( rx_frame.data.u8[5]); - } - - if (rx_frame.DLC = 12 && rx_frame.data.u8[2] == 0x07 && rx_frame.data.u8[3] == 0x62 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x4C) { //Pack Voltage Limits - if ((rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]) < 4700 && (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]) > 2600) { //Make sure values are plausible - battery_info_available = true; - max_design_voltage = (rx_frame.data.u8[6] <<8 | rx_frame.data.u8[7]); - min_design_voltage = (rx_frame.data.u8[8] <<8 | rx_frame.data.u8[9]); - } - } - - if (rx_frame.DLC = 16 && rx_frame.data.u8[3] == 0xF1 && rx_frame.data.u8[4] == 0x8C ) { //Battery Serial Number - //Convert hex bytes to ASCII characters and combine them into a string - char numberString[11]; // 10 characters + null terminator - for (int i = 0; i < 10; i++) { - numberString[i] = char(rx_frame.data.u8[i+6]); + if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && + rx_frame.data.u8[1] == 0x22) { //Individual Cell Voltages - 2nd Continue frame + int start_index = 2; //Data starts here + int voltage_index = 60; //Start cell ID + int num_voltages = 31; // number of voltage readings to get + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { + uint16_t voltage = (rx_frame.data.u8[i] << 8) | rx_frame.data.u8[i + 1]; + if (voltage < 10000) { //Check reading is plausible - otherwise ignore + datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; } - numberString[10] = '\0'; // Null-terminate the string - // Step 3: Convert the string to an unsigned long integer - battery_serial_number = strtoul(numberString, NULL, 10); - } + voltage_index++; + } + } + + if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && + rx_frame.data.u8[1] == 0x23) { //Individual Cell Voltages - 3rd Continue frame + int start_index = 2; //Data starts here + int voltage_index = 91; //Start cell ID + int num_voltages; + if (rx_frame.data.u8[12] == 0xFF && rx_frame.data.u8[13] == 0xFF) { //97th cell is blank - assume 96S Battery + num_voltages = 5; // number of voltage readings to get - 6 more to get on 96S + datalayer.battery.info.number_of_cells = 96; + } else { //We have data in 97th cell, assume 108S Battery + num_voltages = 17; // number of voltage readings to get - 17 more to get on 108S + datalayer.battery.info.number_of_cells = 108; + } + + for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { + uint16_t voltage = (rx_frame.data.u8[i] << 8) | rx_frame.data.u8[i + 1]; + datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + } + } + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0x4D) { //Main Battery Voltage (Pre Contactor) + battery_voltage = (rx_frame.data.u8[5] << 8 | rx_frame.data.u8[6]) / 10; + } + + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0x4A) { //Main Battery Voltage (After Contactor) + battery_voltage_after_contactor = (rx_frame.data.u8[5] << 8 | rx_frame.data.u8[6]) / 10; + } + + if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && + rx_frame.data.u8[5] == 0x61) { //Current amps 32bit signed MSB. dA . negative is discharge + battery_current = ((int32_t)((rx_frame.data.u8[6] << 24) | (rx_frame.data.u8[7] << 16) | + (rx_frame.data.u8[8] << 8) | rx_frame.data.u8[9])) * + 0.1; + } + + if (rx_frame.DLC = 64 && rx_frame.data.u8[4] == 0xE4 && rx_frame.data.u8[5] == 0xCA) { //Balancing Data + balancing_status = (rx_frame.data.u8[6]); //4 = No symmetry mode active, invalid qualifier + } + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0xCE) { //Min/Avg/Max SOC% + min_soc_state = (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]); + avg_soc_state = (rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]); + max_soc_state = (rx_frame.data.u8[10] << 8 | rx_frame.data.u8[11]); + } + + if (rx_frame.DLC = + 12 && rx_frame.data.u8[4] == 0xE5 && + rx_frame.data.u8[5] == 0xC7) { //Current and max capacity kWh. Stored in kWh as 0.01 scale with -50 bias + remaining_capacity = ((rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]) * 10) - 50000; + max_capacity = ((rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]) * 10) - 50000; + } + + if (rx_frame.DLC = 20 && rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x45) { //SOH Max Min Mean Request + min_soh_state = ((rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9])); + avg_soh_state = ((rx_frame.data.u8[10] << 8 | rx_frame.data.u8[11])); + max_soh_state = ((rx_frame.data.u8[12] << 8 | rx_frame.data.u8[13])); + } + + if (rx_frame.DLC = 10 && rx_frame.data.u8[4] == 0xE5 && + rx_frame.data.u8[5] == 0x62) { //Max allowed charge and discharge current - Signed 16bit + allowable_charge_amps = (int16_t)((rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7])) / 10; + allowable_discharge_amps = (int16_t)((rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9])) / 10; + } + + if (rx_frame.DLC = 9 && rx_frame.data.u8[4] == 0xE5 && + rx_frame.data.u8[5] == 0x4B) { //Max allowed charge and discharge current - Signed 16bit + voltage_qualifier_status = (rx_frame.data.u8[8]); // Request HV Voltage Qualifier + } + + if (rx_frame.DLC = + 48 && rx_frame.data.u8[4] == 0xA8 && rx_frame.data.u8[5] == 0x60) { // Safety Isolation Measurements + iso_safety_positive = (rx_frame.data.u8[34] << 24) | (rx_frame.data.u8[35] << 16) | + (rx_frame.data.u8[36] << 8) | rx_frame.data.u8[37]; //Assuming 32bit + iso_safety_negative = (rx_frame.data.u8[38] << 24) | (rx_frame.data.u8[39] << 16) | + (rx_frame.data.u8[40] << 8) | rx_frame.data.u8[41]; //Assuming 32bit + iso_safety_parallel = (rx_frame.data.u8[42] << 24) | (rx_frame.data.u8[43] << 16) | + (rx_frame.data.u8[44] << 8) | rx_frame.data.u8[45]; //Assuming 32bit + } + + if (rx_frame.DLC = + 48 && rx_frame.data.u8[4] == 0xE4 && rx_frame.data.u8[5] == 0xC0) { // Uptime and Vehicle Time Status + sme_uptime = (rx_frame.data.u8[10] << 24) | (rx_frame.data.u8[11] << 16) | (rx_frame.data.u8[12] << 8) | + rx_frame.data.u8[13]; //Assuming 32bit + } + + if (rx_frame.DLC = 8 && rx_frame.data.u8[3] == 0xAC && rx_frame.data.u8[4] == 0x93) { // Pyro Status + pyro_status_pss1 = (rx_frame.data.u8[5]); + pyro_status_pss4 = (rx_frame.data.u8[6]); + pyro_status_pss6 = (rx_frame.data.u8[7]); + } + + if (rx_frame.DLC = 12 && rx_frame.data.u8[4] == 0xE5 && + rx_frame.data.u8[5] == 0x53) { //Min and max cell voltage 10V = Qualifier Invalid + + datalayer.battery.status.CAN_battery_still_alive = + CAN_STILL_ALIVE; //This is the most important safety values, if we receive this we reset CAN alive counter. + + if ((rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]) == 10000 && + (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]) == 10000) { //Qualifier Invalid Mode - Request Reboot +#ifdef DEBUG_VIA_USB + Serial.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); +#endif + set_event(EVENT_SOC_UNAVAILABLE, (millis())); + transmit_can(&BMWiX_6F4_REQUEST_HARD_RESET, can_config.battery); + } else { //Only ingest values if they are not the 10V Error state + min_cell_voltage = (rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]); + max_cell_voltage = (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]); + } + } + + if (rx_frame.DLC = 16 && rx_frame.data.u8[4] == 0xDD && rx_frame.data.u8[5] == 0xC0) { //Battery Temperature + min_battery_temperature = (rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]) / 10; + avg_battery_temperature = (rx_frame.data.u8[10] << 8 | rx_frame.data.u8[11]) / 10; + max_battery_temperature = (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]) / 10; + } + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA3) { //Main Contactor Temperature CHECK FINGERPRINT 2 LEVEL + main_contactor_temperature = (rx_frame.data.u8[5] << 8 | rx_frame.data.u8[6]); + } + if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0xA7) { //Terminal 30 Voltage (12V SME supply) + terminal30_12v_voltage = (rx_frame.data.u8[5] << 8 | rx_frame.data.u8[6]); + } + if (rx_frame.DLC = 6 && rx_frame.data.u8[0] == 0xF4 && rx_frame.data.u8[1] == 0x04 && + rx_frame.data.u8[2] == 0x62 && rx_frame.data.u8[3] == 0xE5 && + rx_frame.data.u8[4] == 0x69) { //HVIL Status + hvil_status = (rx_frame.data.u8[5]); + } + + if (rx_frame.DLC = 12 && rx_frame.data.u8[2] == 0x07 && rx_frame.data.u8[3] == 0x62 && + rx_frame.data.u8[4] == 0xE5 && rx_frame.data.u8[5] == 0x4C) { //Pack Voltage Limits + if ((rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]) < 4700 && + (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]) > 2600) { //Make sure values are plausible + battery_info_available = true; + max_design_voltage = (rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]); + min_design_voltage = (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]); + } + } + + if (rx_frame.DLC = 16 && rx_frame.data.u8[3] == 0xF1 && rx_frame.data.u8[4] == 0x8C) { //Battery Serial Number + //Convert hex bytes to ASCII characters and combine them into a string + char numberString[11]; // 10 characters + null terminator + for (int i = 0; i < 10; i++) { + numberString[i] = char(rx_frame.data.u8[i + 6]); + } + numberString[10] = '\0'; // Null-terminate the string + // Step 3: Convert the string to an unsigned long integer + battery_serial_number = strtoul(numberString, NULL, 10); + } break; default: break; @@ -547,75 +732,72 @@ void send_can_battery() { unsigned long currentMillis = millis(); //if (battery_awake) { //We can always send CAN as the iX BMS will wake up on vehicle comms - //Send 20ms message - if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { - // Check if sending of CAN messages has been delayed too much. - if ((currentMillis - previousMillis20 >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { - set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20)); - } else { - clear_event(EVENT_CAN_OVERRUN); - } - previousMillis20 = currentMillis; - } - // Send 100ms CAN Message - if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { - previousMillis100 = currentMillis; - - //Loop through and send a different UDS request each cycle - uds_req_id_counter = increment_uds_req_id_counter(uds_req_id_counter); - transmit_can(UDS_REQUESTS100MS[uds_req_id_counter], can_config.battery); - - - //Send SME Keep alive values 100ms - transmit_can(&BMWiX_510, can_config.battery); - - } - // Send 200ms CAN Message - if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { - previousMillis200 = currentMillis; - - //Send SME Keep alive values 200ms - BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 - transmit_can(&BMWiX_0C0, can_config.battery); - } - // Send 500ms CAN Message - if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { - previousMillis500 = currentMillis; - } - // Send 640ms CAN Message - if (currentMillis - previousMillis640 >= INTERVAL_640_MS) { - previousMillis640 = currentMillis; - } - // Send 1000ms CAN Message - if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { - previousMillis1000 = currentMillis; - - //Send SME Keep alive values 1000ms - //test disable transmit_can(&BMWiX_06D, can_config.battery); - //test disable transmit_can(&BMWiX_2F1, can_config.battery); - //test disable transmit_can(&BMWiX_439, can_config.battery); - - } - // Send 5000ms CAN Message - if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { - previousMillis5000 = currentMillis; - } - // Send 10000ms CAN Message - if (currentMillis - previousMillis10000 >= INTERVAL_10_S) { - previousMillis10000 = currentMillis; + //Send 20ms message + if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { + // Check if sending of CAN messages has been delayed too much. + if ((currentMillis - previousMillis20 >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20)); + } else { + clear_event(EVENT_CAN_OVERRUN); } + previousMillis20 = currentMillis; } - //We can always send CAN as the iX BMS will wake up on vehicle comms - // else { - // previousMillis20 = currentMillis; - // previousMillis100 = currentMillis; - // previousMillis200 = currentMillis; - // previousMillis500 = currentMillis; - // previousMillis640 = currentMillis; - // previousMillis1000 = currentMillis; - // previousMillis5000 = currentMillis; - // previousMillis10000 = currentMillis; - // } + // Send 100ms CAN Message + if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { + previousMillis100 = currentMillis; + + //Loop through and send a different UDS request each cycle + uds_req_id_counter = increment_uds_req_id_counter(uds_req_id_counter); + transmit_can(UDS_REQUESTS100MS[uds_req_id_counter], can_config.battery); + + //Send SME Keep alive values 100ms + transmit_can(&BMWiX_510, can_config.battery); + } + // Send 200ms CAN Message + if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { + previousMillis200 = currentMillis; + + //Send SME Keep alive values 200ms + BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 + transmit_can(&BMWiX_0C0, can_config.battery); + } + // Send 500ms CAN Message + if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { + previousMillis500 = currentMillis; + } + // Send 640ms CAN Message + if (currentMillis - previousMillis640 >= INTERVAL_640_MS) { + previousMillis640 = currentMillis; + } + // Send 1000ms CAN Message + if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { + previousMillis1000 = currentMillis; + + //Send SME Keep alive values 1000ms + //test disable transmit_can(&BMWiX_06D, can_config.battery); + //test disable transmit_can(&BMWiX_2F1, can_config.battery); + //test disable transmit_can(&BMWiX_439, can_config.battery); + } + // Send 5000ms CAN Message + if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { + previousMillis5000 = currentMillis; + } + // Send 10000ms CAN Message + if (currentMillis - previousMillis10000 >= INTERVAL_10_S) { + previousMillis10000 = currentMillis; + } +} +//We can always send CAN as the iX BMS will wake up on vehicle comms +// else { +// previousMillis20 = currentMillis; +// previousMillis100 = currentMillis; +// previousMillis200 = currentMillis; +// previousMillis500 = currentMillis; +// previousMillis640 = currentMillis; +// previousMillis1000 = currentMillis; +// previousMillis5000 = currentMillis; +// previousMillis10000 = currentMillis; +// } //} //We can always send CAN as the iX BMS will wake up on vehicle comms void setup_battery(void) { // Performs one time setup at startup @@ -631,20 +813,19 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; datalayer.system.status.battery_allows_contactor_closing = true; - //pinMode(WUP_PIN, OUTPUT); // Not needed - can hold WUP pin High with iX BMS - //digitalWrite(WUP_PIN, HIGH); // Wake up the battery // Not needed - can hold WUP pin High with iX BMS + //pinMode(WUP_PIN, OUTPUT); // Not needed - can hold WUP pin High with iX BMS + //digitalWrite(WUP_PIN, HIGH); // Wake up the battery // Not needed - can hold WUP pin High with iX BMS + //Send SME Keep alive values 100ms + transmit_can(&BMWiX_510, can_config.battery); + //Send SME Keep alive values 200ms + BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 + transmit_can(&BMWiX_0C0, can_config.battery); - //Send SME Keep alive values 100ms - transmit_can(&BMWiX_510, can_config.battery); - //Send SME Keep alive values 200ms - BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 - transmit_can(&BMWiX_0C0, can_config.battery); - - //Send SME Keep alive values 1000ms - //Not needed transmit_can(&BMWiX_06D, can_config.battery); - //Not needed transmit_can(&BMWiX_2F1, can_config.battery); - //Not needed transmit_can(&BMWiX_439, can_config.battery); + //Send SME Keep alive values 1000ms + //Not needed transmit_can(&BMWiX_06D, can_config.battery); + //Not needed transmit_can(&BMWiX_2F1, can_config.battery); + //Not needed transmit_can(&BMWiX_439, can_config.battery); } #endif diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 657811c8..450ed80a 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -12,9 +12,10 @@ #define MAX_CELL_VOLTAGE_MV 4300 //Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE_MV 2800 //Battery is put into emergency stop if one cell goes below this value #define MAX_CHARGE_POWER_ALLOWED_W 5000 -#define MAX_CHARGE_POWER_WHEN_TOPBALANCING_W 500 +#define MAX_CHARGE_POWER_WHEN_TOPBALANCING_W 500 #define RAMPDOWN_SOC 9000 // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00% -#define STALE_PERIOD_CONFIG 180000; //Number of milliseconds before critical values are classed as stale/stuck 180000 = 180 seconds +#define STALE_PERIOD_CONFIG \ + 180000; //Number of milliseconds before critical values are classed as stale/stuck 180000 = 180 seconds void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); From bb77d91791882cd21111f1d1a595dabdbf242716 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:14:35 +0000 Subject: [PATCH 25/48] Update formatting Part 2 --- .../webserver/advanced_battery_html.cpp | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index ddad0304..5db01127 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -17,41 +17,39 @@ String advanced_battery_processor(const String& var) { content += "
"; #ifdef BMW_IX_BATTERY - content += "

Battery Voltage after Contactor: " + String(datalayer_extended.bmwix.battery_voltage_after_contactor) + " dV

"; + content += + "

Battery Voltage after Contactor: " + String(datalayer_extended.bmwix.battery_voltage_after_contactor) + + " dV

"; content += "

Max Design Voltage: " + String(datalayer.battery.info.max_design_voltage_dV) + " dV

"; content += "

Min Design Voltage: " + String(datalayer.battery.info.min_design_voltage_dV) + " dV

"; content += "

Max Cell Design Voltage: " + String(datalayer.battery.info.max_cell_voltage_mV) + " mV

"; content += "

Min Cell Design Voltage: " + String(datalayer.battery.info.min_cell_voltage_mV) + " mV

"; - content += "

Min Cell Voltage Data Age: " + String(datalayer_extended.bmwix.min_cell_voltage_data_age) + " ms

"; - content += "

Max Cell Voltage Data Age: " + String(datalayer_extended.bmwix.max_cell_voltage_data_age) + " ms

"; + content += + "

Min Cell Voltage Data Age: " + String(datalayer_extended.bmwix.min_cell_voltage_data_age) + " ms

"; + content += + "

Max Cell Voltage Data Age: " + String(datalayer_extended.bmwix.max_cell_voltage_data_age) + " ms

"; content += "

Allowed Discharge Power: " + String(datalayer.battery.status.max_discharge_power_W) + " W

"; content += "

Allowed Charge Power: " + String(datalayer.battery.status.max_charge_power_W) + " W

"; - content += "

T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + " mV

"; + content += "

T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + " mV

"; content += "

Detected Cell Count: " + String(datalayer.battery.info.number_of_cells) + "

"; - static const char* balanceText[5] = {"0 No balancing mode active", - "1 Voltage-Controlled Balancing Mode", - "2 Time-Controlled Balancing Mode with Demand Calculation at End of Charging" , - "3 Time-Controlled Balancing Mode with Demand Calculation at Resting Voltage" , - "4 No balancing mode active, qualifier invalid" - }; + static const char* balanceText[5] = {"0 No balancing mode active", "1 Voltage-Controlled Balancing Mode", + "2 Time-Controlled Balancing Mode with Demand Calculation at End of Charging", + "3 Time-Controlled Balancing Mode with Demand Calculation at Resting Voltage", + "4 No balancing mode active, qualifier invalid"}; content += "

Balancing: " + String((balanceText[datalayer_extended.bmwix.balancing_status])) + "

"; - static const char* hvilText[2] = {"Error (Loop Open)", - "OK (Loop Closed)"}; + static const char* hvilText[2] = {"Error (Loop Open)", "OK (Loop Closed)"}; content += "

HVIL Status: " + String(hvilText[datalayer_extended.bmwix.hvil_status]) + "

"; content += "

BMS Uptime: " + String(datalayer_extended.bmwix.bms_uptime) + " seconds

"; content += "

BMS Allowed Charge Amps: " + String(datalayer_extended.bmwix.allowable_charge_amps) + " A

"; - content += "

BMS Allowed Disharge Amps: " + String(datalayer_extended.bmwix.allowable_discharge_amps) + " A

"; + content += + "

BMS Allowed Disharge Amps: " + String(datalayer_extended.bmwix.allowable_discharge_amps) + " A

"; content += "
"; content += "

HV Isolation (2147483647kOhm = maximum/invalid)

"; content += "

Isolation Positive: " + String(datalayer_extended.bmwix.iso_safety_positive) + " kOhm

"; content += "

Isolation Negative: " + String(datalayer_extended.bmwix.iso_safety_negative) + " kOhm

"; content += "

Isolation Parallel: " + String(datalayer_extended.bmwix.iso_safety_parallel) + " kOhm

"; - static const char* pyroText[5] = {"0 Value Invalid", - "1 Successfully Blown", - "2 Disconnected" , - "3 Not Activated - Pyro Intact" , - "4 Unknown" - }; + static const char* pyroText[5] = {"0 Value Invalid", "1 Successfully Blown", "2 Disconnected", + "3 Not Activated - Pyro Intact", "4 Unknown"}; content += "

Pyro Status PSS1: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss1])) + "

"; content += "

Pyro Status PSS4: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss4])) + "

"; content += "

Pyro Status PSS6: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss6])) + "

"; From 8a4525c15c20344f3b00ef063fe39e7ed8ac04f0 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:20:27 +0000 Subject: [PATCH 26/48] Update formatting part 3 --- Software/src/datalayer/datalayer_extended.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 3f434764..2009d60b 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -8,17 +8,17 @@ typedef struct { /** Terminal 30 - 12V SME Supply Voltage */ uint16_t T30_Voltage = 0; /** Status HVIL, 1 HVIL OK, 0 HVIL disconnected*/ - uint8_t hvil_status= 0; + uint8_t hvil_status = 0; /** Min/Max Cell SOH*/ uint16_t min_soh_state = 0; - uint16_t max_soh_state=0; - uint32_t bms_uptime=0; - uint8_t pyro_status_pss1=0; - uint8_t pyro_status_pss4=0; - uint8_t pyro_status_pss6=0; - int32_t iso_safety_positive=0; - int32_t iso_safety_negative=0; - int32_t iso_safety_parallel=0; + uint16_t max_soh_state = 0; + uint32_t bms_uptime = 0; + uint8_t pyro_status_pss1 = 0; + uint8_t pyro_status_pss4 = 0; + uint8_t pyro_status_pss6 = 0; + int32_t iso_safety_positive = 0; + int32_t iso_safety_negative = 0; + int32_t iso_safety_parallel = 0; int32_t allowable_charge_amps = 0; int32_t allowable_discharge_amps = 0; int16_t balancing_status = 0; @@ -28,7 +28,6 @@ typedef struct { } DATALAYER_INFO_BMWIX; - typedef struct { /** uint16_t */ /** SOC% raw battery value. Might not always reach 100% */ From b08d93b6a79b213ed5ca54f60ba482b98bdfbaa9 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:44:12 +0000 Subject: [PATCH 27/48] Discharge rate defs and plausible check coverage --- Software/src/battery/BMW-IX-BATTERY.cpp | 7 +++++-- Software/src/battery/BMW-IX-BATTERY.h | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 37110fb7..3857f16e 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -437,7 +437,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.soh_pptt = min_soh_state; - datalayer.battery.status.max_discharge_power_W = 3200; //10000; //Aux HV Port has 100A Fuse + datalayer.battery.status.max_discharge_power_W = MAX_DISCHARGE_POWER_ALLOWED_W; //datalayer.battery.status.max_charge_power_W = 3200; //10000; //Aux HV Port has 100A Fuse Moved to Ramping @@ -593,7 +593,10 @@ void receive_can_battery(CAN_frame rx_frame) { for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { uint16_t voltage = (rx_frame.data.u8[i] << 8) | rx_frame.data.u8[i + 1]; - datalayer.battery.status.cell_voltages_mV[voltage_index++] = voltage; + if (voltage < 10000) { //Check reading is plausible - otherwise ignore + datalayer.battery.status.cell_voltages_mV[voltage_index] = voltage; + } + voltage_index++; } } if (rx_frame.DLC = 7 && rx_frame.data.u8[4] == 0x4D) { //Main Battery Voltage (Pre Contactor) diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 450ed80a..72afe6d5 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -11,7 +11,8 @@ #define MAX_CELL_DEVIATION_MV 250 #define MAX_CELL_VOLTAGE_MV 4300 //Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE_MV 2800 //Battery is put into emergency stop if one cell goes below this value -#define MAX_CHARGE_POWER_ALLOWED_W 5000 +#define MAX_DISCHARGE_POWER_ALLOWED_W 10000 +#define MAX_CHARGE_POWER_ALLOWED_W 10000 #define MAX_CHARGE_POWER_WHEN_TOPBALANCING_W 500 #define RAMPDOWN_SOC 9000 // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00% #define STALE_PERIOD_CONFIG \ From 7efe4323fda6233aa6bd8b488568e4d7f5493a1f Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:14:20 +0000 Subject: [PATCH 28/48] Various Review cleanups -unchecked debug logging removed -datalayer updates grouped -cleaned up message loops -cleaned up setup function --- Software/src/battery/BMW-IX-BATTERY.cpp | 54 +++++-------------------- 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 3857f16e..33556d6c 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -461,34 +461,30 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.temperature_max_dC = max_battery_temperature; - if (isStale(min_cell_voltage, datalayer.battery.status.cell_min_voltage_mV, - min_cell_voltage_lastchanged)) { //TODO prevent flipflop after error - Serial.println("min_cell_voltage has gone stale."); + if (isStale(min_cell_voltage, datalayer.battery.status.cell_min_voltage_mV, min_cell_voltage_lastchanged)) { datalayer.battery.status.cell_min_voltage_mV = 9999; //Stale values force stop set_event(EVENT_CAN_RX_FAILURE, 0); } else { datalayer.battery.status.cell_min_voltage_mV = min_cell_voltage; //Value is alive } - if (isStale(max_cell_voltage, datalayer.battery.status.cell_max_voltage_mV, - max_cell_voltage_lastchanged)) { //TODO prevent flipflop after error - Serial.println("max_cell_voltage has gone stale."); + if (isStale(max_cell_voltage, datalayer.battery.status.cell_max_voltage_mV, max_cell_voltage_lastchanged)) { datalayer.battery.status.cell_max_voltage_mV = 9999; //Stale values force stop set_event(EVENT_CAN_RX_FAILURE, 0); } else { datalayer.battery.status.cell_max_voltage_mV = max_cell_voltage; //Value is alive } - datalayer_extended.bmwix.min_cell_voltage_data_age = (millis() - min_cell_voltage_lastchanged); - - datalayer_extended.bmwix.max_cell_voltage_data_age = (millis() - max_cell_voltage_lastchanged); - datalayer.battery.info.max_design_voltage_dV = max_design_voltage; datalayer.battery.info.min_design_voltage_dV = min_design_voltage; datalayer.battery.info.number_of_cells = 108; //init with 108S before autodetection + datalayer_extended.bmwix.min_cell_voltage_data_age = (millis() - min_cell_voltage_lastchanged); + + datalayer_extended.bmwix.max_cell_voltage_data_age = (millis() - max_cell_voltage_lastchanged); + datalayer_extended.bmwix.T30_Voltage = terminal30_12v_voltage; datalayer_extended.bmwix.hvil_status = hvil_status; @@ -735,16 +731,6 @@ void send_can_battery() { unsigned long currentMillis = millis(); //if (battery_awake) { //We can always send CAN as the iX BMS will wake up on vehicle comms - //Send 20ms message - if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { - // Check if sending of CAN messages has been delayed too much. - if ((currentMillis - previousMillis20 >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { - set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20)); - } else { - clear_event(EVENT_CAN_OVERRUN); - } - previousMillis20 = currentMillis; - } // Send 100ms CAN Message if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; @@ -764,22 +750,14 @@ void send_can_battery() { BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 transmit_can(&BMWiX_0C0, can_config.battery); } - // Send 500ms CAN Message - if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { - previousMillis500 = currentMillis; - } - // Send 640ms CAN Message - if (currentMillis - previousMillis640 >= INTERVAL_640_MS) { - previousMillis640 = currentMillis; - } // Send 1000ms CAN Message if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { previousMillis1000 = currentMillis; //Send SME Keep alive values 1000ms - //test disable transmit_can(&BMWiX_06D, can_config.battery); - //test disable transmit_can(&BMWiX_2F1, can_config.battery); - //test disable transmit_can(&BMWiX_439, can_config.battery); + //Don't believe this is needed: transmit_can(&BMWiX_06D, can_config.battery); + //Don't believe this is needed: transmit_can(&BMWiX_2F1, can_config.battery); + //Don't believe this is needed: transmit_can(&BMWiX_439, can_config.battery); } // Send 5000ms CAN Message if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { @@ -815,20 +793,6 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; datalayer.system.status.battery_allows_contactor_closing = true; - - //pinMode(WUP_PIN, OUTPUT); // Not needed - can hold WUP pin High with iX BMS - //digitalWrite(WUP_PIN, HIGH); // Wake up the battery // Not needed - can hold WUP pin High with iX BMS - - //Send SME Keep alive values 100ms - transmit_can(&BMWiX_510, can_config.battery); - //Send SME Keep alive values 200ms - BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 - transmit_can(&BMWiX_0C0, can_config.battery); - - //Send SME Keep alive values 1000ms - //Not needed transmit_can(&BMWiX_06D, can_config.battery); - //Not needed transmit_can(&BMWiX_2F1, can_config.battery); - //Not needed transmit_can(&BMWiX_439, can_config.battery); } #endif From 8b14078b5222252a027ff7f8ef52356c05d0cd78 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:25:49 +0000 Subject: [PATCH 29/48] Cleaner update of detected cell count --- Software/src/battery/BMW-IX-BATTERY.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 33556d6c..a04cb093 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -373,6 +373,7 @@ static uint8_t pyro_status_pss1 = 0; //Using AC 93 static uint8_t pyro_status_pss4 = 0; //Using AC 93 static uint8_t pyro_status_pss6 = 0; //Using AC 93 static uint8_t uds_req_id_counter = 0; +static uint8_t detected_number_of_cells = 108; const unsigned long STALE_PERIOD = STALE_PERIOD_CONFIG; // Time in milliseconds to check for staleness (e.g., 5000 ms = 5 seconds) @@ -479,7 +480,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.info.min_design_voltage_dV = min_design_voltage; - datalayer.battery.info.number_of_cells = 108; //init with 108S before autodetection + datalayer.battery.info.number_of_cells = detected_number_of_cells; datalayer_extended.bmwix.min_cell_voltage_data_age = (millis() - min_cell_voltage_lastchanged); @@ -581,10 +582,10 @@ void receive_can_battery(CAN_frame rx_frame) { int num_voltages; if (rx_frame.data.u8[12] == 0xFF && rx_frame.data.u8[13] == 0xFF) { //97th cell is blank - assume 96S Battery num_voltages = 5; // number of voltage readings to get - 6 more to get on 96S - datalayer.battery.info.number_of_cells = 96; + detected_number_of_cells = 96; } else { //We have data in 97th cell, assume 108S Battery num_voltages = 17; // number of voltage readings to get - 17 more to get on 108S - datalayer.battery.info.number_of_cells = 108; + detected_number_of_cells = 108; } for (int i = start_index; i < (start_index + num_voltages * 2); i += 2) { From 710a7339d881c28498fe0adc8ad09336c78ea6cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 8 Nov 2024 22:56:53 +0200 Subject: [PATCH 30/48] Add charge/discharge current to datalayer --- Software/Software.ino | 22 +++++++- Software/src/datalayer/datalayer.h | 8 ++- Software/src/devboard/safety/safety.cpp | 8 +++ Software/src/devboard/webserver/webserver.cpp | 8 +++ Software/src/inverter/AFORE-CAN.cpp | 33 ++--------- Software/src/inverter/BYD-CAN.cpp | 36 ++---------- Software/src/inverter/BYD-SMA.cpp | 35 ++---------- Software/src/inverter/FOXESS-CAN.cpp | 56 ++----------------- Software/src/inverter/PYLON-CAN.cpp | 54 ++++++------------ Software/src/inverter/PYLON-LV-CAN.cpp | 28 ++++------ Software/src/inverter/SMA-CAN.cpp | 33 ++--------- Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 33 ++--------- Software/src/inverter/SOFAR-CAN.cpp | 8 +-- Software/src/inverter/SOLAX-CAN.cpp | 54 ++---------------- 14 files changed, 104 insertions(+), 312 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 588f28cf..adc771e1 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -293,7 +293,7 @@ void core_loop(void* task_time_us) { #ifdef DOUBLE_BATTERY update_values_battery2(); #endif - update_scaled_values(); // Check if real or calculated SOC% value should be sent + update_calculated_values(); #ifndef SERIAL_LINK_RECEIVER update_machineryprotection(); // Check safeties (Not on serial link reciever board) #endif @@ -837,7 +837,23 @@ void handle_contactors() { #endif // CONTACTOR_CONTROL } -void update_scaled_values() { +void update_calculated_values() { + /* Calculate allowed charge/discharge currents*/ + if (datalayer.battery.status.voltage_dV > 10) { + // Only update value when we have voltage available to avoid div0. TODO: This should be based on nominal voltage + datalayer.battery.status.max_charge_current_dA = + ((datalayer.battery.status.max_charge_power_W * 100) / datalayer.battery.status.voltage_dV); + datalayer.battery.status.max_discharge_current_dA = + ((datalayer.battery.status.max_discharge_power_W * 100) / datalayer.battery.status.voltage_dV); + } + /* Restrict values from user settings if needed*/ + if (datalayer.battery.status.max_charge_current_dA > datalayer.battery.info.max_charge_amp_dA) { + datalayer.battery.status.max_charge_current_dA = datalayer.battery.info.max_charge_amp_dA; + } + if (datalayer.battery.status.max_discharge_current_dA > datalayer.battery.info.max_discharge_amp_dA) { + datalayer.battery.status.max_discharge_current_dA = datalayer.battery.info.max_discharge_amp_dA; + } + if (datalayer.battery.settings.soc_scaling_active) { /** SOC Scaling * @@ -896,7 +912,7 @@ void update_scaled_values() { } #endif - } else { // No SOC window wanted. Set scaled to same as real. + } else { // soc_scaling_active == false. No SOC window wanted. Set scaled to same as real. datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc; datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh; #ifdef DOUBLE_BATTERY diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index d0b6e840..b4967f4b 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -49,10 +49,14 @@ typedef struct { */ uint32_t reported_remaining_capacity_Wh; - /** Maximum allowed battery discharge power in Watts */ + /** Maximum allowed battery discharge power in Watts. Set by battery */ uint32_t max_discharge_power_W = 0; - /** Maximum allowed battery charge power in Watts */ + /** Maximum allowed battery charge power in Watts. Set by battery */ uint32_t max_charge_power_W = 0; + /** Maximum allowed battery discharge current in dA. Calculated based on allowed W and Voltage */ + uint16_t max_discharge_current_dA = 0; + /** Maximum allowed battery charge current in dA. Calculated based on allowed W and Voltage */ + uint16_t max_charge_current_dA = 0; /** int16_t */ /** Maximum temperature currently measured in the pack, in d°C. 150 = 15.0 °C */ diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp index f2023f41..ee72af88 100644 --- a/Software/src/devboard/safety/safety.cpp +++ b/Software/src/devboard/safety/safety.cpp @@ -229,6 +229,14 @@ void update_machineryprotection() { } #endif // DOUBLE_BATTERY + + //Safeties verified, Zero charge/discharge ampere values incase any safety wrote the W to 0 + if (datalayer.battery.status.max_discharge_power_W == 0) { + datalayer.battery.status.max_discharge_current_dA = 0; + } + if (datalayer.battery.status.max_charge_power_W == 0) { + datalayer.battery.status.max_charge_current_dA = 0; + } } //battery pause status begin diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index d42bac4b..4a1554f3 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -652,6 +652,10 @@ String processor(const String& var) { float powerFloat = static_cast(datalayer.battery.status.active_power_W); // Convert to float float tempMaxFloat = static_cast(datalayer.battery.status.temperature_max_dC) / 10.0; // Convert to float float tempMinFloat = static_cast(datalayer.battery.status.temperature_min_dC) / 10.0; // Convert to float + float maxCurrentChargeFloat = + static_cast(datalayer.battery.status.max_charge_current_dA) / 10.0; // Convert to float + float maxCurrentDischargeFloat = + static_cast(datalayer.battery.status.max_discharge_current_dA) / 10.0; // Convert to float uint16_t cell_delta_mv = datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV; @@ -669,9 +673,13 @@ String processor(const String& var) { if (emulator_pause_status == NORMAL) { content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1); content += formatPowerValue("Max charge power", datalayer.battery.status.max_charge_power_W, "", 1); + content += "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A

"; + content += "

Max charge current: " + String(maxCurrentChargeFloat, 1) + " A

"; } else { content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1, "red"); content += formatPowerValue("Max charge power", datalayer.battery.status.max_charge_power_W, "", 1, "red"); + content += "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A

"; + content += "

Max charge current: " + String(maxCurrentChargeFloat, 1) + " A

"; } content += "

Cell max: " + String(datalayer.battery.status.cell_max_voltage_mV) + " mV

"; diff --git a/Software/src/inverter/AFORE-CAN.cpp b/Software/src/inverter/AFORE-CAN.cpp index 6ac88873..74435116 100644 --- a/Software/src/inverter/AFORE-CAN.cpp +++ b/Software/src/inverter/AFORE-CAN.cpp @@ -72,31 +72,10 @@ CAN_frame AFORE_35A = {.FD = false, .DLC = 8, .ID = 0x35A, .data = {0x65, 0x6D, 0x75, 0x6C, 0x61, 0x74, 0x6F, 0x72}}; // Emulator -static int16_t max_charge_current_dA = 0; -static int16_t max_discharge_current_dA = 0; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages //There are more mappings that could be added, but this should be enough to use as a starting point - // Note we map both 0 and 1 messages - if (datalayer.battery.status.voltage_dV > 10) { //div0 safeguard - max_charge_current_dA = (datalayer.battery.status.max_charge_power_W * 100) / datalayer.battery.status.voltage_dV; - if (max_charge_current_dA > datalayer.battery.info.max_charge_amp_dA) { - max_charge_current_dA = - datalayer.battery.info - .max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - max_discharge_current_dA = - (datalayer.battery.status.max_discharge_power_W * 100) / datalayer.battery.status.voltage_dV; - if (max_discharge_current_dA > datalayer.battery.info.max_discharge_amp_dA) { - max_discharge_current_dA = - datalayer.battery.info - .max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - } else { - max_charge_current_dA = 0; - max_discharge_current_dA = 0; - } /*0x350 Operation Information*/ AFORE_350.data.u8[0] = (datalayer.battery.status.voltage_dV & 0x00FF); AFORE_350.data.u8[1] = (datalayer.battery.status.voltage_dV >> 8); @@ -115,11 +94,11 @@ void update_values_can_inverter() { //This function maps all the values fetched AFORE_351.data.u8[2] = SOCMAX; AFORE_351.data.u8[3] = SOCMIN; AFORE_351.data.u8[4] = 0x03; //Bit0 and Bit1 set - if ((max_charge_current_dA == 0) || (datalayer.battery.status.reported_soc == 10000) || + if ((datalayer.battery.status.max_charge_current_dA == 0) || (datalayer.battery.status.reported_soc == 10000) || (datalayer.battery.status.bms_status == FAULT)) { AFORE_351.data.u8[4] &= ~0x01; // Remove Bit0 (clear) Charge enable flag } - if ((max_discharge_current_dA == 0) || (datalayer.battery.status.reported_soc == 0) || + if ((datalayer.battery.status.max_discharge_current_dA == 0) || (datalayer.battery.status.reported_soc == 0) || (datalayer.battery.status.bms_status == FAULT)) { AFORE_351.data.u8[4] &= ~0x02; // Remove Bit1 (clear) Discharge enable flag } @@ -135,10 +114,10 @@ void update_values_can_inverter() { //This function maps all the values fetched AFORE_351.data.u8[7] = (datalayer.battery.info.number_of_cells >> 8); /*0x352 - Protection parameters*/ - AFORE_352.data.u8[0] = (max_charge_current_dA & 0x00FF); - AFORE_352.data.u8[1] = (max_charge_current_dA >> 8); - AFORE_352.data.u8[2] = (max_discharge_current_dA & 0x00FF); - AFORE_352.data.u8[3] = (max_discharge_current_dA >> 8); + AFORE_352.data.u8[0] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); + AFORE_352.data.u8[1] = (datalayer.battery.status.max_charge_current_dA >> 8); + AFORE_352.data.u8[2] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); + AFORE_352.data.u8[3] = (datalayer.battery.status.max_discharge_current_dA >> 8); AFORE_352.data.u8[4] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); AFORE_352.data.u8[5] = (datalayer.battery.info.max_design_voltage_dV >> 8); AFORE_352.data.u8[6] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 82527469..757547ec 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -79,8 +79,6 @@ CAN_frame BYD_210 = {.FD = false, .ID = 0x210, .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -static uint16_t discharge_current = 0; -static uint16_t charge_current = 0; static int16_t temperature_average = 0; static uint16_t inverter_voltage = 0; static uint16_t inverter_SOC = 0; @@ -91,32 +89,6 @@ static bool initialDataSent = 0; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages - /* Calculate allowed charge/discharge currents*/ - if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0 - charge_current = - ((datalayer.battery.status.max_charge_power_W * 10) / - datalayer.battery.status.voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) - //The above calculation results in (30 000*10)/3700=81A - charge_current = (charge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - - discharge_current = - ((datalayer.battery.status.max_discharge_power_W * 10) / - datalayer.battery.status.voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) - //The above calculation results in (30 000*10)/3700=81A - discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - } - /* Restrict values from user settings if needed*/ - if (charge_current > datalayer.battery.info.max_charge_amp_dA) { - charge_current = - datalayer.battery.info - .max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - if (discharge_current > datalayer.battery.info.max_discharge_amp_dA) { - discharge_current = - datalayer.battery.info - .max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - /* Calculate temperature */ temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); @@ -137,11 +109,11 @@ void update_values_can_inverter() { //This function maps all the values fetched BYD_110.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); BYD_110.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); //Maximum discharge power allowed (Unit: A+1) - BYD_110.data.u8[4] = (discharge_current >> 8); - BYD_110.data.u8[5] = (discharge_current & 0x00FF); + BYD_110.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); + BYD_110.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); //Maximum charge power allowed (Unit: A+1) - BYD_110.data.u8[6] = (charge_current >> 8); - BYD_110.data.u8[7] = (charge_current & 0x00FF); + BYD_110.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); + BYD_110.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); //SOC (100.00%) BYD_150.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); diff --git a/Software/src/inverter/BYD-SMA.cpp b/Software/src/inverter/BYD-SMA.cpp index 162cfb3a..230b61e7 100644 --- a/Software/src/inverter/BYD-SMA.cpp +++ b/Software/src/inverter/BYD-SMA.cpp @@ -80,30 +80,6 @@ static uint16_t ampere_hours_remaining = 0; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages //Calculate values - - if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0 - discharge_current = - ((datalayer.battery.status.max_discharge_power_W * 10) / - datalayer.battery.status.voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) - discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - charge_current = - ((datalayer.battery.status.max_charge_power_W * 10) / - datalayer.battery.status.voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) - charge_current = (charge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - } - - if (charge_current > datalayer.battery.info.max_charge_amp_dA) { - charge_current = - datalayer.battery.info - .max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - - if (discharge_current > datalayer.battery.info.max_discharge_amp_dA) { - discharge_current = - datalayer.battery.info - .max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); @@ -118,15 +94,14 @@ void update_values_can_inverter() { //This function maps all the values fetched SMA_358.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); SMA_358.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); //Minvoltage (eg 300.0V = 3000 , 16bits long) - SMA_358.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> - 8); //Minvoltage behaves strange on SMA, cuts out at 56% of the set value? + SMA_358.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); SMA_358.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); //Discharge limited current, 500 = 50A, (0.1, A) - SMA_358.data.u8[4] = (discharge_current >> 8); - SMA_358.data.u8[5] = (discharge_current & 0x00FF); + SMA_358.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); + SMA_358.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); //Charge limited current, 125 =12.5A (0.1, A) - SMA_358.data.u8[6] = (charge_current >> 8); - SMA_358.data.u8[7] = (charge_current & 0x00FF); + SMA_358.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); + SMA_358.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); //SOC (100.00%) SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); diff --git a/Software/src/inverter/FOXESS-CAN.cpp b/Software/src/inverter/FOXESS-CAN.cpp index 8b567946..3909bbbe 100644 --- a/Software/src/inverter/FOXESS-CAN.cpp +++ b/Software/src/inverter/FOXESS-CAN.cpp @@ -22,8 +22,6 @@ below that you can customize, incase you use a lower voltage battery with this p #define TOTAL_LIFETIME_WH_ACCUMULATED 0 //We dont have this value in the emulator /* Do not change code below unless you are sure what you are doing */ -static uint16_t max_charge_rate_amp = 0; -static uint16_t max_discharge_rate_amp = 0; static int16_t temperature_average = 0; static uint16_t voltage_per_pack = 0; static int16_t current_per_pack = 0; @@ -364,50 +362,6 @@ void update_values_can_inverter() { //This function maps all the CAN values fet temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); - //datalayer.battery.status.max_charge_power_W (30000W max) - if (datalayer.battery.status.reported_soc > 9999) { // 99.99% - // Additional safety incase SOC% is 100, then do not charge battery further - max_charge_rate_amp = 0; - } else { // We can pass on the battery charge rate (in W) to the inverter (that takes A) - if (datalayer.battery.status.max_charge_power_W >= 30000) { - max_charge_rate_amp = 75; // Incase battery can take over 30kW, cap value to 75A - } else { // Calculate the W value into A - if (datalayer.battery.status.voltage_dV > 10) { - max_charge_rate_amp = - datalayer.battery.status.max_charge_power_W / (datalayer.battery.status.voltage_dV * 0.1); // P/U=I - } else { // We avoid dividing by 0 and crashing the board - // If we have no voltage, something has gone wrong, do not allow charging - max_charge_rate_amp = 0; - } - } - } - - //datalayer.battery.status.max_discharge_power_W (30000W max) - if (datalayer.battery.status.reported_soc < 100) { // 1.00% - // Additional safety in case SOC% is below 1, then do not discharge battery further - max_discharge_rate_amp = 0; - } else { // We can pass on the battery discharge rate to the inverter - if (datalayer.battery.status.max_discharge_power_W >= 30000) { - max_discharge_rate_amp = 75; // Incase battery can be charged with over 30kW, cap value to 75A - } else { // Calculate the W value into A - if (datalayer.battery.status.voltage_dV > 10) { - max_discharge_rate_amp = - datalayer.battery.status.max_discharge_power_W / (datalayer.battery.status.voltage_dV * 0.1); // P/U=I - } else { // We avoid dividing by 0 and crashing the board - // If we have no voltage, something has gone wrong, do not allow discharging - max_discharge_rate_amp = 0; - } - } - } - - //Cap the value according to user settings. Some inverters cannot handle large values. - if ((max_charge_rate_amp * 10) > datalayer.battery.info.max_charge_amp_dA) { - max_charge_rate_amp = (datalayer.battery.info.max_charge_amp_dA / 10); - } - if ((max_discharge_rate_amp * 10) > datalayer.battery.info.max_discharge_amp_dA) { - max_discharge_rate_amp = (datalayer.battery.info.max_discharge_amp_dA / 10); - } - if (inverterStillAlive > 0) { inverterStillAlive--; } @@ -424,10 +378,10 @@ void update_values_can_inverter() { //This function maps all the CAN values fet FOXESS_1872.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV >> 8); FOXESS_1872.data.u8[2] = (uint8_t)datalayer.battery.info.min_design_voltage_dV; FOXESS_1872.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV >> 8); - FOXESS_1872.data.u8[4] = (uint8_t)(max_charge_rate_amp * 10); - FOXESS_1872.data.u8[5] = ((max_charge_rate_amp * 10) >> 8); - FOXESS_1872.data.u8[6] = (uint8_t)(max_discharge_rate_amp * 10); - FOXESS_1872.data.u8[7] = ((max_discharge_rate_amp * 10) >> 8); + FOXESS_1872.data.u8[4] = (uint8_t)datalayer.battery.status.max_charge_current_dA; + FOXESS_1872.data.u8[5] = (datalayer.battery.status.max_charge_current_dA >> 8); + FOXESS_1872.data.u8[6] = (uint8_t)datalayer.battery.status.max_discharge_current_dA; + FOXESS_1872.data.u8[7] = (datalayer.battery.status.max_discharge_current_dA >> 8); //BMS_PackData FOXESS_1873.data.u8[0] = (uint8_t)datalayer.battery.status.voltage_dV; // OK @@ -463,7 +417,7 @@ void update_values_can_inverter() { //This function maps all the CAN values fet // 0x1876 b0 bit 0 appears to be 1 when at maxsoc and BMS says charge is not allowed - // when at 0 indicates charge is possible - additional note there is something more to it than this, // it's not as straight forward - needs more testing to find what sets/unsets bit0 of byte0 - if ((max_charge_rate_amp == 0) || (datalayer.battery.status.reported_soc == 10000) || + if ((datalayer.battery.status.max_charge_current_dA == 0) || (datalayer.battery.status.reported_soc == 10000) || (datalayer.battery.status.bms_status == FAULT)) { FOXESS_1876.data.u8[0] = 0x01; } else { //continue using battery diff --git a/Software/src/inverter/PYLON-CAN.cpp b/Software/src/inverter/PYLON-CAN.cpp index 9706f759..2b8e036c 100644 --- a/Software/src/inverter/PYLON-CAN.cpp +++ b/Software/src/inverter/PYLON-CAN.cpp @@ -134,32 +134,10 @@ CAN_frame PYLON_4291 = {.FD = false, .ID = 0x4291, .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -static int16_t max_charge_current = 0; -static int16_t max_discharge_current = 0; - void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages //There are more mappings that could be added, but this should be enough to use as a starting point // Note we map both 0 and 1 messages - if (datalayer.battery.status.voltage_dV > 10) { //div0 safeguard - max_charge_current = (datalayer.battery.status.max_charge_power_W * 100) / datalayer.battery.status.voltage_dV; - if (max_charge_current > datalayer.battery.info.max_charge_amp_dA) { - max_charge_current = - datalayer.battery.info - .max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - max_discharge_current = - (datalayer.battery.status.max_discharge_power_W * 100) / datalayer.battery.status.voltage_dV; - if (max_discharge_current > datalayer.battery.info.max_discharge_amp_dA) { - max_discharge_current = - datalayer.battery.info - .max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - } else { - max_charge_current = 0; - max_discharge_current = 0; - } - //Charge / Discharge allowed PYLON_4280.data.u8[0] = 0; PYLON_4280.data.u8[1] = 0; @@ -253,28 +231,28 @@ void update_values_can_inverter() { //This function maps all the values fetched #ifdef SET_30K_OFFSET //Max ChargeCurrent - PYLON_4220.data.u8[4] = ((max_charge_current + 30000) & 0x00FF); - PYLON_4220.data.u8[5] = ((max_charge_current + 30000) >> 8); - PYLON_4221.data.u8[4] = ((max_charge_current + 30000) & 0x00FF); - PYLON_4221.data.u8[5] = ((max_charge_current + 30000) >> 8); + PYLON_4220.data.u8[4] = ((datalayer.battery.status.max_charge_current_dA + 30000) & 0x00FF); + PYLON_4220.data.u8[5] = ((datalayer.battery.status.max_charge_current_dA + 30000) >> 8); + PYLON_4221.data.u8[4] = ((datalayer.battery.status.max_charge_current_dA + 30000) & 0x00FF); + PYLON_4221.data.u8[5] = ((datalayer.battery.status.max_charge_current_dA + 30000) >> 8); //Max DischargeCurrent - PYLON_4220.data.u8[6] = ((30000 - max_discharge_current) & 0x00FF); - PYLON_4220.data.u8[7] = ((30000 - max_discharge_current) >> 8); - PYLON_4221.data.u8[6] = ((30000 - max_discharge_current) & 0x00FF); - PYLON_4221.data.u8[7] = ((30000 - max_discharge_current) >> 8); + PYLON_4220.data.u8[6] = ((30000 - datalayer.battery.status.max_discharge_current_dA) & 0x00FF); + PYLON_4220.data.u8[7] = ((30000 - datalayer.battery.status.max_discharge_current_dA) >> 8); + PYLON_4221.data.u8[6] = ((30000 - datalayer.battery.status.max_discharge_current_dA) & 0x00FF); + PYLON_4221.data.u8[7] = ((30000 - datalayer.battery.status.max_discharge_current_dA) >> 8); #else //Max ChargeCurrent - PYLON_4220.data.u8[4] = (max_charge_current & 0x00FF); - PYLON_4220.data.u8[5] = (max_charge_current >> 8); - PYLON_4221.data.u8[4] = (max_charge_current & 0x00FF); - PYLON_4221.data.u8[5] = (max_charge_current >> 8); + PYLON_4220.data.u8[4] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); + PYLON_4220.data.u8[5] = (datalayer.battery.status.max_charge_current_dA >> 8); + PYLON_4221.data.u8[4] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); + PYLON_4221.data.u8[5] = (datalayer.battery.status.max_charge_current_dA >> 8); //Max DishargeCurrent - PYLON_4220.data.u8[6] = (max_discharge_current & 0x00FF); - PYLON_4220.data.u8[7] = (max_discharge_current >> 8); - PYLON_4221.data.u8[6] = (max_discharge_current & 0x00FF); - PYLON_4221.data.u8[7] = (max_discharge_current >> 8); + PYLON_4220.data.u8[6] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); + PYLON_4220.data.u8[7] = (datalayer.battery.status.max_discharge_current_dA >> 8); + PYLON_4221.data.u8[6] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); + PYLON_4221.data.u8[7] = (datalayer.battery.status.max_discharge_current_dA >> 8); #endif //Max cell voltage diff --git a/Software/src/inverter/PYLON-LV-CAN.cpp b/Software/src/inverter/PYLON-LV-CAN.cpp index d169146e..458ac7a0 100644 --- a/Software/src/inverter/PYLON-LV-CAN.cpp +++ b/Software/src/inverter/PYLON-LV-CAN.cpp @@ -42,20 +42,13 @@ CAN_frame PYLON_35E = {.FD = false, void update_values_can_inverter() { // This function maps all the values fetched from battery CAN to the correct CAN messages - // do not update values unless we have some voltage, as we will run into IntegerDivideByZero exceptions otherwise - if (datalayer.battery.status.voltage_dV == 0) - return; - // TODO: officially this value is "battery charge voltage". Do we need to add something here to the actual voltage? PYLON_351.data.u8[0] = datalayer.battery.status.voltage_dV & 0xff; PYLON_351.data.u8[1] = datalayer.battery.status.voltage_dV >> 8; - int16_t maxChargeCurrent = datalayer.battery.status.max_charge_power_W * 100 / datalayer.battery.status.voltage_dV; - PYLON_351.data.u8[2] = maxChargeCurrent & 0xff; - PYLON_351.data.u8[3] = maxChargeCurrent >> 8; - int16_t maxDischargeCurrent = - datalayer.battery.status.max_discharge_power_W * 100 / datalayer.battery.status.voltage_dV; - PYLON_351.data.u8[4] = maxDischargeCurrent & 0xff; - PYLON_351.data.u8[5] = maxDischargeCurrent >> 8; + PYLON_351.data.u8[2] = datalayer.battery.status.max_charge_current_dA & 0xff; + PYLON_351.data.u8[3] = datalayer.battery.status.max_charge_current_dA >> 8; + PYLON_351.data.u8[4] = datalayer.battery.status.max_discharge_current_dA & 0xff; + PYLON_351.data.u8[5] = datalayer.battery.status.max_discharge_current_dA >> 8; PYLON_355.data.u8[0] = (datalayer.battery.status.reported_soc / 10) & 0xff; PYLON_355.data.u8[1] = (datalayer.battery.status.reported_soc / 10) >> 8; @@ -75,11 +68,11 @@ void update_values_can_inverter() { PYLON_359.data.u8[2] = 0x00; PYLON_359.data.u8[3] = 0x00; PYLON_359.data.u8[4] = PACK_NUMBER; - PYLON_359.data.u8[5] = 'P'; - PYLON_359.data.u8[6] = 'N'; + PYLON_359.data.u8[5] = 0x50; //P + PYLON_359.data.u8[6] = 0x4E; //N // ERRORS - if (datalayer.battery.status.current_dA >= maxDischargeCurrent) + if (datalayer.battery.status.current_dA >= (datalayer.battery.status.max_discharge_current_dA + 10)) PYLON_359.data.u8[0] |= 0x80; if (datalayer.battery.status.temperature_min_dC <= BATTERY_MINTEMPERATURE) PYLON_359.data.u8[0] |= 0x10; @@ -88,11 +81,11 @@ void update_values_can_inverter() { if (datalayer.battery.status.voltage_dV * 100 <= datalayer.battery.info.min_cell_voltage_mV) PYLON_359.data.u8[0] |= 0x04; // we never set PYLON_359.data.u8[1] |= 0x80 called "BMS internal" - if (datalayer.battery.status.current_dA <= -1 * maxChargeCurrent) + if (datalayer.battery.status.current_dA <= -1 * datalayer.battery.status.max_charge_current_dA) PYLON_359.data.u8[1] |= 0x01; // WARNINGS (using same rules as errors but reporting earlier) - if (datalayer.battery.status.current_dA >= maxDischargeCurrent * WARNINGS_PERCENT / 100) + if (datalayer.battery.status.current_dA >= datalayer.battery.status.max_discharge_current_dA * WARNINGS_PERCENT / 100) PYLON_359.data.u8[2] |= 0x80; if (datalayer.battery.status.temperature_min_dC <= BATTERY_MINTEMPERATURE * WARNINGS_PERCENT / 100) PYLON_359.data.u8[2] |= 0x10; @@ -101,7 +94,8 @@ void update_values_can_inverter() { if (datalayer.battery.status.voltage_dV * 100 <= datalayer.battery.info.min_cell_voltage_mV + 100) PYLON_359.data.u8[2] |= 0x04; // we never set PYLON_359.data.u8[3] |= 0x80 called "BMS internal" - if (datalayer.battery.status.current_dA <= -1 * maxChargeCurrent * WARNINGS_PERCENT / 100) + if (datalayer.battery.status.current_dA <= + -1 * datalayer.battery.status.max_charge_current_dA * WARNINGS_PERCENT / 100) PYLON_359.data.u8[3] |= 0x01; PYLON_35C.data.u8[0] = 0xC0; // enable charging and discharging diff --git a/Software/src/inverter/SMA-CAN.cpp b/Software/src/inverter/SMA-CAN.cpp index 4fabbd16..cecae60c 100644 --- a/Software/src/inverter/SMA-CAN.cpp +++ b/Software/src/inverter/SMA-CAN.cpp @@ -70,37 +70,12 @@ CAN_frame SMA_158 = {.FD = false, .ID = 0x158, .data = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA}}; -static int16_t discharge_current = 0; -static int16_t charge_current = 0; static int16_t temperature_average = 0; static uint16_t ampere_hours_remaining = 0; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages //Calculate values - if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0 - discharge_current = - ((datalayer.battery.status.max_discharge_power_W * 10) / - datalayer.battery.status.voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) - discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - charge_current = - ((datalayer.battery.status.max_charge_power_W * 10) / - datalayer.battery.status.voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) - charge_current = (charge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - } - - if (charge_current > datalayer.battery.info.max_charge_amp_dA) { - charge_current = - datalayer.battery.info - .max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - - if (discharge_current > datalayer.battery.info.max_discharge_amp_dA) { - discharge_current = - datalayer.battery.info - .max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); @@ -119,11 +94,11 @@ void update_values_can_inverter() { //This function maps all the values fetched 8); //Minvoltage behaves strange on SMA, cuts out at 56% of the set value? SMA_358.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); //Discharge limited current, 500 = 50A, (0.1, A) - SMA_358.data.u8[4] = (discharge_current >> 8); - SMA_358.data.u8[5] = (discharge_current & 0x00FF); + SMA_358.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); + SMA_358.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); //Charge limited current, 125 =12.5A (0.1, A) - SMA_358.data.u8[6] = (charge_current >> 8); - SMA_358.data.u8[7] = (charge_current & 0x00FF); + SMA_358.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); + SMA_358.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); //SOC (100.00%) SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 0cf0e0b7..9c0cc279 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -81,8 +81,6 @@ CAN_frame SMA_018 = {.FD = false, .ID = 0x018, .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -static uint16_t discharge_current = 0; -static uint16_t charge_current = 0; static int16_t temperature_average = 0; static uint16_t ampere_hours_remaining = 0; static uint16_t ampere_hours_max = 0; @@ -123,29 +121,6 @@ InvInitState invInitState = SYSTEM_FREQUENCY; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the inverter CAN //Calculate values - if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0 - charge_current = - ((datalayer.battery.status.max_charge_power_W * 10) / - datalayer.battery.status.voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) - charge_current = (charge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - discharge_current = - ((datalayer.battery.status.max_discharge_power_W * 10) / - datalayer.battery.status.voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) - discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - } - - if (charge_current > datalayer.battery.info.max_charge_amp_dA) { - charge_current = - datalayer.battery.info - .max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - - if (discharge_current > datalayer.battery.info.max_discharge_amp_dA) { - discharge_current = - datalayer.battery.info - .max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values. - } - temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); @@ -167,11 +142,11 @@ void update_values_can_inverter() { //This function maps all the values fetched SMA_00D.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); SMA_00D.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); //Discharge limited current, 500 = 50A, (0.1, A) - SMA_00D.data.u8[4] = (discharge_current >> 8); - SMA_00D.data.u8[5] = (discharge_current & 0x00FF); + SMA_00D.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); + SMA_00D.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); //Charge limited current, 125 =12.5A (0.1, A) - SMA_00D.data.u8[6] = (charge_current >> 8); - SMA_00D.data.u8[7] = (charge_current & 0x00FF); + SMA_00D.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); + SMA_00D.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); // Battery State //SOC (100.00%) diff --git a/Software/src/inverter/SOFAR-CAN.cpp b/Software/src/inverter/SOFAR-CAN.cpp index 628db1a3..eb13b7c5 100644 --- a/Software/src/inverter/SOFAR-CAN.cpp +++ b/Software/src/inverter/SOFAR-CAN.cpp @@ -207,10 +207,10 @@ void update_values_can_inverter() { //This function maps all the values fetched //Maxvoltage (eg 400.0V = 4000 , 16bits long) Charge Cutoff Voltage SOFAR_351.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); SOFAR_351.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); - //SOFAR_351.data.u8[2] = DC charge current limitation (Default 25.0A) - //SOFAR_351.data.u8[3] = DC charge current limitation - //SOFAR_351.data.u8[4] = DC discharge current limitation (Default 25.0A) - //SOFAR_351.data.u8[5] = DC discharge current limitation + SOFAR_351.data.u8[2] = (datalayer.battery.status.max_charge_current_dA >> 8); + SOFAR_351.data.u8[3] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); + SOFAR_351.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); + SOFAR_351.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); //Minvoltage (eg 300.0V = 3000 , 16bits long) Discharge Cutoff Voltage SOFAR_351.data.u8[6] = (datalayer.battery.info.min_design_voltage_dV >> 8); SOFAR_351.data.u8[7] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp index 32c6207b..790c8524 100644 --- a/Software/src/inverter/SOLAX-CAN.cpp +++ b/Software/src/inverter/SOLAX-CAN.cpp @@ -10,8 +10,6 @@ // https://github.com/dalathegreat/Battery-Emulator/wiki/Solax-inverters /* Do not change code below unless you are sure what you are doing */ -static uint16_t max_charge_rate_amp = 0; -static uint16_t max_discharge_rate_amp = 0; static int16_t temperature_average = 0; static uint8_t STATE = BATTERY_ANNOUNCE; static unsigned long LastFrameTime = 0; @@ -93,50 +91,6 @@ void update_values_can_inverter() { //This function maps all the values fetched temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); - //datalayer.battery.status.max_charge_power_W (30000W max) - if (datalayer.battery.status.reported_soc > 9999) { // 99.99% - // Additional safety incase SOC% is 100, then do not charge battery further - max_charge_rate_amp = 0; - } else { // We can pass on the battery charge rate (in W) to the inverter (that takes A) - if (datalayer.battery.status.max_charge_power_W >= 30000) { - max_charge_rate_amp = 75; // Incase battery can take over 30kW, cap value to 75A - } else { // Calculate the W value into A - if (datalayer.battery.status.voltage_dV > 10) { - max_charge_rate_amp = - datalayer.battery.status.max_charge_power_W / (datalayer.battery.status.voltage_dV * 0.1); // P/U=I - } else { // We avoid dividing by 0 and crashing the board - // If we have no voltage, something has gone wrong, do not allow charging - max_charge_rate_amp = 0; - } - } - } - - //datalayer.battery.status.max_discharge_power_W (30000W max) - if (datalayer.battery.status.reported_soc < 100) { // 1.00% - // Additional safety in case SOC% is below 1, then do not discharge battery further - max_discharge_rate_amp = 0; - } else { // We can pass on the battery discharge rate to the inverter - if (datalayer.battery.status.max_discharge_power_W >= 30000) { - max_discharge_rate_amp = 75; // Incase battery can be charged with over 30kW, cap value to 75A - } else { // Calculate the W value into A - if (datalayer.battery.status.voltage_dV > 10) { - max_discharge_rate_amp = - datalayer.battery.status.max_discharge_power_W / (datalayer.battery.status.voltage_dV * 0.1); // P/U=I - } else { // We avoid dividing by 0 and crashing the board - // If we have no voltage, something has gone wrong, do not allow discharging - max_discharge_rate_amp = 0; - } - } - } - - //Cap the value according to user settings. Some inverters cannot handle large values. - if ((max_charge_rate_amp * 10) > datalayer.battery.info.max_charge_amp_dA) { - max_charge_rate_amp = (datalayer.battery.info.max_charge_amp_dA / 10); - } - if ((max_discharge_rate_amp * 10) > datalayer.battery.info.max_discharge_amp_dA) { - max_discharge_rate_amp = (datalayer.battery.info.max_discharge_amp_dA / 10); - } - // Batteries might be larger than uint16_t value can take if (datalayer.battery.info.total_capacity_Wh > 65000) { capped_capacity_Wh = 65000; @@ -156,10 +110,10 @@ void update_values_can_inverter() { //This function maps all the values fetched SOLAX_1872.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV >> 8); SOLAX_1872.data.u8[2] = (uint8_t)datalayer.battery.info.min_design_voltage_dV; SOLAX_1872.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV >> 8); - SOLAX_1872.data.u8[4] = (uint8_t)(max_charge_rate_amp * 10); - SOLAX_1872.data.u8[5] = ((max_charge_rate_amp * 10) >> 8); - SOLAX_1872.data.u8[6] = (uint8_t)(max_discharge_rate_amp * 10); - SOLAX_1872.data.u8[7] = ((max_discharge_rate_amp * 10) >> 8); + SOLAX_1872.data.u8[4] = (uint8_t)datalayer.battery.status.max_charge_current_dA; + SOLAX_1872.data.u8[5] = (datalayer.battery.status.max_charge_current_dA >> 8); + SOLAX_1872.data.u8[6] = (uint8_t)datalayer.battery.status.max_discharge_current_dA; + SOLAX_1872.data.u8[7] = (datalayer.battery.status.max_discharge_current_dA >> 8); //BMS_PackData SOLAX_1873.data.u8[0] = (uint8_t)datalayer.battery.status.voltage_dV; // OK From 91f3c8caf92e2bdbf9fe43d633f3b3d148e14987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 8 Nov 2024 23:37:16 +0200 Subject: [PATCH 31/48] Rename user specified limit in datalayer --- Software/src/datalayer/datalayer.h | 8 ++++---- Software/src/devboard/webserver/settings_html.cpp | 8 ++++---- Software/src/devboard/webserver/webserver.cpp | 6 +++--- Software/src/inverter/BYD-MODBUS.cpp | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index b4967f4b..a26097af 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -19,10 +19,10 @@ typedef struct { uint16_t min_cell_voltage_mV = 2700; /** The maxumum allowed deviation between cells, in milliVolt. 500 = 0.500 V */ uint16_t max_cell_voltage_deviation_mV = 500; - /** BYD CAN specific setting, max charge in deciAmpere. 300 = 30.0 A */ - uint16_t max_charge_amp_dA = BATTERY_MAX_CHARGE_AMP; - /** BYD CAN specific setting, max discharge in deciAmpere. 300 = 30.0 A */ - uint16_t max_discharge_amp_dA = BATTERY_MAX_DISCHARGE_AMP; + /** The user specified maximum allowed charge rate, in deciAmpere. 300 = 30.0 A */ + uint16_t max_user_set_charge_dA = BATTERY_MAX_CHARGE_AMP; + /** The user specified maximum allowed discharge rate, in deciAmpere. 300 = 30.0 A */ + uint16_t max_user_set_discharge_dA = BATTERY_MAX_DISCHARGE_AMP; /** uint8_t */ /** Total number of cells in the pack */ diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 8d2d5ec7..5efe2493 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -57,11 +57,11 @@ String settings_processor(const String& var) { content += "

SOC min percentage: " + String(datalayer.battery.settings.min_percentage / 100.0, 1) + "

"; - content += - "

Max charge speed: " + String(datalayer.battery.info.max_charge_amp_dA / 10.0, 1) + - " A

"; + content += "

Max charge speed: " + + String(datalayer.battery.info.max_user_set_charge_dA / 10.0, 1) + + " A

"; content += "

Max discharge speed: " + - String(datalayer.battery.info.max_discharge_amp_dA / 10.0, 1) + + String(datalayer.battery.info.max_user_set_discharge_dA / 10.0, 1) + " A

"; // Close the block content += "
"; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 4a1554f3..244d8846 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -209,7 +209,7 @@ void init_webserver() { return request->requestAuthentication(); if (request->hasParam("value")) { String value = request->getParam("value")->value(); - datalayer.battery.info.max_charge_amp_dA = static_cast(value.toFloat() * 10); + datalayer.battery.info.max_user_set_charge_dA = static_cast(value.toFloat() * 10); storeSettings(); request->send(200, "text/plain", "Updated successfully"); } else { @@ -223,7 +223,7 @@ void init_webserver() { return request->requestAuthentication(); if (request->hasParam("value")) { String value = request->getParam("value")->value(); - datalayer.battery.info.max_discharge_amp_dA = static_cast(value.toFloat() * 10); + datalayer.battery.info.max_user_set_discharge_dA = static_cast(value.toFloat() * 10); storeSettings(); request->send(200, "text/plain", "Updated successfully"); } else { @@ -285,7 +285,7 @@ void init_webserver() { String value = request->getParam("value")->value(); float val = value.toFloat(); - if (!(val <= datalayer.battery.info.max_charge_amp_dA && val <= CHARGER_MAX_A)) { + if (!(val <= datalayer.battery.info.max_user_set_charge_dA && val <= CHARGER_MAX_A)) { request->send(400, "text/plain", "Bad Request"); } diff --git a/Software/src/inverter/BYD-MODBUS.cpp b/Software/src/inverter/BYD-MODBUS.cpp index c37a5139..3522e18b 100644 --- a/Software/src/inverter/BYD-MODBUS.cpp +++ b/Software/src/inverter/BYD-MODBUS.cpp @@ -65,13 +65,13 @@ void handle_update_data_modbusp301_byd() { } // Convert max discharge Amp value to max Watt user_configured_max_discharge_W = - ((datalayer.battery.info.max_discharge_amp_dA * datalayer.battery.info.max_design_voltage_dV) / 100); + ((datalayer.battery.info.max_user_set_discharge_dA * datalayer.battery.info.max_design_voltage_dV) / 100); // Use the smaller value, battery reported value OR user configured value max_discharge_W = std::min(datalayer.battery.status.max_discharge_power_W, user_configured_max_discharge_W); // Convert max charge Amp value to max Watt user_configured_max_charge_W = - ((datalayer.battery.info.max_charge_amp_dA * datalayer.battery.info.max_design_voltage_dV) / 100); + ((datalayer.battery.info.max_user_set_charge_dA * datalayer.battery.info.max_design_voltage_dV) / 100); // Use the smaller value, battery reported value OR user configured value max_charge_W = std::min(datalayer.battery.status.max_charge_power_W, user_configured_max_charge_W); From ae34a9985cc50b0628b2445d7ae9e3ce834d03b4 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sat, 9 Nov 2024 21:03:37 +0000 Subject: [PATCH 32/48] Update BMW-IX-BATTERY.h --- Software/src/battery/BMW-IX-BATTERY.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 72afe6d5..602411af 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -16,7 +16,7 @@ #define MAX_CHARGE_POWER_WHEN_TOPBALANCING_W 500 #define RAMPDOWN_SOC 9000 // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00% #define STALE_PERIOD_CONFIG \ - 180000; //Number of milliseconds before critical values are classed as stale/stuck 180000 = 180 seconds + 210000; //Number of milliseconds before critical values are classed as stale/stuck 210000 = 210 seconds void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); From c3e67d2f62b14ca112e30e5dabb1f99ff77a39e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 10 Nov 2024 11:49:31 +0200 Subject: [PATCH 33/48] Make discharge limits under settings datalayer --- Software/Software.ino | 16 ++++++++-------- Software/src/datalayer/datalayer.h | 8 ++++---- .../src/devboard/webserver/settings_html.cpp | 4 ++-- Software/src/devboard/webserver/webserver.cpp | 6 +++--- Software/src/inverter/BYD-MODBUS.cpp | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index adc771e1..2b45dc5a 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -401,11 +401,11 @@ void init_stored_settings() { } temp = settings.getUInt("MAXCHARGEAMP", false); if (temp != 0) { - datalayer.battery.info.max_charge_amp_dA = temp; + datalayer.battery.settings.max_user_set_charge_dA = temp; } temp = settings.getUInt("MAXDISCHARGEAMP", false); if (temp != 0) { - datalayer.battery.info.max_discharge_amp_dA = temp; + datalayer.battery.settings.max_user_set_discharge_dA = temp; temp = settings.getBool("USE_SCALED_SOC", false); datalayer.battery.settings.soc_scaling_active = temp; //This bool needs to be checked inside the temp!= block } // No way to know if it wasnt reset otherwise @@ -847,11 +847,11 @@ void update_calculated_values() { ((datalayer.battery.status.max_discharge_power_W * 100) / datalayer.battery.status.voltage_dV); } /* Restrict values from user settings if needed*/ - if (datalayer.battery.status.max_charge_current_dA > datalayer.battery.info.max_charge_amp_dA) { - datalayer.battery.status.max_charge_current_dA = datalayer.battery.info.max_charge_amp_dA; + if (datalayer.battery.status.max_charge_current_dA > datalayer.battery.settings.max_user_set_charge_dA) { + datalayer.battery.status.max_charge_current_dA = datalayer.battery.settings.max_user_set_charge_dA; } - if (datalayer.battery.status.max_discharge_current_dA > datalayer.battery.info.max_discharge_amp_dA) { - datalayer.battery.status.max_discharge_current_dA = datalayer.battery.info.max_discharge_amp_dA; + if (datalayer.battery.status.max_discharge_current_dA > datalayer.battery.settings.max_user_set_discharge_dA) { + datalayer.battery.status.max_discharge_current_dA = datalayer.battery.settings.max_user_set_discharge_dA; } if (datalayer.battery.settings.soc_scaling_active) { @@ -991,8 +991,8 @@ void storeSettings() { datalayer.battery.settings.max_percentage / 10); // Divide by 10 for backwards compatibility settings.putUInt("MINPERCENTAGE", datalayer.battery.settings.min_percentage / 10); // Divide by 10 for backwards compatibility - settings.putUInt("MAXCHARGEAMP", datalayer.battery.info.max_charge_amp_dA); - settings.putUInt("MAXDISCHARGEAMP", datalayer.battery.info.max_discharge_amp_dA); + settings.putUInt("MAXCHARGEAMP", datalayer.battery.settings.max_user_set_charge_dA); + settings.putUInt("MAXDISCHARGEAMP", datalayer.battery.settings.max_user_set_discharge_dA); settings.putBool("USE_SCALED_SOC", datalayer.battery.settings.soc_scaling_active); settings.end(); } diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index a26097af..7e1880af 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -19,10 +19,6 @@ typedef struct { uint16_t min_cell_voltage_mV = 2700; /** The maxumum allowed deviation between cells, in milliVolt. 500 = 0.500 V */ uint16_t max_cell_voltage_deviation_mV = 500; - /** The user specified maximum allowed charge rate, in deciAmpere. 300 = 30.0 A */ - uint16_t max_user_set_charge_dA = BATTERY_MAX_CHARGE_AMP; - /** The user specified maximum allowed discharge rate, in deciAmpere. 300 = 30.0 A */ - uint16_t max_user_set_discharge_dA = BATTERY_MAX_DISCHARGE_AMP; /** uint8_t */ /** Total number of cells in the pack */ @@ -111,6 +107,10 @@ typedef struct { * you want the inverter to be able to use. At this real SOC, the inverter * will "see" 100% */ uint16_t max_percentage = BATTERY_MAXPERCENTAGE; + /** The user specified maximum allowed charge rate, in deciAmpere. 300 = 30.0 A */ + uint16_t max_user_set_charge_dA = BATTERY_MAX_CHARGE_AMP; + /** The user specified maximum allowed discharge rate, in deciAmpere. 300 = 30.0 A */ + uint16_t max_user_set_discharge_dA = BATTERY_MAX_DISCHARGE_AMP; } DATALAYER_BATTERY_SETTINGS_TYPE; typedef struct { diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 5efe2493..caac64d4 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -58,10 +58,10 @@ String settings_processor(const String& var) { ";'>SOC min percentage: " + String(datalayer.battery.settings.min_percentage / 100.0, 1) + " "; content += "

Max charge speed: " + - String(datalayer.battery.info.max_user_set_charge_dA / 10.0, 1) + + String(datalayer.battery.settings.max_user_set_charge_dA / 10.0, 1) + " A

"; content += "

Max discharge speed: " + - String(datalayer.battery.info.max_user_set_discharge_dA / 10.0, 1) + + String(datalayer.battery.settings.max_user_set_discharge_dA / 10.0, 1) + " A

"; // Close the block content += "
"; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 244d8846..81d77567 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -209,7 +209,7 @@ void init_webserver() { return request->requestAuthentication(); if (request->hasParam("value")) { String value = request->getParam("value")->value(); - datalayer.battery.info.max_user_set_charge_dA = static_cast(value.toFloat() * 10); + datalayer.battery.settings.max_user_set_charge_dA = static_cast(value.toFloat() * 10); storeSettings(); request->send(200, "text/plain", "Updated successfully"); } else { @@ -223,7 +223,7 @@ void init_webserver() { return request->requestAuthentication(); if (request->hasParam("value")) { String value = request->getParam("value")->value(); - datalayer.battery.info.max_user_set_discharge_dA = static_cast(value.toFloat() * 10); + datalayer.battery.settings.max_user_set_discharge_dA = static_cast(value.toFloat() * 10); storeSettings(); request->send(200, "text/plain", "Updated successfully"); } else { @@ -285,7 +285,7 @@ void init_webserver() { String value = request->getParam("value")->value(); float val = value.toFloat(); - if (!(val <= datalayer.battery.info.max_user_set_charge_dA && val <= CHARGER_MAX_A)) { + if (!(val <= datalayer.battery.settings.max_user_set_charge_dA && val <= CHARGER_MAX_A)) { request->send(400, "text/plain", "Bad Request"); } diff --git a/Software/src/inverter/BYD-MODBUS.cpp b/Software/src/inverter/BYD-MODBUS.cpp index 3522e18b..7cee6b8d 100644 --- a/Software/src/inverter/BYD-MODBUS.cpp +++ b/Software/src/inverter/BYD-MODBUS.cpp @@ -65,13 +65,13 @@ void handle_update_data_modbusp301_byd() { } // Convert max discharge Amp value to max Watt user_configured_max_discharge_W = - ((datalayer.battery.info.max_user_set_discharge_dA * datalayer.battery.info.max_design_voltage_dV) / 100); + ((datalayer.battery.settings.max_user_set_discharge_dA * datalayer.battery.info.max_design_voltage_dV) / 100); // Use the smaller value, battery reported value OR user configured value max_discharge_W = std::min(datalayer.battery.status.max_discharge_power_W, user_configured_max_discharge_W); // Convert max charge Amp value to max Watt user_configured_max_charge_W = - ((datalayer.battery.info.max_user_set_charge_dA * datalayer.battery.info.max_design_voltage_dV) / 100); + ((datalayer.battery.settings.max_user_set_charge_dA * datalayer.battery.info.max_design_voltage_dV) / 100); // Use the smaller value, battery reported value OR user configured value max_charge_W = std::min(datalayer.battery.status.max_charge_power_W, user_configured_max_charge_W); From 5650c991abd592b265805ab1907e2ece2ded09f2 Mon Sep 17 00:00:00 2001 From: wjcloudy <56305354+wjcloudy@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:24:12 +0000 Subject: [PATCH 34/48] Reduce iX stale value sensitivity --- Software/src/battery/BMW-IX-BATTERY.cpp | 2 +- Software/src/battery/BMW-IX-BATTERY.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index a04cb093..2f316097 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -672,7 +672,7 @@ void receive_can_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //This is the most important safety values, if we receive this we reset CAN alive counter. - if ((rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]) == 10000 && + if ((rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]) == 10000 || (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]) == 10000) { //Qualifier Invalid Mode - Request Reboot #ifdef DEBUG_VIA_USB Serial.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 602411af..a5336778 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -16,7 +16,7 @@ #define MAX_CHARGE_POWER_WHEN_TOPBALANCING_W 500 #define RAMPDOWN_SOC 9000 // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00% #define STALE_PERIOD_CONFIG \ - 210000; //Number of milliseconds before critical values are classed as stale/stuck 210000 = 210 seconds + 300000; //Number of milliseconds before critical values are classed as stale/stuck 300000 = 300 seconds void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); From ec00b9be8f0b09cbf60f004dd345e35b0d36541f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 11 Nov 2024 20:26:35 +0200 Subject: [PATCH 35/48] Refactor CAN logging --- Software/Software.ino | 44 ++++++++++++---------- Software/USER_SETTINGS.h | 4 +- Software/src/battery/TEST-FAKE-BATTERY.cpp | 24 ------------ 3 files changed, 26 insertions(+), 46 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 2b45dc5a..c85c376d 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -614,31 +614,32 @@ void init_equipment_stop_button() { #endif -#ifdef CAN_FD -// Functions -#ifdef DEBUG_CANFD_DATA -enum frameDirection { MSG_RX, MSG_TX }; -void print_canfd_frame(CANFDMessage rx_frame, frameDirection msgDir); // Needs to be declared before it is defined -void print_canfd_frame(CANFDMessage rx_frame, frameDirection msgDir) { - int i = 0; - (msgDir == 0) ? Serial.print("RX ") : Serial.print("TX "); - Serial.print(rx_frame.id, HEX); +enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 +void print_can_frame(CAN_frame frame, frameDirection msgDir); +void print_can_frame(CAN_frame frame, frameDirection msgDir) { + uint8_t i = 0; + Serial.print(millis()); Serial.print(" "); - for (i = 0; i < rx_frame.len; i++) { - Serial.print(rx_frame.data[i] < 16 ? "0" : ""); - Serial.print(rx_frame.data[i], HEX); + (msgDir == 0) ? Serial.print("RX ") : Serial.print("TX "); + Serial.print(frame.ID, HEX); + Serial.print(" "); + Serial.print(frame.DLC); + Serial.print(" "); + for (i = 0; i < frame.DLC; i++) { + Serial.print(frame.data.u8[i] < 16 ? "0" : ""); + Serial.print(frame.data.u8[i], HEX); Serial.print(" "); } Serial.println(" "); } -#endif + +#ifdef CAN_FD +// Functions void receive_canfd() { // This section checks if we have a complete CAN-FD message incoming CANFDMessage frame; if (canfd.available()) { canfd.receive(frame); -#ifdef DEBUG_CANFD_DATA - print_canfd_frame(frame, frameDirection(MSG_RX)); -#endif + CAN_frame rx_frame; rx_frame.ID = frame.id; rx_frame.ext_ID = frame.ext; @@ -1078,6 +1079,9 @@ void transmit_can(CAN_frame* tx_frame, int interface) { if (!allowed_to_send_CAN) { return; } +#ifdef DEBUG_CAN_DATA + print_can_frame(*tx_frame, frameDirection(MSG_TX)); +#endif //DEBUG_CAN_DATA switch (interface) { case CAN_NATIVE: @@ -1120,10 +1124,6 @@ void transmit_can(CAN_frame* tx_frame, int interface) { send_ok = canfd.tryToSend(MCP2518Frame); if (!send_ok) { set_event(EVENT_CANFD_BUFFER_FULL, interface); - } else { -#ifdef DEBUG_CANFD_DATA - print_canfd_frame(MCP2518Frame, frameDirection(MSG_TX)); -#endif } #else // Interface not compiled, and settings try to use it set_event(EVENT_INTERFACE_MISSING, interface); @@ -1136,6 +1136,10 @@ void transmit_can(CAN_frame* tx_frame, int interface) { } void receive_can(CAN_frame* rx_frame, int interface) { +#ifdef DEBUG_CAN_DATA + print_can_frame(*rx_frame, frameDirection(MSG_RX)); +#endif //DEBUG_CAN_DATA + if (interface == can_config.battery) { receive_can_battery(*rx_frame); } diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 26272ca7..2f30bf26 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -20,7 +20,7 @@ //#define KIA_E_GMP_BATTERY //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MG_5_BATTERY -//#define NISSAN_LEAF_BATTERY +#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RENAULT_KANGOO_BATTERY @@ -54,7 +54,7 @@ /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -//#define DEBUG_CANFD_DATA //Enable this line to have the USB port output CAN-FD data while program runs (WARNING, raises CPU load, do not use for production) +//#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) //#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting //#define CONTACTOR_CONTROL //Enable this line to have pins 25,32,33 handle automatic precharge/contactor+/contactor- closing sequence //#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index 630fa536..423654aa 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -130,35 +130,11 @@ void update_values_battery2() { // Handle the values coming in from battery #2 void receive_can_battery2(CAN_frame rx_frame) { datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - // All CAN messages recieved will be logged via serial - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); - for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); - } - Serial.println(""); } #endif // DOUBLE_BATTERY void receive_can_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - // All CAN messages recieved will be logged via serial - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); - for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); - } - Serial.println(""); } void send_can_battery() { unsigned long currentMillis = millis(); From 538d7b6ac0013d8220ca543b7fea99a3f324881a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 11 Nov 2024 20:56:40 +0200 Subject: [PATCH 36/48] Remove LEAF --- Software/USER_SETTINGS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 2f30bf26..2f5428c9 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -20,7 +20,7 @@ //#define KIA_E_GMP_BATTERY //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MG_5_BATTERY -#define NISSAN_LEAF_BATTERY +//#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RENAULT_KANGOO_BATTERY From 72c2373cf4680913330ea3dd251618b0927b5cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 12 Nov 2024 00:02:14 +0200 Subject: [PATCH 37/48] Fix inverter missing event for Foxess --- Software/src/inverter/FOXESS-CAN.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Software/src/inverter/FOXESS-CAN.cpp b/Software/src/inverter/FOXESS-CAN.cpp index 3909bbbe..e4b3b34c 100644 --- a/Software/src/inverter/FOXESS-CAN.cpp +++ b/Software/src/inverter/FOXESS-CAN.cpp @@ -28,7 +28,6 @@ static int16_t current_per_pack = 0; static uint8_t temperature_max_per_pack = 0; static uint8_t temperature_min_per_pack = 0; static uint8_t current_pack_info = 0; -static uint8_t inverterStillAlive = 60; // Inverter can be missing for 1minute on startup static bool send_cellvoltages = false; static unsigned long previousMillisCellvoltage = 0; // Store the last time a cellvoltage CAN messages were sent @@ -362,16 +361,6 @@ void update_values_can_inverter() { //This function maps all the CAN values fet temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); - if (inverterStillAlive > 0) { - inverterStillAlive--; - } - - if (!inverterStillAlive) { - set_event(EVENT_CAN_INVERTER_MISSING, 0); - } else { - clear_event(EVENT_CAN_INVERTER_MISSING); - } - //Put the values into the CAN messages //BMS_Limits FOXESS_1872.data.u8[0] = (uint8_t)datalayer.battery.info.max_design_voltage_dV; @@ -686,7 +675,7 @@ void send_can_inverter() { // This function loops as fast as possible void receive_can_inverter(CAN_frame rx_frame) { if (rx_frame.ID == 0x1871) { - inverterStillAlive = CAN_STILL_ALIVE; + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; if (rx_frame.data.u8[0] == 0x03) { //0x1871 [0x03, 0x06, 0x17, 0x05, 0x09, 0x09, 0x28, 0x22] //This message is sent by the inverter every '6' seconds (0.5s after the pack serial numbers) //and contains a timestamp in bytes 2-7 i.e. ,,
,,, From ff496f3d4e5729fbc7f5c6ca16b49c8b2f350a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 13 Nov 2024 12:11:07 +0200 Subject: [PATCH 38/48] Add Range Rover PHEV support --- Software/USER_SETTINGS.h | 1 + Software/src/battery/BATTERIES.h | 4 + .../src/battery/RANGE-ROVER-PHEV-BATTERY.cpp | 329 ++++++++++++++++++ .../src/battery/RANGE-ROVER-PHEV-BATTERY.h | 18 + Software/src/devboard/webserver/webserver.cpp | 3 + 5 files changed, 355 insertions(+) create mode 100644 Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp create mode 100644 Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 2f5428c9..c6351a12 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -23,6 +23,7 @@ //#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS +//#define RANGE_ROVER_PHEV_BATTERY //#define RENAULT_KANGOO_BATTERY //#define RENAULT_TWIZY_BATTERY //#define RENAULT_ZOE_GEN1_BATTERY diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index ecc21ad1..3bc65189 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -58,6 +58,10 @@ #include "RJXZS-BMS.h" #endif +#ifdef RANGE_ROVER_PHEV_BATTERY +#include "RANGE-ROVER-PHEV-BATTERY.h" +#endif + #ifdef RENAULT_KANGOO_BATTERY #include "RENAULT-KANGOO-BATTERY.h" #endif diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp new file mode 100644 index 00000000..d530c2d5 --- /dev/null +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp @@ -0,0 +1,329 @@ +#include "../include.h" +#ifdef RANGE_ROVER_PHEV_BATTERY +#include "../datalayer/datalayer.h" +#include "../devboard/utils/events.h" +#include "RANGE-ROVER-PHEV-BATTERY.h" + +/* TODO +- LOG files from vehicle needed to determine CAN content needed to send towards battery! + - BCCM_PMZ_A (0x18B 50ms) + - BCCMB_PMZ_A (0x224 90ms) + - BCM_CCP_RX_PMZCAN (0x601 non cyclic) + - EPIC_PMZ_B (0x009 non cyclic) + - GWM_FuelPumpEnableDataControl_PMZ (0x1F8 non cyclic) + - GWM_IgnitionAuthDataTarget_PMZ (0x004 non cyclic) + - GWM_PMZ_A (0x008 10ms cyclic) + - GWM_PMZ_B -F, G-I, Immo, K-P + - 0x010 10ms + - 0x090 10ms + - 0x108 20ms + - 0x110 20ms + - 0x1d0 80ms + - 0x490 900ms + - 0x1B0 80ms + - 0x460 720ms + - 0x006 non cyclic immo + - 0x450 600ms + - 0x2b8 180ms + - 0x388 200ms + - 0x2b0 180ms + - 0x380 80ms + - GWM_PMZ_V_HYBRID (0x18d 60ms) + - HVAC_PMZ_A-E + - 0x1a8 70ms + - 0x210 100ms + - 0x300 200ms + - 0x440 180ms + - 0x0c0 10ms + - PCM_PMZ_C_Hybrid C, D, H, M + - 0x030 15ms + - 0x304 180ms + - 0x1C0 80ms + - 0x434 350ms + - TCU_PMZ_A + - 0x014 non cyclic, command from TCU, most likely not needed +- Determine CRC calculation +- Figure out contactor closing requirements +*/ + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis50ms = 0; // will store last time a 50ms CAN Message was sent + +//CAN content from battery +static bool StatusCAT5BPOChg = false; +static bool StatusCAT4Derate = false; +static uint8_t OCMonitorStatus = 0; +static bool StatusCAT3 = false; +static bool IsolationStatus = false; +static bool HVILStatus = false; +static bool ContactorStatus = false; +static uint8_t StatusGpCounter = 0; +static bool WeldCheckStatus = false; +static bool StatusCAT7NowBPO = false; +static bool StatusCAT6DlyBPO = false; +static uint8_t StatusGpCS = 0; +static uint8_t CAT6Count = 0; +static bool EndOfCharge = false; +static bool DerateWarning = false; +static bool PrechargeAllowed = false; +static uint8_t DischargeExtGpCounter = 0; // Counter 0-15 +static uint8_t DischargeExtGpCS = 0; // CRC +static uint16_t DischargeVoltageLimit = 0; //Min voltage battery allows discharging to +static uint16_t DischargePowerLimitExt = 0; //Momentary Discharge power limit kW*0.01 (0-655) +static uint16_t DischargeContPwrLmt = 0; //Longterm Discharge power limit kW*0.01 (0-655) +static uint8_t PwrGpCS = 0; // CRC +static uint8_t PwrGpCounter = 0; // Counter 0-15 +static uint16_t VoltageExt = 370; // Voltage of the HV Battery +static uint16_t VoltageBus = 0; // Voltage on the high-voltage DC bus +static int32_t CurrentExt = + 209715; //Positive - discharge, Negative Charge (0 - 16777215) Scaling: 0.025 Offset: -209715.175 Units: Amps +static bool HVIsolationTestRunning = false; +static uint16_t VoltageOC = + 0; //The instantaneous equivalent open-circuit voltage of the high voltage battery. This is used by the high-voltage inverter in power prediction and derating calculations. +static uint16_t DchCurrentLimit = + 0; // A, 'Maximum current that can be delivered by the HV Battery during motoring mode i.e during discharging. +static uint16_t ChgCurrentLimit = + 0; // - 1023 A, Maximum current that can be transferred into the HV Battery during generating mode i.e during charging. Charging is neagtive and discharging is positive. +static uint16_t ChargeContPwrLmt = 0; //Longterm charge power limit kW*0.01 (0-655) +static uint16_t ChargePowerLimitExt = 0; //Momentary Charge power limit kW*0.01 (0-655) +static uint8_t ChgExtGpCS = 0; // CRC +static uint8_t ChgExtGpCounter = 0; //counter 0-15 +static uint16_t ChargeVoltageLimit = 500; //Max voltage limit during charging of the HV Battery. +static uint8_t CurrentWarning = 0; // 0 normal, 1 cell overcurrent, 2 cell undercurrent +static uint8_t TempWarning = 0; // 0 normal, 1 cell overtemp, 2 cell undertemp +static int8_t TempUpLimit = 0; //Upper temperature limit. +static uint8_t CellVoltWarning = 0; // 0 normal, 1 cell overvoltage, 2 cell undervoltage +static bool CCCVChargeMode = false; //0 CC, 1 = CV +static uint16_t CellVoltUpLimit = 0; //mV, Upper cell voltage limit +static uint16_t SOCHighestCell = 0; //0.01, % +static uint16_t SOCLowestCell = 0; //0.01, % +static uint16_t SOCAverage = 0; //0.01, % +static bool WakeUpTopUpReq = + false; //The HV Battery can trigger a vehicle wake-up to request its State of Charge to be increased. +static bool WakeUpThermalReq = + false; //The HV Battery can trigger a vehicle wake-up in order to be thermally managed (ie. cooled down OR warmed up). +static bool WakeUpDchReq = + false; //The HV Battery can trigger a vehicle wake-up to request its State of Charge to be reduced. +static uint16_t StateofHealth = 0; +static uint16_t EstimatedLossChg = + 0; //fact0.001, kWh Expected energy which will be lost during charging (at the rate given by VSCEstChargePower) due to resistance within the HV Battery. +static bool CoolingRequest = + false; //HV Battery cooling request to be cooled by the eAC/chiller as its cooling needs exceed the LTR cooling loop capability. +static uint16_t EstimatedLossDch = + 0; //fact0.001, kWh Expected energy which will be lost during discharging (at the rate given by VSCEstDischargePower) due to resistance within the HV Battery. +static uint8_t FanDutyRequest = + 0; //Request from the HV Battery cooling system to demand a change of duty for the electrical engine cooling fan speed (whilst using its LTR cooling loop). +static bool ValveCtrlStat = false; //0 Chiller/Heater cooling loop requested , 1 LTR cooling loop requested +static uint16_t EstLossDchTgtSoC = + 0; //fact0.001, kWh Expected energy which will be lost during discharging (at the rate given by VSCEstimatedDchPower) from the target charging SoC (PHEV: HVBattEnergyUsableMax, BEV: HVBattEnergyUsableBulk) down to HVBattEnergyUsableMin, due to resistance within the Traction Battery. +static uint8_t HeatPowerGenChg = + 0; //fact0.1, kW, Estimated average heat generated by battery if charged at the rate given by VSCEstimatedChgPower. +static uint8_t HeatPowerGenDch = + 0; //fact0.1, kW, Estimated average heat generated by battery if discharged at the rate given by VSCEstimatedDchPower. +static uint8_t WarmupRateChg = + 0; //fact0.1, C/min , Expected average rate at which the battery will self-heat if charged at the rate given by VSCEstimatedChgPower. +static uint8_t WarmupRateDch = + 0; //fact0.1, C/min , Expected average rate at which the battery will self-heat if discharged at the rate given by VSCEstimatedDchPower. +static uint16_t CellVoltageMax = 3700; +static uint16_t CellVoltageMin = 3700; +static int8_t CellTempAverage = 0; //factor0.5, -40 offset +static int8_t CellTempColdest = 0; //factor0.5, -40 offset +static int8_t CellTempHottest = 0; //factor0.5, -40 offset +static uint8_t HeaterCtrlStat = 0; //factor1, 0 offset +static bool ThermalOvercheck = false; // 0 OK, 1 NOT OK +static int8_t InletCoolantTemp = 0; //factor0.5, -40 offset +static bool ClntPumpDiagStat_UB = false; +static bool InletCoolantTemp_UB = false; +static bool CoolantLevel = false; // Coolant level OK , 1 NOT OK +static bool ClntPumpDiagStat = false; // 0 Pump OK, 1 NOT OK +static uint8_t MILRequest = 0; //No req, 1 ON, 2 FLASHING, 3 unused +static uint16_t EnergyAvailable = 0; //fac0.05 , The total energy available from the HV Battery +static uint16_t EnergyUsableMax = 0; //fac0.05 , The total energy available from the HV Battery at its maximum SOC +static uint16_t EnergyUsableMin = 0; //fac0.05 , The total energy available from the HV Battery at its minimum SOC +static uint16_t TotalCapacity = + 0; //fac0.1 , Total Battery capacity in Kwh. This will reduce over the lifetime of the HV Battery. + +//CAN messages needed by battery (LOG needed!) +CAN_frame RANGE_ROVER_18B = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x18B, //CONTENT??? TODO + .data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +void update_values_battery() { + + datalayer.battery.status.real_soc = SOCAverage; + + datalayer.battery.status.soh_pptt = StateofHealth * 10; + + datalayer.battery.status.voltage_dV = VoltageExt * 10; + + datalayer.battery.status.current_dA = (CurrentExt * 0.025) - 209715; + + datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt + ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); + + datalayer.battery.status.max_charge_power_W = (ChargeContPwrLmt * 10) - 6550; + + datalayer.battery.status.max_discharge_power_W = (DischargeContPwrLmt * 10) - 6550; + + datalayer.battery.status.remaining_capacity_Wh = static_cast( + (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); + + datalayer.battery.status.cell_max_voltage_mV = CellVoltageMax; + + datalayer.battery.status.cell_min_voltage_mV = CellVoltageMin; + + datalayer.battery.status.temperature_min_dC = CellTempColdest * 10; + + datalayer.battery.status.temperature_max_dC = CellTempHottest * 10; + + datalayer.battery.info.max_design_voltage_dV = ChargeVoltageLimit * 10; + + datalayer.battery.info.min_design_voltage_dV = DischargeVoltageLimit * 10; +} + +void receive_can_battery(CAN_frame rx_frame) { + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + switch (rx_frame.ID) { + case 0x080: // 15ms + StatusCAT5BPOChg = (rx_frame.data.u8[0] & 0x01); + StatusCAT4Derate = (rx_frame.data.u8[0] & 0x02) >> 1; + OCMonitorStatus = (rx_frame.data.u8[0] & 0x0C) >> 2; + StatusCAT3 = (rx_frame.data.u8[0] & 0x10) >> 4; + IsolationStatus = (rx_frame.data.u8[0] & 0x20) >> 5; + HVILStatus = (rx_frame.data.u8[0] & 0x40) >> 6; + ContactorStatus = (rx_frame.data.u8[0] & 0x80) >> 7; + StatusGpCounter = (rx_frame.data.u8[1] & 0x0F); + WeldCheckStatus = (rx_frame.data.u8[1] & 0x20) >> 5; + StatusCAT7NowBPO = (rx_frame.data.u8[1] & 0x40) >> 6; + StatusCAT6DlyBPO = (rx_frame.data.u8[1] & 0x80) >> 7; + StatusGpCS = rx_frame.data.u8[2]; + CAT6Count = rx_frame.data.u8[3] & 0x7F; + EndOfCharge = (rx_frame.data.u8[6] & 0x04) >> 2; + DerateWarning = (rx_frame.data.u8[6] & 0x08) >> 3; + PrechargeAllowed = (rx_frame.data.u8[6] & 0x10) >> 4; + break; + case 0x100: // 20ms + DischargeExtGpCounter = (rx_frame.data.u8[0] & 0x0F); + DischargeExtGpCS = rx_frame.data.u8[1]; + DischargeVoltageLimit = (((rx_frame.data.u8[2] & 0x03) << 8) | rx_frame.data.u8[3]); + DischargePowerLimitExt = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + DischargeContPwrLmt = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case 0x102: // 20ms + PwrGpCS = rx_frame.data.u8[0]; + PwrGpCounter = (rx_frame.data.u8[1] & 0x3C) >> 2; + VoltageExt = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[2]); + VoltageBus = (((rx_frame.data.u8[3] & 0x03) << 8) | rx_frame.data.u8[4]); + CurrentExt = ((rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case 0x104: // 20ms + HVIsolationTestRunning = (rx_frame.data.u8[2] & 0x10) >> 4; + VoltageOC = (((rx_frame.data.u8[2] & 0x03) << 8) | rx_frame.data.u8[3]); + DchCurrentLimit = (((rx_frame.data.u8[4] & 0x03) << 8) | rx_frame.data.u8[5]); + ChgCurrentLimit = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[7]); + break; + case 0x10A: // 20ms + ChargeContPwrLmt = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]); + ChargePowerLimitExt = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); + ChgExtGpCS = rx_frame.data.u8[4]; + ChgExtGpCounter = (rx_frame.data.u8[5] >> 4); + ChargeVoltageLimit = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[7]); + break; + case 0x198: // 60ms + CurrentWarning = (rx_frame.data.u8[4] & 0x03); + TempWarning = ((rx_frame.data.u8[4] & 0x0C) >> 2); + TempUpLimit = (rx_frame.data.u8[5] / 2) - 40; + CellVoltWarning = ((rx_frame.data.u8[6] & 0x60) >> 5); + CCCVChargeMode = ((rx_frame.data.u8[6] & 0x80) >> 7); + CellVoltUpLimit = (((rx_frame.data.u8[6] & 0x1F) << 8) | rx_frame.data.u8[7]); + break; + case 0x220: // 100ms + SOCHighestCell = (((rx_frame.data.u8[0] & 0x3F) << 8) | rx_frame.data.u8[1]); + SOCLowestCell = (((rx_frame.data.u8[2] & 0x3F) << 8) | rx_frame.data.u8[3]); + SOCAverage = (((rx_frame.data.u8[4] & 0x3F) << 8) | rx_frame.data.u8[5]); + WakeUpTopUpReq = ((rx_frame.data.u8[6] & 0x04) >> 2); + WakeUpThermalReq = ((rx_frame.data.u8[6] & 0x08) >> 3); + WakeUpDchReq = ((rx_frame.data.u8[6] & 0x10) >> 4); + StateofHealth = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[7]); + break; + case 0x308: // 190ms + EstimatedLossChg = (((rx_frame.data.u8[0] & 0x03) << 8) | rx_frame.data.u8[1]); + CoolingRequest = ((rx_frame.data.u8[6] & 0x04) >> 2); + EstimatedLossDch = (((rx_frame.data.u8[2] & 0x03) << 8) | rx_frame.data.u8[3]); + FanDutyRequest = (rx_frame.data.u8[4] & 0x7F); + ValveCtrlStat = ((rx_frame.data.u8[4] & 0x80) >> 7); + EstLossDchTgtSoC = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[6]); + break; + case 0x424: // 280ms + HeatPowerGenChg = (rx_frame.data.u8[0] & 0x7F); + HeatPowerGenDch = (rx_frame.data.u8[1] & 0x7F); + WarmupRateChg = (rx_frame.data.u8[2] & 0x3F); + WarmupRateDch = (rx_frame.data.u8[3] & 0x3F); + CellVoltageMax = (((rx_frame.data.u8[4] & 0x1F) << 8) | rx_frame.data.u8[5]); + CellVoltageMin = (((rx_frame.data.u8[6] & 0x1F) << 8) | rx_frame.data.u8[7]); + break; + case 0x448: // 600ms + CellTempAverage = (rx_frame.data.u8[0] / 2) - 40; + CellTempColdest = (rx_frame.data.u8[1] / 2) - 40; + CellTempHottest = (rx_frame.data.u8[2] / 2) - 40; + HeaterCtrlStat = (rx_frame.data.u8[3] & 0x7F); + ThermalOvercheck = ((rx_frame.data.u8[3] & 0x80) >> 7); + InletCoolantTemp = rx_frame.data.u8[5]; + ClntPumpDiagStat_UB = ((rx_frame.data.u8[6] & 0x04) >> 2); + InletCoolantTemp_UB = ((rx_frame.data.u8[6] & 0x08) >> 3); + CoolantLevel = ((rx_frame.data.u8[6] & 0x10) >> 4); + ClntPumpDiagStat = ((rx_frame.data.u8[6] & 0x20) >> 5); + MILRequest = ((rx_frame.data.u8[6] & 0xC0) >> 6); + break; + case 0x464: // 800ms + EnergyAvailable = (((rx_frame.data.u8[0] & 0x07) << 8) | rx_frame.data.u8[1]); + EnergyUsableMax = (((rx_frame.data.u8[2] & 0x07) << 8) | rx_frame.data.u8[3]); + EnergyUsableMin = (((rx_frame.data.u8[4] & 0x07) << 8) | rx_frame.data.u8[5]); + TotalCapacity = (((rx_frame.data.u8[6] & 0x0F) << 8) | rx_frame.data.u8[7]); + break; + case 0x5A2: //Not periodically transferred + break; + case 0x656: //Not periodically transferred + break; + case 0x657: //Not periodically transferred + break; + case 0x6C8: //Not periodically transferred + break; + case 0x6C9: //Not periodically transferred + break; + case 0x6CA: //Not periodically transferred + break; + case 0x6CB: //Not periodically transferred + break; + case 0x7EC: //Not periodically transferred + break; + default: + break; + } +} + +void send_can_battery() { + unsigned long currentMillis = millis(); + // Send 50ms CAN Message + if (currentMillis - previousMillis50ms >= INTERVAL_50_MS) { + + previousMillis50ms = currentMillis; + + transmit_can(&RANGE_ROVER_18B, can_config.battery); + } +} + +void setup_battery(void) { // Performs one time setup at startup +#ifdef DEBUG_VIA_USB + Serial.println("Range Rover PHEV battery (L494 / L405) selected"); +#endif //DEBUG_VIA_USB + + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; +} + +#endif //RANGE_ROVER_PHEV_BATTERY diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h new file mode 100644 index 00000000..c4cdcf07 --- /dev/null +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h @@ -0,0 +1,18 @@ +#ifndef RANGE_ROVER_PHEV_BATTERY_H +#define RANGE_ROVER_PHEV_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED + +/* Change the following to suit your battery */ +#define MAX_PACK_VOLTAGE_DV 5000 //TODO: Configure +#define MIN_PACK_VOLTAGE_DV 0 //TODO: Configure +#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value +#define MAX_CELL_DEVIATION_MV 500 //TODO: Configure + +void setup_battery(void); +void transmit_can(CAN_frame* tx_frame, int interface); + +#endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 09ebe9d4..8eab7631 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -558,6 +558,9 @@ String processor(const String& var) { #ifdef RJXZS_BMS content += "RJXZS BMS, DIY battery"; #endif // RJXZS_BMS +#ifdef RANGE_ROVER_PHEV_BATTERY + content += "Range Rover 13kWh PHEV battery (L494/L405)"; +#endif //RANGE_ROVER_PHEV_BATTERY #ifdef RENAULT_KANGOO_BATTERY content += "Renault Kangoo"; #endif // RENAULT_KANGOO_BATTERY From 3a9aefd58c2668e9165231fb46f156ab488ff0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 13 Nov 2024 21:28:46 +0200 Subject: [PATCH 39/48] Fix endianess, simplify inverter brand read --- Software/src/inverter/BYD-CAN.cpp | 39 +++++++++++-------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 5cf999a3..ae0bb560 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -7,13 +7,6 @@ static unsigned long previousMillis2s = 0; // will store last time a 2s CAN Message was send static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send -static uint8_t char1_151 = 0; -static uint8_t char2_151 = 0; -static uint8_t char3_151 = 0; -static uint8_t char4_151 = 0; -static uint8_t char5_151 = 0; -static uint8_t char6_151 = 0; -static uint8_t char7_151 = 0; CAN_frame BYD_250 = {.FD = false, .ext_ID = false, @@ -79,6 +72,7 @@ CAN_frame BYD_210 = {.FD = false, .ID = 0x210, .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static uint8_t inverter_name[7] = {0}; static int16_t temperature_average = 0; static uint16_t inverter_voltage = 0; static uint16_t inverter_SOC = 0; @@ -146,15 +140,12 @@ void update_values_can_inverter() { //This function maps all the values fetched BYD_210.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF); #ifdef DEBUG_VIA_USB - if (char1_151 != 0) { + if (inverter_name[0] != 0) { Serial.print("Detected inverter: "); - Serial.print((char)char1_151); - Serial.print((char)char2_151); - Serial.print((char)char3_151); - Serial.print((char)char4_151); - Serial.print((char)char5_151); - Serial.print((char)char6_151); - Serial.println((char)char7_151); + for (uint8_t i = 0; i < 7; i++) { + Serial.print((char)inverter_name[i]); + } + Serial.println(); } #endif } @@ -166,27 +157,23 @@ void receive_can_inverter(CAN_frame rx_frame) { if (rx_frame.data.u8[0] & 0x01) { //Battery requests identification send_intial_data(); } else { // We can identify what inverter type we are connected to - char1_151 = rx_frame.data.u8[1]; - char2_151 = rx_frame.data.u8[2]; - char3_151 = rx_frame.data.u8[3]; - char4_151 = rx_frame.data.u8[4]; - char5_151 = rx_frame.data.u8[5]; - char6_151 = rx_frame.data.u8[6]; - char7_151 = rx_frame.data.u8[7]; + for (uint8_t i = 0; i < 7; i++) { + inverter_name[i] = rx_frame.data.u8[i + 1]; + } } break; case 0x091: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - inverter_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.1; + inverter_voltage = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]) * 0.1; break; case 0x0D1: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - inverter_SOC = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.1; + inverter_SOC = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]) * 0.1; break; case 0x111: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - inverter_timestamp = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[1] << 8) | - rx_frame.data.u8[0]); + inverter_timestamp = ((rx_frame.data.u8[0] << 24) | (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | + rx_frame.data.u8[3]); break; default: break; From 1e50394b0f9643f870653461ffaae8ec99f55d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 13 Nov 2024 22:41:51 +0200 Subject: [PATCH 40/48] Centralize active_power_w writing --- Software/Software.ino | 6 ++++++ Software/src/battery/BMW-I3-BATTERY.cpp | 10 ---------- Software/src/battery/BMW-IX-BATTERY.cpp | 5 ----- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 6 ------ Software/src/battery/CELLPOWER-BMS.cpp | 3 --- Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp | 2 -- Software/src/battery/JAGUAR-IPACE-BATTERY.cpp | 4 ---- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 5 ----- Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 4 ---- Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp | 4 ---- Software/src/battery/MG-5-BATTERY.cpp | 2 -- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 7 ------- Software/src/battery/PYLON-BATTERY.cpp | 3 --- Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp | 3 --- Software/src/battery/RENAULT-KANGOO-BATTERY.cpp | 3 --- Software/src/battery/RENAULT-TWIZY.cpp | 3 --- Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 4 ---- Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp | 3 --- Software/src/battery/RJXZS-BMS.cpp | 3 --- Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp | 4 ---- Software/src/battery/TESLA-BATTERY.cpp | 4 ---- Software/src/battery/TEST-FAKE-BATTERY.cpp | 4 ---- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 1 - 23 files changed, 6 insertions(+), 87 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index c85c376d..babef4dd 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -854,6 +854,9 @@ void update_calculated_values() { if (datalayer.battery.status.max_discharge_current_dA > datalayer.battery.settings.max_user_set_discharge_dA) { datalayer.battery.status.max_discharge_current_dA = datalayer.battery.settings.max_user_set_discharge_dA; } + /* Calculate active power based on voltage and current*/ + datalayer.battery.status.active_power_W = + (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); if (datalayer.battery.settings.soc_scaling_active) { /** SOC Scaling @@ -899,6 +902,9 @@ void update_calculated_values() { } #ifdef DOUBLE_BATTERY + /* Calculate active power based on voltage and current*/ + datalayer.battery2.status.active_power_W = + (datalayer.battery2.status.current_dA * (datalayer.battery2.status.voltage_dV / 100)); // Calculate the scaled remaining capacity in Wh if (datalayer.battery2.info.total_capacity_Wh > 0 && datalayer.battery2.status.real_soc > 0) { diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index c02a112e..a1b576d4 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -239,7 +239,6 @@ static int16_t battery_temperature_max = 0; static int16_t battery_temperature_min = 0; static int16_t battery_max_charge_amperage = 0; static int16_t battery_max_discharge_amperage = 0; -static int16_t battery_power = 0; static int16_t battery_current = 0; static uint8_t battery_status_error_isolation_external_Bordnetz = 0; static uint8_t battery_status_error_isolation_internal_Bordnetz = 0; @@ -308,7 +307,6 @@ static int16_t battery2_temperature_max = 0; static int16_t battery2_temperature_min = 0; static int16_t battery2_max_charge_amperage = 0; static int16_t battery2_max_discharge_amperage = 0; -static int16_t battery2_power = 0; static int16_t battery2_current = 0; static uint8_t battery2_status_error_isolation_external_Bordnetz = 0; static uint8_t battery2_status_error_isolation_internal_Bordnetz = 0; @@ -388,10 +386,6 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.max_charge_power_W = battery2_BEV_available_power_longterm_charge; } - battery2_power = (datalayer.battery2.status.current_dA * (datalayer.battery2.status.voltage_dV / 100)); - - datalayer.battery2.status.active_power_W = battery2_power; - datalayer.battery2.status.temperature_min_dC = battery2_temperature_min * 10; // Add a decimal datalayer.battery2.status.temperature_max_dC = battery2_temperature_max * 10; // Add a decimal @@ -456,10 +450,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = battery_BEV_available_power_longterm_charge; - battery_power = (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); - - datalayer.battery.status.active_power_W = battery_power; - datalayer.battery.status.temperature_min_dC = battery_temperature_min * 10; // Add a decimal datalayer.battery.status.temperature_max_dC = battery_temperature_max * 10; // Add a decimal diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 2f316097..a994e27d 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -353,7 +353,6 @@ static unsigned long min_cell_voltage_lastchanged = 0; static unsigned long max_cell_voltage_lastchanged = 0; static unsigned min_cell_voltage_lastreceived = 0; static unsigned max_cell_voltage_lastreceived = 0; -static int16_t battery_power = 0; static uint32_t sme_uptime = 0; //Uses E4 C0 static int16_t allowable_charge_amps = 0; //E5 62 static int16_t allowable_discharge_amps = 0; //E5 62 @@ -454,10 +453,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_ALLOWED_W; } - battery_power = (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); - - datalayer.battery.status.active_power_W = battery_power; - datalayer.battery.status.temperature_min_dC = min_battery_temperature; datalayer.battery.status.temperature_max_dC = max_battery_temperature; diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index f20f0c1f..9a1e1f9b 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -122,9 +122,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = 10000; //TODO: Map from CAN later on - datalayer.battery.status.active_power_W = - (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); - datalayer.battery.status.cell_max_voltage_mV = BMS_highest_cell_voltage_mV; datalayer.battery.status.cell_min_voltage_mV = BMS_lowest_cell_voltage_mV; @@ -445,9 +442,6 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.max_charge_power_W = 10000; //TODO: Map from CAN later on - datalayer.battery2.status.active_power_W = - (datalayer.battery2.status.current_dA * (datalayer.battery2.status.voltage_dV / 100)); - datalayer.battery2.status.cell_max_voltage_mV = BMS2_highest_cell_voltage_mV; datalayer.battery2.status.cell_min_voltage_mV = BMS2_lowest_cell_voltage_mV; diff --git a/Software/src/battery/CELLPOWER-BMS.cpp b/Software/src/battery/CELLPOWER-BMS.cpp index 8bd5a1b5..ec448312 100644 --- a/Software/src/battery/CELLPOWER-BMS.cpp +++ b/Software/src/battery/CELLPOWER-BMS.cpp @@ -124,9 +124,6 @@ void update_values_battery() { datalayer.battery.status.current_dA = battery_pack_current_dA; - datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.max_charge_power_W = 5000; //TODO, is this available via CAN? datalayer.battery.status.max_discharge_power_W = 5000; //TODO, is this available via CAN? diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index c4094e3f..43ef0b07 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -51,8 +51,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_discharge_power_W = 10000; // 10kW //TODO: Fix when CAN is decoded - datalayer.battery.status.active_power_W = BMU_Power; //TODO: Scaling? - static int n = sizeof(cell_voltages) / sizeof(cell_voltages[0]); max_volt_cel = cell_voltages[0]; // Initialize max with the first element of the array for (int i = 1; i < n; i++) { diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp index e5f3fe9b..a083a8ce 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp @@ -81,10 +81,6 @@ void update_values_battery() { datalayer.battery.status.cell_min_voltage_mV = HVBattCellVoltageMinMv; - //Power in watts, Negative = charging batt - datalayer.battery.status.active_power_W = - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.temperature_min_dC = HVBattCellTempColdest * 10; // C to dC datalayer.battery.status.temperature_max_dC = HVBattCellTempHottest * 10; // C to dC diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index bb0c174d..19db7992 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -38,7 +38,6 @@ static uint16_t CellVoltMin_mV = 3700; static uint16_t batteryVoltage = 6700; static int16_t leadAcidBatteryVoltage = 120; static int16_t batteryAmps = 0; -static int16_t powerWatt = 0; static int16_t temperatureMax = 0; static int16_t temperatureMin = 0; static int16_t allowedDischargePower = 0; @@ -660,10 +659,6 @@ void update_values_battery() { //This function maps all the values fetched via //The allowed discharge power is not available. We hardcode this value for now datalayer.battery.status.max_discharge_power_W = MAXDISCHARGEPOWERALLOWED; - powerWatt = ((batteryVoltage * batteryAmps) / 100); - - datalayer.battery.status.active_power_W = powerWatt; //Power in watts, Negative = charging batt - datalayer.battery.status.temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C datalayer.battery.status.temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index a99be631..b3f935a6 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -124,10 +124,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_discharge_power_W = allowedDischargePower * 10; - //Power in watts, Negative = charging batt - datalayer.battery.status.active_power_W = - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C datalayer.battery.status.temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp index f2597d3d..49a8dae6 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp @@ -68,10 +68,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = available_charge_power * 10; - //Power in watts, Negative = charging batt - datalayer.battery.status.active_power_W = - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.temperature_min_dC = (int16_t)(battery_module_min_temperature * 10); datalayer.battery.status.temperature_max_dC = (int16_t)(battery_module_max_temperature * 10); diff --git a/Software/src/battery/MG-5-BATTERY.cpp b/Software/src/battery/MG-5-BATTERY.cpp index b181edaf..8da1b9a2 100644 --- a/Software/src/battery/MG-5-BATTERY.cpp +++ b/Software/src/battery/MG-5-BATTERY.cpp @@ -39,8 +39,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W; - datalayer.battery.status.active_power_W; - datalayer.battery.status.temperature_min_dC; datalayer.battery.status.temperature_max_dC; diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 67bb21f9..f32a9ba6 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -197,9 +197,6 @@ void update_values_battery() { /* This function maps all the values fetched via datalayer.battery.status.remaining_capacity_Wh = battery_Wh_Remaining; - datalayer.battery.status.active_power_W = ((battery_Total_Voltage2 * battery_Current2) / - 4); //P = U * I (Both values are 0.5 per bit so the math is non-intuitive) - //Update temperature readings. Method depends on which generation LEAF battery is used if (LEAF_battery_Type == ZE0_BATTERY) { //Since we only have average value, send the minimum as -1.0 degrees below average @@ -369,10 +366,6 @@ void update_values_battery2() { // Handle the values coming in from battery #2 datalayer.battery2.status.remaining_capacity_Wh = battery2_Wh_Remaining; - datalayer.battery2.status.active_power_W = - ((battery2_Total_Voltage2 * battery2_Current2) / - 4); //P = U * I (Both values are 0.5 per bit so the math is non-intuitive) - //Update temperature readings. Method depends on which generation LEAF battery is used if (LEAF_battery2_Type == ZE0_BATTERY) { //Since we only have average value, send the minimum as -1.0 degrees below average diff --git a/Software/src/battery/PYLON-BATTERY.cpp b/Software/src/battery/PYLON-BATTERY.cpp index 068a12b7..16906722 100644 --- a/Software/src/battery/PYLON-BATTERY.cpp +++ b/Software/src/battery/PYLON-BATTERY.cpp @@ -60,9 +60,6 @@ void update_values_battery() { datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) , invert the sign - datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.max_charge_power_W = (max_charge_current * (voltage_dV / 10)); datalayer.battery.status.max_discharge_power_W = (-max_discharge_current * (voltage_dV / 10)); diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp index d530c2d5..4f6eb16c 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp @@ -160,9 +160,6 @@ void update_values_battery() { datalayer.battery.status.current_dA = (CurrentExt * 0.025) - 209715; - datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.max_charge_power_W = (ChargeContPwrLmt * 10) - 6550; datalayer.battery.status.max_discharge_power_W = (DischargeContPwrLmt * 10) - 6550; diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index bd8b1665..00b4e12b 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -95,9 +95,6 @@ void update_values_battery() { //This function maps all the values fetched via //The above value is 0 on some packs. We instead hardcode this now. datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_W; - datalayer.battery.status.active_power_W = - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.temperature_min_dC = (LB_MIN_TEMPERATURE * 10); datalayer.battery.status.temperature_max_dC = (LB_MAX_TEMPERATURE * 10); diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index 98f27a83..69a83316 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -46,9 +46,6 @@ void update_values_battery() { datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) datalayer.battery.status.remaining_capacity_Wh = remaining_capacity_Wh; - datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - // The twizy provides two values: one for the maximum charge provided by the on-board charger // and one for the maximum charge during recuperation. // For now we use the lower of the two (usually the charger one) diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index 917e7892..1044729f 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -104,10 +104,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = 50; } - //Power in watts, Negative = charging batt - datalayer.battery.status.active_power_W = - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - int16_t temperatures[] = {cell_1_temperature_polled, cell_2_temperature_polled, cell_3_temperature_polled, cell_4_temperature_polled, cell_5_temperature_polled, cell_6_temperature_polled, cell_7_temperature_polled, cell_8_temperature_polled, cell_9_temperature_polled, diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp index 38c875b1..50b09d2e 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp @@ -166,9 +166,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = battery_max_generated * 10; - datalayer.battery.status.active_power_W = - (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100)); - datalayer.battery.status.temperature_min_dC = ((battery_min_temp - 640) * 0.625); datalayer.battery.status.temperature_max_dC = ((battery_max_temp - 640) * 0.625); diff --git a/Software/src/battery/RJXZS-BMS.cpp b/Software/src/battery/RJXZS-BMS.cpp index ed23fb40..b75934c8 100644 --- a/Software/src/battery/RJXZS-BMS.cpp +++ b/Software/src/battery/RJXZS-BMS.cpp @@ -98,9 +98,6 @@ void update_values_battery() { datalayer.battery.status.current_dA = total_current; - datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - // Charge power is set in .h file if (datalayer.battery.status.real_soc > 9900) { datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_WHEN_TOPBALANCING_W; diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index dbe69b55..36b1a649 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -85,10 +85,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = allowedChargePower * 10; - //Power in watts, Negative = charging batt - datalayer.battery.status.active_power_W = - ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.cell_max_voltage_mV = CellVoltMax_mV; datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV; diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 3eac62cc..eaa01e1b 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -297,8 +297,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W = MAXCHARGEPOWERALLOWED; } - datalayer.battery.status.active_power_W = ((battery_volts / 10) * battery_amps); - datalayer.battery.status.temperature_min_dC = battery_min_temp; datalayer.battery.status.temperature_max_dC = battery_max_temp; @@ -857,8 +855,6 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.max_charge_power_W = MAXCHARGEPOWERALLOWED; } - datalayer.battery2.status.active_power_W = ((battery2_volts / 10) * battery2_amps); - datalayer.battery2.status.temperature_min_dC = battery2_min_temp; datalayer.battery2.status.temperature_max_dC = battery2_max_temp; diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index 423654aa..fdc35294 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -40,8 +40,6 @@ void update_values_battery() { /* This function puts fake values onto the parame datalayer.battery.status.cell_min_voltage_mV = 3500; - datalayer.battery.status.active_power_W = 0; // 0W - datalayer.battery.status.temperature_min_dC = 50; // 5.0*C datalayer.battery.status.temperature_max_dC = 60; // 6.0*C @@ -95,8 +93,6 @@ void update_values_battery2() { // Handle the values coming in from battery #2 datalayer.battery2.status.cell_min_voltage_mV = 3500; - datalayer.battery2.status.active_power_W = 0; // 0W - datalayer.battery2.status.temperature_min_dC = 50; // 5.0*C datalayer.battery2.status.temperature_max_dC = 60; // 6.0*C diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index d321ad38..efdbc0a0 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -83,7 +83,6 @@ void update_values_battery() { //This function maps all the values fetched via //datalayer.battery.status.max_discharge_power_W = HvBattPwrLimDchaSoft * 1000; // Use power limit reported from BMS, not trusted ATM datalayer.battery.status.max_discharge_power_W = 30000; datalayer.battery.status.max_charge_power_W = 30000; - datalayer.battery.status.active_power_W = (BATT_U)*BATT_I; datalayer.battery.status.temperature_min_dC = BATT_T_MIN; datalayer.battery.status.temperature_max_dC = BATT_T_MAX; From 1398c6213b36cdfc7f5441e94fa157979d2a3cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 13 Nov 2024 23:07:05 +0200 Subject: [PATCH 41/48] Update datalayer comment --- Software/src/datalayer/datalayer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 7e1880af..5b198158 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -31,7 +31,7 @@ typedef struct { typedef struct { /** int32_t */ - /** Instantaneous battery power in Watts */ + /** Instantaneous battery power in Watts. Calculated based on voltage_dV and current_dA */ /* Positive value = Battery Charging */ /* Negative value = Battery Discharging */ int32_t active_power_W; From edb6dcd39b66e0930df57717148815169c3897f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 18:38:23 +0200 Subject: [PATCH 42/48] Add battery text to datalayer --- Software/src/battery/BMW-I3-BATTERY.cpp | 9 +-- Software/src/battery/BMW-IX-BATTERY.cpp | 7 +- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 6 +- Software/src/battery/CELLPOWER-BMS.cpp | 6 +- Software/src/battery/CHADEMO-BATTERY.cpp | 8 +- .../src/battery/IMIEV-CZERO-ION-BATTERY.cpp | 7 +- Software/src/battery/JAGUAR-IPACE-BATTERY.cpp | 6 +- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 8 +- .../src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 7 +- .../battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp | 8 +- Software/src/battery/MG-5-BATTERY.cpp | 6 +- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 7 +- Software/src/battery/PYLON-BATTERY.cpp | 7 +- .../src/battery/RANGE-ROVER-PHEV-BATTERY.cpp | 7 +- .../src/battery/RENAULT-KANGOO-BATTERY.cpp | 7 +- Software/src/battery/RENAULT-TWIZY.cpp | 7 +- .../src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 7 +- .../src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp | 7 +- Software/src/battery/RJXZS-BMS.cpp | 8 +- .../src/battery/SANTA-FE-PHEV-BATTERY.cpp | 6 +- .../SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp | 5 +- Software/src/battery/TESLA-BATTERY.cpp | 12 ++- Software/src/battery/TEST-FAKE-BATTERY.cpp | 7 +- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 8 +- Software/src/datalayer/datalayer.h | 5 +- Software/src/devboard/webserver/webserver.cpp | 78 +------------------ 26 files changed, 101 insertions(+), 155 deletions(-) diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index a1b576d4..15bac9f4 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -1118,9 +1118,9 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("BMW i3 battery selected"); -#endif //DEBUG_VIA_USB + strncpy(datalayer.system.info.battery_protocol, "BMW i3", sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination //Before we have started up and detected which battery is in use, use 60AH values datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH; @@ -1129,9 +1129,6 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.system.status.battery_allows_contactor_closing = true; #ifdef DOUBLE_BATTERY -#ifdef DEBUG_VIA_USB - Serial.println("Another BMW i3 battery also selected!"); -#endif //DEBUG_VIA_USB datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV; datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV; datalayer.battery2.info.max_cell_voltage_deviation_mV = datalayer.battery.info.max_cell_voltage_deviation_mV; diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index a994e27d..5712d591 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -778,9 +778,10 @@ void send_can_battery() { //} //We can always send CAN as the iX BMS will wake up on vehicle comms void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("BMW iX battery selected"); -#endif //DEBUG_VIA_USB + strncpy(datalayer.system.info.battery_protocol, "BMW iX and i4-7 platform", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination //Before we have started up and detected which battery is in use, use 108S values datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 9a1e1f9b..4e7ad1fd 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -399,9 +399,9 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("BYD Atto 3 battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "BYD Atto 3", sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.number_of_cells = 126; datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/CELLPOWER-BMS.cpp b/Software/src/battery/CELLPOWER-BMS.cpp index ec448312..604f2e65 100644 --- a/Software/src/battery/CELLPOWER-BMS.cpp +++ b/Software/src/battery/CELLPOWER-BMS.cpp @@ -333,9 +333,9 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Cellpower BMS selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Cellpower BMS", sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index 90ecd950..d582f690 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -1031,9 +1031,11 @@ void handle_chademo_sequence() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Chademo battery selected"); -#endif + + strncpy(datalayer.system.info.battery_protocol, "Chademo V2X mode", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination CHADEMO_Status = CHADEMO_IDLE; diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index 43ef0b07..f24490cc 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -224,9 +224,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Mitsubishi i-MiEV / Citroen C-Zero / Peugeot Ion battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "I-Miev / C-Zero / Ion Triplet", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp index a083a8ce..3733810e 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp @@ -254,9 +254,9 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Jaguar iPace 90kWh battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Jaguar I-PACE", sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index 19db7992..0a810e9f 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -1037,14 +1037,14 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Hyundai E-GMP (Electric Global Modular Platform) battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai EGMP platform", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination startMillis = millis(); // Record the starting time datalayer.system.status.battery_allows_contactor_closing = true; - datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index b3f935a6..b25268d6 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -534,9 +534,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Kia Niro / Hyundai Kona 64kWh battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai 64/40kWh battery", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp index 49a8dae6..f6f88c52 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp @@ -257,9 +257,11 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Kia/Hyundai Hybrid battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai Hybrid", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination + datalayer.battery.info.number_of_cells = 56; // HEV , TODO: Make dynamic according to HEV/PHEV datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/MG-5-BATTERY.cpp b/Software/src/battery/MG-5-BATTERY.cpp index 8da1b9a2..94b8ec38 100644 --- a/Software/src/battery/MG-5-BATTERY.cpp +++ b/Software/src/battery/MG-5-BATTERY.cpp @@ -135,9 +135,9 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("MG 5 battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "MG 5 battery", sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index f32a9ba6..bb0d6f91 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1224,9 +1224,10 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature) { //This function feels horrib } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Nissan LEAF battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Nissan LEAF battery", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/PYLON-BATTERY.cpp b/Software/src/battery/PYLON-BATTERY.cpp index 16906722..dfa0dfe0 100644 --- a/Software/src/battery/PYLON-BATTERY.cpp +++ b/Software/src/battery/PYLON-BATTERY.cpp @@ -175,9 +175,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Pylon battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Pylon compatible battery", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp index 4f6eb16c..ce6ea714 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp @@ -313,9 +313,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Range Rover PHEV battery (L494 / L405) selected"); -#endif //DEBUG_VIA_USB + strncpy(datalayer.system.info.battery_protocol, "Range Rover 13kWh PHEV battery (L494/L405)", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index 00b4e12b..f3d51887 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -234,9 +234,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Renault Kangoo battery selected"); -#endif + + strncpy(datalayer.system.info.battery_protocol, "Renault Kangoo", sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index 69a83316..74c9ea91 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -132,10 +132,9 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Renault Twizy battery selected"); -#endif - + strncpy(datalayer.system.info.battery_protocol, "Renault Twizy", sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.number_of_cells = 14; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index 1044729f..27050919 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -518,9 +518,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Renault Zoe 22/40kWh battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen1 22/40kWh", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp index 50b09d2e..bafbdaf3 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp @@ -385,9 +385,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Renault Zoe 50kWh battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen2 50kWh", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RJXZS-BMS.cpp b/Software/src/battery/RJXZS-BMS.cpp index b75934c8..86b3d983 100644 --- a/Software/src/battery/RJXZS-BMS.cpp +++ b/Software/src/battery/RJXZS-BMS.cpp @@ -570,10 +570,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("RJXZS BMS selected"); -#endif - + strncpy(datalayer.system.info.battery_protocol, "RJXZS BMS, DIY battery", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index 36b1a649..2180628e 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -402,9 +402,9 @@ uint8_t CalculateCRC8(CAN_frame rx_frame) { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Hyundai Santa Fe PHEV battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Santa Fe PHEV", sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp index 0f4ac135..25a97ddd 100644 --- a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp +++ b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp @@ -219,7 +219,10 @@ void update_values_serial_link() { } void setup_battery(void) { - Serial.println("SERIAL_DATA_LINK_RECEIVER selected"); + strncpy(datalayer.system.info.battery_protocol, "Serial link to another LilyGo board", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination } // Needed to make the compiler happy void update_values_battery() {} diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index eaa01e1b..357864be 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1249,13 +1249,13 @@ void printDebugIfActive(uint8_t symbol, const char* message) { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Tesla Model S/3/X/Y battery selected"); -#endif - datalayer.system.status.battery_allows_contactor_closing = true; #ifdef TESLA_MODEL_SX_BATTERY // Always use NCM/A mode on S/X packs + strncpy(datalayer.system.info.battery_protocol, "Tesla Model S/X", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM; @@ -1271,6 +1271,10 @@ void setup_battery(void) { // Performs one time setup at startup #endif // TESLA_MODEL_SX_BATTERY #ifdef TESLA_MODEL_3Y_BATTERY // Model 3/Y can be either LFP or NCM/A + strncpy(datalayer.system.info.battery_protocol, "Tesla Model 3/Y", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination #ifdef LFP_CHEMISTRY datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP; diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index fdc35294..c964eb54 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -145,9 +145,10 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup randomSeed(analogRead(0)); -#ifdef DEBUG_VIA_USB - Serial.println("Test mode with fake battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Fake battery for testing purposes", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index efdbc0a0..fc71de42 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -332,10 +332,10 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("Volvo SPA XC40 Recharge / Polestar2 78kWh battery selected"); -#endif - + strncpy(datalayer.system.info.battery_protocol, "Volvo / Polestar 78kWh battery", + sizeof(datalayer.system.info.battery_protocol) - 1); + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = + '\0'; // Ensure null termination datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 5b198158..f925d30c 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -127,7 +127,10 @@ typedef struct { } DATALAYER_SHUNT_TYPE; typedef struct { - // TODO + /** array with type of battery used, for displaying on webserver */ + char battery_protocol[64] = {0}; + /** array with type of inverter used, for displaying on webserver */ + char inverter_protocol[64] = {0}; } DATALAYER_SYSTEM_INFO_TYPE; typedef struct { diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 8eab7631..b6de87a0 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -486,6 +486,7 @@ String processor(const String& var) { // Display which components are used content += "

Inverter protocol: "; + content += datalayer.system.info.inverter_protocol; #ifdef BYD_CAN content += "BYD Battery-Box Premium HVS over CAN Bus"; #endif // BYD_CAN @@ -514,83 +515,8 @@ String processor(const String& var) { content += "SolaX Triple Power LFP over CAN bus"; #endif // SOLAX_CAN content += "

"; - content += "

Battery protocol: "; -#ifdef BMW_I3_BATTERY - content += "BMW i3"; -#endif // BMW_I3_BATTERY -#ifdef BMW_IX_BATTERY - content += "BMW iX and i4-7 platform"; -#endif // BMW_IX_BATTERY -#ifdef BYD_ATTO_3_BATTERY - content += "BYD Atto 3"; -#endif // BYD_ATTO_3_BATTERY -#ifdef CELLPOWER_BMS - content += "Cellpower BMS"; -#endif // CELLPOWER_BMS -#ifdef CHADEMO_BATTERY - content += "Chademo V2X mode"; -#endif // CHADEMO_BATTERY -#ifdef IMIEV_CZERO_ION_BATTERY - content += "I-Miev / C-Zero / Ion Triplet"; -#endif // IMIEV_CZERO_ION_BATTERY -#ifdef JAGUAR_IPACE_BATTERY - content += "Jaguar I-PACE"; -#endif // JAGUAR_IPACE_BATTERY -#ifdef KIA_HYUNDAI_64_BATTERY - content += "Kia/Hyundai 64kWh"; -#endif // KIA_HYUNDAI_64_BATTERY -#ifdef KIA_E_GMP_BATTERY - content += "Kia/Hyundai EGMP platform"; -#endif // KIA_E_GMP_BATTERY -#ifdef KIA_HYUNDAI_HYBRID_BATTERY - content += "Kia/Hyundai Hybrid"; -#endif // KIA_HYUNDAI_HYBRID_BATTERY -#ifdef MG_5_BATTERY - content += "MG 5"; -#endif // MG_5_BATTERY -#ifdef NISSAN_LEAF_BATTERY - content += "Nissan LEAF"; -#endif // NISSAN_LEAF_BATTERY -#ifdef PYLON_BATTERY - content += "Pylon compatible battery"; -#endif // PYLON_BATTERY -#ifdef RJXZS_BMS - content += "RJXZS BMS, DIY battery"; -#endif // RJXZS_BMS -#ifdef RANGE_ROVER_PHEV_BATTERY - content += "Range Rover 13kWh PHEV battery (L494/L405)"; -#endif //RANGE_ROVER_PHEV_BATTERY -#ifdef RENAULT_KANGOO_BATTERY - content += "Renault Kangoo"; -#endif // RENAULT_KANGOO_BATTERY -#ifdef RENAULT_TWIZY_BATTERY - content += "Renault Twizy"; -#endif // RENAULT_TWIZY_BATTERY -#ifdef RENAULT_ZOE_GEN1_BATTERY - content += "Renault Zoe Gen1 22/40"; -#endif // RENAULT_ZOE_GEN1_BATTERY -#ifdef RENAULT_ZOE_GEN2_BATTERY - content += "Renault Zoe Gen2 50"; -#endif // RENAULT_ZOE_GEN2_BATTERY -#ifdef SANTA_FE_PHEV_BATTERY - content += "Santa Fe PHEV"; -#endif // SANTA_FE_PHEV_BATTERY -#ifdef SERIAL_LINK_RECEIVER - content += "Serial link to another LilyGo board"; -#endif // SERIAL_LINK_RECEIVER -#ifdef TESLA_MODEL_SX_BATTERY - content += "Tesla Model S/X"; -#endif // TESLA_MODEL_SX_BATTERY -#ifdef TESLA_MODEL_3Y_BATTERY - content += "Tesla Model 3/Y"; -#endif // TESLA_MODEL_3Y_BATTERY -#ifdef VOLVO_SPA_BATTERY - content += "Volvo / Polestar 78kWh battery"; -#endif // VOLVO_SPA_BATTERY -#ifdef TEST_FAKE_BATTERY - content += "Fake battery for testing purposes"; -#endif // TEST_FAKE_BATTERY + content += datalayer.system.info.battery_protocol; #ifdef DOUBLE_BATTERY content += " (Double battery)"; if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { From 950b0bbb269d8b4f2218037ad3a2adb42ec99cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 18:40:09 +0200 Subject: [PATCH 43/48] Remove comment --- Software/src/battery/BMW-I3-BATTERY.cpp | 3 +-- Software/src/battery/BMW-IX-BATTERY.cpp | 3 +-- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 3 +-- Software/src/battery/CELLPOWER-BMS.cpp | 3 +-- Software/src/battery/CHADEMO-BATTERY.cpp | 3 +-- Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp | 3 +-- Software/src/battery/JAGUAR-IPACE-BATTERY.cpp | 3 +-- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 3 +-- Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 3 +-- Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp | 3 +-- Software/src/battery/MG-5-BATTERY.cpp | 3 +-- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 3 +-- Software/src/battery/PYLON-BATTERY.cpp | 3 +-- Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp | 3 +-- Software/src/battery/RENAULT-KANGOO-BATTERY.cpp | 3 +-- Software/src/battery/RENAULT-TWIZY.cpp | 3 +-- Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 3 +-- Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp | 3 +-- Software/src/battery/RJXZS-BMS.cpp | 3 +-- Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp | 3 +-- Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp | 3 +-- Software/src/battery/TESLA-BATTERY.cpp | 6 ++---- Software/src/battery/TEST-FAKE-BATTERY.cpp | 3 +-- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 3 +-- 24 files changed, 25 insertions(+), 50 deletions(-) diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index 15bac9f4..2000558e 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -1119,8 +1119,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "BMW i3", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; //Before we have started up and detected which battery is in use, use 60AH values datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH; diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 5712d591..4a0846a5 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -780,8 +780,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "BMW iX and i4-7 platform", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; //Before we have started up and detected which battery is in use, use 108S values datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 4e7ad1fd..18040f9a 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -400,8 +400,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "BYD Atto 3", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.number_of_cells = 126; datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/CELLPOWER-BMS.cpp b/Software/src/battery/CELLPOWER-BMS.cpp index 604f2e65..d0b94943 100644 --- a/Software/src/battery/CELLPOWER-BMS.cpp +++ b/Software/src/battery/CELLPOWER-BMS.cpp @@ -334,8 +334,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Cellpower BMS", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index d582f690..afcc31a5 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -1034,8 +1034,7 @@ void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Chademo V2X mode", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; CHADEMO_Status = CHADEMO_IDLE; diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index f24490cc..c1ced536 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -226,8 +226,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "I-Miev / C-Zero / Ion Triplet", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp index 3733810e..a8c2234d 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp @@ -255,8 +255,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Jaguar I-PACE", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index 0a810e9f..4ec47bbf 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -1039,8 +1039,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai EGMP platform", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; startMillis = millis(); // Record the starting time diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index b25268d6..989ed911 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -536,8 +536,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai 64/40kWh battery", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp index f6f88c52..030ed454 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp @@ -259,8 +259,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai Hybrid", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.number_of_cells = 56; // HEV , TODO: Make dynamic according to HEV/PHEV datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/MG-5-BATTERY.cpp b/Software/src/battery/MG-5-BATTERY.cpp index 94b8ec38..bb50dd50 100644 --- a/Software/src/battery/MG-5-BATTERY.cpp +++ b/Software/src/battery/MG-5-BATTERY.cpp @@ -136,8 +136,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "MG 5 battery", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index bb0d6f91..fde3b41c 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1226,8 +1226,7 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature) { //This function feels horrib void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Nissan LEAF battery", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/PYLON-BATTERY.cpp b/Software/src/battery/PYLON-BATTERY.cpp index dfa0dfe0..a805e3b8 100644 --- a/Software/src/battery/PYLON-BATTERY.cpp +++ b/Software/src/battery/PYLON-BATTERY.cpp @@ -177,8 +177,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Pylon compatible battery", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp index ce6ea714..101d41a1 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp @@ -315,8 +315,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Range Rover 13kWh PHEV battery (L494/L405)", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index f3d51887..1f7b5cb0 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -236,8 +236,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Renault Kangoo", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index 74c9ea91..cce08880 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -133,8 +133,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Renault Twizy", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.number_of_cells = 14; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index 27050919..ed451064 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -520,8 +520,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen1 22/40kWh", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp index bafbdaf3..fe7525bd 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp @@ -387,8 +387,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen2 50kWh", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RJXZS-BMS.cpp b/Software/src/battery/RJXZS-BMS.cpp index 86b3d983..e9f4c070 100644 --- a/Software/src/battery/RJXZS-BMS.cpp +++ b/Software/src/battery/RJXZS-BMS.cpp @@ -572,8 +572,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "RJXZS BMS, DIY battery", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index 2180628e..39add8d9 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -403,8 +403,7 @@ uint8_t CalculateCRC8(CAN_frame rx_frame) { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Santa Fe PHEV", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp index 25a97ddd..141edead 100644 --- a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp +++ b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp @@ -221,8 +221,7 @@ void update_values_serial_link() { void setup_battery(void) { strncpy(datalayer.system.info.battery_protocol, "Serial link to another LilyGo board", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; } // Needed to make the compiler happy void update_values_battery() {} diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 357864be..839c0335 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1254,8 +1254,7 @@ void setup_battery(void) { // Performs one time setup at startup #ifdef TESLA_MODEL_SX_BATTERY // Always use NCM/A mode on S/X packs strncpy(datalayer.system.info.battery_protocol, "Tesla Model S/X", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM; @@ -1273,8 +1272,7 @@ void setup_battery(void) { // Performs one time setup at startup #ifdef TESLA_MODEL_3Y_BATTERY // Model 3/Y can be either LFP or NCM/A strncpy(datalayer.system.info.battery_protocol, "Tesla Model 3/Y", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; #ifdef LFP_CHEMISTRY datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP; diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index c964eb54..bb49e0a2 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -147,8 +147,7 @@ void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Fake battery for testing purposes", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index fc71de42..e94e8069 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -334,8 +334,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Volvo / Polestar 78kWh battery", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = - '\0'; // Ensure null termination + datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; From 8bba61405378f6db806485bb7cefcdfadc0e3f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 19:36:37 +0200 Subject: [PATCH 44/48] Add init function for inverters --- Software/Software.ino | 17 ++---------- Software/src/battery/BMW-I3-BATTERY.cpp | 4 +-- Software/src/battery/BMW-IX-BATTERY.cpp | 5 ++-- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 4 +-- Software/src/battery/CELLPOWER-BMS.cpp | 4 +-- Software/src/battery/CHADEMO-BATTERY.cpp | 5 ++-- .../src/battery/IMIEV-CZERO-ION-BATTERY.cpp | 5 ++-- Software/src/battery/JAGUAR-IPACE-BATTERY.cpp | 5 ++-- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 5 ++-- .../src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 5 ++-- .../battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp | 5 ++-- Software/src/battery/MG-5-BATTERY.cpp | 4 +-- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 5 ++-- Software/src/battery/PYLON-BATTERY.cpp | 6 ++--- .../src/battery/RANGE-ROVER-PHEV-BATTERY.cpp | 6 ++--- .../src/battery/RENAULT-KANGOO-BATTERY.cpp | 4 +-- Software/src/battery/RENAULT-TWIZY.cpp | 4 +-- .../src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 5 ++-- .../src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp | 5 ++-- Software/src/battery/RJXZS-BMS.cpp | 5 ++-- .../src/battery/SANTA-FE-PHEV-BATTERY.cpp | 4 +-- .../SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp | 5 ++-- Software/src/battery/TESLA-BATTERY.cpp | 10 +++---- Software/src/battery/TEST-FAKE-BATTERY.cpp | 5 ++-- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 5 ++-- Software/src/devboard/webserver/webserver.cpp | 27 ------------------- Software/src/inverter/AFORE-CAN.cpp | 4 +++ Software/src/inverter/AFORE-CAN.h | 3 +-- Software/src/inverter/BYD-CAN.cpp | 4 +++ Software/src/inverter/BYD-CAN.h | 1 + Software/src/inverter/BYD-MODBUS.cpp | 4 +++ Software/src/inverter/BYD-MODBUS.h | 1 + Software/src/inverter/BYD-SMA.cpp | 6 +++++ Software/src/inverter/BYD-SMA.h | 1 + Software/src/inverter/FOXESS-CAN.cpp | 4 +++ Software/src/inverter/FOXESS-CAN.h | 1 + Software/src/inverter/PYLON-CAN.cpp | 4 +++ Software/src/inverter/PYLON-CAN.h | 1 + Software/src/inverter/PYLON-LV-CAN.cpp | 4 +++ Software/src/inverter/PYLON-LV-CAN.h | 1 + .../SERIAL-LINK-TRANSMITTER-INVERTER.cpp | 8 ++++++ .../SERIAL-LINK-TRANSMITTER-INVERTER.h | 1 + Software/src/inverter/SMA-CAN.cpp | 5 ++++ Software/src/inverter/SMA-CAN.h | 1 + Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 5 ++++ Software/src/inverter/SMA-TRIPOWER-CAN.h | 1 + Software/src/inverter/SOFAR-CAN.cpp | 5 ++++ Software/src/inverter/SOFAR-CAN.h | 1 + Software/src/inverter/SOLAX-CAN.cpp | 5 ++++ Software/src/inverter/SOLAX-CAN.h | 1 + 50 files changed, 122 insertions(+), 114 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index babef4dd..303442a8 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -555,26 +555,13 @@ void init_rs485() { } void init_inverter() { -#ifdef SOLAX_CAN - datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first - intervalUpdateValues = 800; // This protocol also requires the values to be updated faster -#endif -#ifdef FOXESS_CAN - intervalUpdateValues = 950; // This protocol also requires the values to be updated faster -#endif -#ifdef BYD_SMA - datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first - pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); -#endif + // Inform user what inverter is used and perform setup + setup_inverter(); } void init_battery() { // Inform user what battery is used and perform setup setup_battery(); - -#ifdef CHADEMO_BATTERY - intervalUpdateValues = 800; // This mode requires the values to be updated faster -#endif } #ifdef EQUIPMENT_STOP_BUTTON diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index 2000558e..b15cb31e 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -1118,8 +1118,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "BMW i3", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "BMW i3", 63); + datalayer.system.info.battery_protocol[63] = '\0'; //Before we have started up and detected which battery is in use, use 60AH values datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH; diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 4a0846a5..8d9f358d 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -778,9 +778,8 @@ void send_can_battery() { //} //We can always send CAN as the iX BMS will wake up on vehicle comms void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "BMW iX and i4-7 platform", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "BMW iX and i4-7 platform", 63); + datalayer.system.info.battery_protocol[63] = '\0'; //Before we have started up and detected which battery is in use, use 108S values datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 18040f9a..bfbc92f3 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -399,8 +399,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "BYD Atto 3", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "BYD Atto 3", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 126; datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/CELLPOWER-BMS.cpp b/Software/src/battery/CELLPOWER-BMS.cpp index d0b94943..80c981c6 100644 --- a/Software/src/battery/CELLPOWER-BMS.cpp +++ b/Software/src/battery/CELLPOWER-BMS.cpp @@ -333,8 +333,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Cellpower BMS", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Cellpower BMS", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index afcc31a5..9e8d9e8c 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -1032,9 +1032,8 @@ void handle_chademo_sequence() { void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Chademo V2X mode", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Chademo V2X mode", 63); + datalayer.system.info.battery_protocol[63] = '\0'; CHADEMO_Status = CHADEMO_IDLE; diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index c1ced536..05e6e7c6 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -224,9 +224,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "I-Miev / C-Zero / Ion Triplet", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "I-Miev / C-Zero / Ion Triplet", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp index a8c2234d..eb13017c 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp @@ -254,9 +254,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Jaguar I-PACE", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; - + strncpy(datalayer.system.info.battery_protocol, "Jaguar I-PACE", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index 4ec47bbf..a0715a26 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -1037,9 +1037,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai EGMP platform", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai EGMP platform", 63); + datalayer.system.info.battery_protocol[63] = '\0'; startMillis = millis(); // Record the starting time diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 989ed911..3a6663c6 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -534,9 +534,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai 64/40kWh battery", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai 64/40kWh battery", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp index 030ed454..c37fcb15 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp @@ -257,9 +257,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai Hybrid", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai Hybrid", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 56; // HEV , TODO: Make dynamic according to HEV/PHEV datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/MG-5-BATTERY.cpp b/Software/src/battery/MG-5-BATTERY.cpp index bb50dd50..35c8ee96 100644 --- a/Software/src/battery/MG-5-BATTERY.cpp +++ b/Software/src/battery/MG-5-BATTERY.cpp @@ -135,8 +135,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "MG 5 battery", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "MG 5 battery", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index fde3b41c..79538070 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1224,9 +1224,8 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature) { //This function feels horrib } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Nissan LEAF battery", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Nissan LEAF battery", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/PYLON-BATTERY.cpp b/Software/src/battery/PYLON-BATTERY.cpp index a805e3b8..ec61901d 100644 --- a/Software/src/battery/PYLON-BATTERY.cpp +++ b/Software/src/battery/PYLON-BATTERY.cpp @@ -175,10 +175,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Pylon compatible battery", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; - + strncpy(datalayer.system.info.battery_protocol, "Pylon compatible battery", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp index 101d41a1..4ca3a330 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp @@ -313,10 +313,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Range Rover 13kWh PHEV battery (L494/L405)", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; - + strncpy(datalayer.system.info.battery_protocol, "Range Rover 13kWh PHEV battery (L494/L405)", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index 1f7b5cb0..096cb629 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -235,8 +235,8 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Renault Kangoo", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Renault Kangoo", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index cce08880..b0140eff 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -132,8 +132,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Renault Twizy", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Renault Twizy", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 14; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index ed451064..ef9f54f8 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -518,9 +518,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen1 22/40kWh", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen1 22/40kWh", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp index fe7525bd..08ac57bf 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp @@ -385,9 +385,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen2 50kWh", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen2 50kWh", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RJXZS-BMS.cpp b/Software/src/battery/RJXZS-BMS.cpp index e9f4c070..85b96434 100644 --- a/Software/src/battery/RJXZS-BMS.cpp +++ b/Software/src/battery/RJXZS-BMS.cpp @@ -570,9 +570,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "RJXZS BMS, DIY battery", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "RJXZS BMS, DIY battery", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index 39add8d9..e6f27acc 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -402,8 +402,8 @@ uint8_t CalculateCRC8(CAN_frame rx_frame) { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Santa Fe PHEV", sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Santa Fe PHEV", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp index 141edead..41697c33 100644 --- a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp +++ b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp @@ -219,9 +219,8 @@ void update_values_serial_link() { } void setup_battery(void) { - strncpy(datalayer.system.info.battery_protocol, "Serial link to another LilyGo board", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Serial link to another LilyGo board", 63); + datalayer.system.info.battery_protocol[63] = '\0'; } // Needed to make the compiler happy void update_values_battery() {} diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 839c0335..6e4ea6b1 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1252,9 +1252,8 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.system.status.battery_allows_contactor_closing = true; #ifdef TESLA_MODEL_SX_BATTERY // Always use NCM/A mode on S/X packs - strncpy(datalayer.system.info.battery_protocol, "Tesla Model S/X", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Tesla Model S/X", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM; @@ -1270,9 +1269,8 @@ void setup_battery(void) { // Performs one time setup at startup #endif // TESLA_MODEL_SX_BATTERY #ifdef TESLA_MODEL_3Y_BATTERY // Model 3/Y can be either LFP or NCM/A - strncpy(datalayer.system.info.battery_protocol, "Tesla Model 3/Y", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Tesla Model 3/Y", 63); + datalayer.system.info.battery_protocol[63] = '\0'; #ifdef LFP_CHEMISTRY datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP; diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index bb49e0a2..e69ddfb2 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -145,9 +145,8 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup randomSeed(analogRead(0)); - strncpy(datalayer.system.info.battery_protocol, "Fake battery for testing purposes", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Fake battery for testing purposes", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index e94e8069..839665c8 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -332,9 +332,8 @@ void send_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Volvo / Polestar 78kWh battery", - sizeof(datalayer.system.info.battery_protocol) - 1); - datalayer.system.info.battery_protocol[sizeof(datalayer.system.info.battery_protocol) - 1] = '\0'; + strncpy(datalayer.system.info.battery_protocol, "Volvo / Polestar 78kWh battery", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index b6de87a0..5c2cb2c1 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -487,33 +487,6 @@ String processor(const String& var) { // Display which components are used content += "

Inverter protocol: "; content += datalayer.system.info.inverter_protocol; -#ifdef BYD_CAN - content += "BYD Battery-Box Premium HVS over CAN Bus"; -#endif // BYD_CAN -#ifdef BYD_MODBUS - content += "BYD 11kWh HVM battery over Modbus RTU"; -#endif // BYD_MODBUS -#ifdef FOXESS_CAN - content += "FoxESS compatible HV2600/ECS4100 battery"; -#endif // FOXESS_CAN -#ifdef PYLON_CAN - content += "Pylontech battery over CAN bus"; -#endif // PYLON_CAN -#ifdef PYLON_LV_CAN - content += "Pylontech LV battery over CAN bus"; -#endif // PYLON_LV_CAN -#ifdef SERIAL_LINK_TRANSMITTER - content += "Serial link to another LilyGo board"; -#endif // SERIAL_LINK_TRANSMITTER -#ifdef SMA_CAN - content += "BYD Battery-Box H 8.9kWh, 7 mod over CAN bus"; -#endif // SMA_CAN -#ifdef SOFAR_CAN - content += "Sofar Energy Storage Inverter High Voltage BMS General Protocol (Extended Frame) over CAN bus"; -#endif // SOFAR_CAN -#ifdef SOLAX_CAN - content += "SolaX Triple Power LFP over CAN bus"; -#endif // SOLAX_CAN content += "

"; content += "

Battery protocol: "; content += datalayer.system.info.battery_protocol; diff --git a/Software/src/inverter/AFORE-CAN.cpp b/Software/src/inverter/AFORE-CAN.cpp index 74435116..a8d551d7 100644 --- a/Software/src/inverter/AFORE-CAN.cpp +++ b/Software/src/inverter/AFORE-CAN.cpp @@ -233,4 +233,8 @@ void send_can_inverter() { time_to_send_info = false; } } +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "Afore battery over CAN", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/AFORE-CAN.h b/Software/src/inverter/AFORE-CAN.h index cc9f8548..9829befc 100644 --- a/Software/src/inverter/AFORE-CAN.h +++ b/Software/src/inverter/AFORE-CAN.h @@ -4,8 +4,7 @@ #define CAN_INVERTER_SELECTED -void send_system_data(); -void send_setup_info(); void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index ae0bb560..e11de744 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -219,4 +219,8 @@ void send_intial_data() { transmit_can(&BYD_3D0_2, can_config.inverter); transmit_can(&BYD_3D0_3, can_config.inverter); } +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box Premium HVS over CAN Bus", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index 6a45317b..5a90d6ba 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -8,5 +8,6 @@ void send_intial_data(); void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/BYD-MODBUS.cpp b/Software/src/inverter/BYD-MODBUS.cpp index 7cee6b8d..814e24e4 100644 --- a/Software/src/inverter/BYD-MODBUS.cpp +++ b/Software/src/inverter/BYD-MODBUS.cpp @@ -143,4 +143,8 @@ void verify_inverter_modbus() { history_index = (history_index + 1) % HISTORY_LENGTH; } } +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "BYD 11kWh HVM battery over Modbus RTU", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/BYD-MODBUS.h b/Software/src/inverter/BYD-MODBUS.h index 3d014daa..487c9784 100644 --- a/Software/src/inverter/BYD-MODBUS.h +++ b/Software/src/inverter/BYD-MODBUS.h @@ -14,4 +14,5 @@ void verify_temperature_modbus(); void verify_inverter_modbus(); void handle_update_data_modbusp201_byd(); void handle_update_data_modbusp301_byd(); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/BYD-SMA.cpp b/Software/src/inverter/BYD-SMA.cpp index 230b61e7..34e33063 100644 --- a/Software/src/inverter/BYD-SMA.cpp +++ b/Software/src/inverter/BYD-SMA.cpp @@ -251,4 +251,10 @@ void send_can_inverter() { } } } +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box HVS over SMA CAN", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; + datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first + pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); +} #endif diff --git a/Software/src/inverter/BYD-SMA.h b/Software/src/inverter/BYD-SMA.h index b71a60fa..e787191d 100644 --- a/Software/src/inverter/BYD-SMA.h +++ b/Software/src/inverter/BYD-SMA.h @@ -8,5 +8,6 @@ #define STOP_STATE 0x02 void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/FOXESS-CAN.cpp b/Software/src/inverter/FOXESS-CAN.cpp index e4b3b34c..e23f9006 100644 --- a/Software/src/inverter/FOXESS-CAN.cpp +++ b/Software/src/inverter/FOXESS-CAN.cpp @@ -737,4 +737,8 @@ void receive_can_inverter(CAN_frame rx_frame) { } } } +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "FoxESS compatible HV2600/ECS4100 battery", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/FOXESS-CAN.h b/Software/src/inverter/FOXESS-CAN.h index d9a3da2d..365a559d 100644 --- a/Software/src/inverter/FOXESS-CAN.h +++ b/Software/src/inverter/FOXESS-CAN.h @@ -5,5 +5,6 @@ #define CAN_INVERTER_SELECTED void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/PYLON-CAN.cpp b/Software/src/inverter/PYLON-CAN.cpp index 2b8e036c..2145b3e7 100644 --- a/Software/src/inverter/PYLON-CAN.cpp +++ b/Software/src/inverter/PYLON-CAN.cpp @@ -477,4 +477,8 @@ void send_system_data() { //System equipment information transmit_can(&PYLON_4291, can_config.inverter); #endif } +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "Pylontech battery over CAN bus", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/PYLON-CAN.h b/Software/src/inverter/PYLON-CAN.h index 86bb4afa..6b39afcd 100644 --- a/Software/src/inverter/PYLON-CAN.h +++ b/Software/src/inverter/PYLON-CAN.h @@ -7,5 +7,6 @@ void send_system_data(); void send_setup_info(); void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/PYLON-LV-CAN.cpp b/Software/src/inverter/PYLON-LV-CAN.cpp index 458ac7a0..e5eb2e87 100644 --- a/Software/src/inverter/PYLON-LV-CAN.cpp +++ b/Software/src/inverter/PYLON-LV-CAN.cpp @@ -133,4 +133,8 @@ void send_can_inverter() { transmit_can(&PYLON_35E, can_config.inverter); } } +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "Pylontech LV battery over CAN bus", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/PYLON-LV-CAN.h b/Software/src/inverter/PYLON-LV-CAN.h index 45376d2b..ca6922eb 100644 --- a/Software/src/inverter/PYLON-LV-CAN.h +++ b/Software/src/inverter/PYLON-LV-CAN.h @@ -12,5 +12,6 @@ void send_system_data(); void send_setup_info(); void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp index 6d3b5071..aa0a7ec4 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp @@ -159,6 +159,10 @@ void printSendingValues() { Serial.print(datalayer.battery.status.soh_pptt); Serial.print(" Voltage: "); Serial.print(datalayer.battery.status.voltage_dV); + void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "Serial link to another LilyGo board", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; + } Serial.print(" Current: "); Serial.print(datalayer.battery.status.current_dA); Serial.print(" Capacity: "); @@ -190,4 +194,8 @@ void printSendingValues() { Serial.println(""); } +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "Serial link to another LilyGo board", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h index 14ae08d7..1637e6bd 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h @@ -6,5 +6,6 @@ #include "../lib/mackelec-SerialDataLink/SerialDataLink.h" void manageSerialLinkTransmitter(); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/SMA-CAN.cpp b/Software/src/inverter/SMA-CAN.cpp index cecae60c..5831406d 100644 --- a/Software/src/inverter/SMA-CAN.cpp +++ b/Software/src/inverter/SMA-CAN.cpp @@ -249,4 +249,9 @@ void send_can_inverter() { } } } + +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "SMA CAN", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/SMA-CAN.h b/Software/src/inverter/SMA-CAN.h index 73b9f160..111044a4 100644 --- a/Software/src/inverter/SMA-CAN.h +++ b/Software/src/inverter/SMA-CAN.h @@ -8,5 +8,6 @@ #define STOP_STATE 0x02 void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 9c0cc279..7a242dae 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -320,4 +320,9 @@ void send_tripower_init() { transmit_can(&SMA_017, can_config.inverter); // Battery Manufacturer transmit_can(&SMA_018, can_config.inverter); // Battery Name } + +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "SMA Tripower CAN", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index e12692da..90967001 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -6,5 +6,6 @@ void send_tripower_init(); void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/SOFAR-CAN.cpp b/Software/src/inverter/SOFAR-CAN.cpp index eb13b7c5..838ebf93 100644 --- a/Software/src/inverter/SOFAR-CAN.cpp +++ b/Software/src/inverter/SOFAR-CAN.cpp @@ -263,4 +263,9 @@ void send_can_inverter() { transmit_can(&SOFAR_35A, can_config.inverter); } } + +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "Sofar BMS (Extended Frame) over CAN bus", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} #endif diff --git a/Software/src/inverter/SOFAR-CAN.h b/Software/src/inverter/SOFAR-CAN.h index 6d43222f..7a80bf62 100644 --- a/Software/src/inverter/SOFAR-CAN.h +++ b/Software/src/inverter/SOFAR-CAN.h @@ -5,5 +5,6 @@ #define CAN_INVERTER_SELECTED void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp index 790c8524..9bef56ec 100644 --- a/Software/src/inverter/SOLAX-CAN.cpp +++ b/Software/src/inverter/SOLAX-CAN.cpp @@ -252,4 +252,9 @@ void receive_can_inverter(CAN_frame rx_frame) { #endif } } +void setup_inverter(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.inverter_protocol, "SolaX Triple Power LFP over CAN bus", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; + datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first +} #endif diff --git a/Software/src/inverter/SOLAX-CAN.h b/Software/src/inverter/SOLAX-CAN.h index 6ad461a7..68373ec2 100644 --- a/Software/src/inverter/SOLAX-CAN.h +++ b/Software/src/inverter/SOLAX-CAN.h @@ -15,5 +15,6 @@ #define UPDATING_FW 4 void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); #endif From 3b546d1466bf623e157a99b3845840eb033876da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 21:24:49 +0200 Subject: [PATCH 45/48] Add all inv/bat to Github workflow --- .github/workflows/compile-all-batteries.yml | 13 ++++++------- .github/workflows/compile-all-inverters.yml | 2 ++ Software/src/devboard/webserver/webserver.cpp | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index 1cd8955e..287b75f2 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -34,19 +34,25 @@ jobs: # These are the batteries for which the code will be compiled. battery: - BMW_I3_BATTERY + - BMW_IX_BATTERY - BYD_ATTO_3_BATTERY - CELLPOWER_BMS - CHADEMO_BATTERY - IMIEV_CZERO_ION_BATTERY - JAGUAR_IPACE_BATTERY - KIA_HYUNDAI_64_BATTERY + - KIA_E_GMP_BATTERY - KIA_HYUNDAI_HYBRID_BATTERY + - MG_5_BATTERY - NISSAN_LEAF_BATTERY - PYLON_BATTERY - RJXZS_BMS + - RANGE_ROVER_PHEV_BATTERY - RENAULT_KANGOO_BATTERY + - RENAULT_TWIZY_BATTERY - RENAULT_ZOE_GEN1_BATTERY - RENAULT_ZOE_GEN2_BATTERY + - SANTA_FE_PHEV_BATTERY - TESLA_MODEL_3Y_BATTERY - VOLVO_SPA_BATTERY - TEST_FAKE_BATTERY @@ -54,13 +60,6 @@ jobs: # These are the emulated inverter communication protocols for which the code will be compiled. inverter: - BYD_CAN -# - BYD_MODBUS -# - PYLON_CAN -# - SMA_CAN -# - SMA_TRIPOWER_CAN -# - SOFAR_CAN -# - SOLAX_CAN - # This is the platform GitHub will use to run our workflow. runs-on: ubuntu-latest diff --git a/.github/workflows/compile-all-inverters.yml b/.github/workflows/compile-all-inverters.yml index 85beb384..deb0ccc9 100644 --- a/.github/workflows/compile-all-inverters.yml +++ b/.github/workflows/compile-all-inverters.yml @@ -42,10 +42,12 @@ jobs: # - TESLA_MODEL_3Y_BATTERY # These are the emulated inverter communication protocols for which the code will be compiled. inverter: + - AFORE_CAN - BYD_CAN - BYD_SMA - BYD_MODBUS - FOXESS_CAN + - PYLON_LV_CAN - PYLON_CAN - SMA_CAN - SMA_TRIPOWER_CAN diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 5c2cb2c1..b7e36273 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -492,10 +492,10 @@ String processor(const String& var) { content += datalayer.system.info.battery_protocol; #ifdef DOUBLE_BATTERY content += " (Double battery)"; +#endif // DOUBLE_BATTERY if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { content += " (LFP)"; } -#endif // DOUBLE_BATTERY content += "

"; #if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER From 0b278034d419f3e73a3b788ee027c79925621882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 22:25:10 +0200 Subject: [PATCH 46/48] Remove compilation error, runtime event catches egmp CAN-FD --- Software/Software.ino | 25 +++++-------------- Software/src/include.h | 6 ----- .../SERIAL-LINK-TRANSMITTER-INVERTER.h | 2 ++ 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 303442a8..957d4537 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -70,13 +70,11 @@ volatile bool send_ok = 0; static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT); static ACAN2515_Buffer16 gBuffer; -#endif +#endif //DUAL_CAN #ifdef CAN_FD #include "src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); -#else -typedef char CANFDMessage; -#endif +#endif //CAN_FD // ModbusRTU parameters #ifdef MODBUS_INVERTER_SELECTED @@ -172,11 +170,10 @@ void setup() { init_rs485(); init_serialDataLink(); - - init_inverter(); - - init_battery(); - +#if defined(CAN_INVERTER_SELECTED) || defined(MODBUS_INVERTER_SELECTED) + setup_inverter(); +#endif + setup_battery(); #ifdef EQUIPMENT_STOP_BUTTON init_equipment_stop_button(); #endif @@ -554,16 +551,6 @@ void init_rs485() { #endif } -void init_inverter() { - // Inform user what inverter is used and perform setup - setup_inverter(); -} - -void init_battery() { - // Inform user what battery is used and perform setup - setup_battery(); -} - #ifdef EQUIPMENT_STOP_BUTTON void monitor_equipment_stop_button() { diff --git a/Software/src/include.h b/Software/src/include.h index 83f2290d..b29345e6 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -45,10 +45,4 @@ #error No battery selected! Choose one from the USER_SETTINGS.h file #endif -#ifdef KIA_E_GMP_BATTERY -#ifndef CAN_FD -#error KIA HYUNDAI EGMP BATTERIES CANNOT BE USED WITHOUT CAN FD -#endif -#endif - #endif diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h index 1637e6bd..487ca103 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h @@ -1,6 +1,8 @@ #ifndef SERIAL_LINK_TRANSMITTER_INVERTER_H #define SERIAL_LINK_TRANSMITTER_INVERTER_H +#define MODBUS_INVERTER_SELECTED + #include #include "../include.h" #include "../lib/mackelec-SerialDataLink/SerialDataLink.h" From a537b7ff1b9060b69a95169381265788c03392d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 22:33:35 +0200 Subject: [PATCH 47/48] Fix compilation issue for seriallink --- .../src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp | 10 ++-------- .../src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h | 2 -- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp index aa0a7ec4..a61ea7dc 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp @@ -128,6 +128,8 @@ void manageSerialLinkTransmitter() { static unsigned long updateDataTime = 0; if (currentTime - updateDataTime > INTERVAL_1_S) { + strncpy(datalayer.system.info.inverter_protocol, "Serial link to another LilyGo board", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; updateDataTime = currentTime; dataLinkTransmit.updateData(0, datalayer.battery.status.real_soc); dataLinkTransmit.updateData(1, datalayer.battery.status.soh_pptt); @@ -159,10 +161,6 @@ void printSendingValues() { Serial.print(datalayer.battery.status.soh_pptt); Serial.print(" Voltage: "); Serial.print(datalayer.battery.status.voltage_dV); - void setup_inverter(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Serial link to another LilyGo board", 63); - datalayer.system.info.inverter_protocol[63] = '\0'; - } Serial.print(" Current: "); Serial.print(datalayer.battery.status.current_dA); Serial.print(" Capacity: "); @@ -194,8 +192,4 @@ void printSendingValues() { Serial.println(""); } -void setup_inverter(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Serial link to another LilyGo board", 63); - datalayer.system.info.inverter_protocol[63] = '\0'; -} #endif diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h index 487ca103..1637e6bd 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h @@ -1,8 +1,6 @@ #ifndef SERIAL_LINK_TRANSMITTER_INVERTER_H #define SERIAL_LINK_TRANSMITTER_INVERTER_H -#define MODBUS_INVERTER_SELECTED - #include #include "../include.h" #include "../lib/mackelec-SerialDataLink/SerialDataLink.h" From 5d9105d9a85dd6c36f874b770b2c7e725fc21bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 22:54:19 +0200 Subject: [PATCH 48/48] Add more BYD inverter mappings --- Software/src/inverter/BYD-CAN.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index ae0bb560..58dc00e4 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -76,6 +76,8 @@ static uint8_t inverter_name[7] = {0}; static int16_t temperature_average = 0; static uint16_t inverter_voltage = 0; static uint16_t inverter_SOC = 0; +static int16_t inverter_current = 0; +static int16_t inverter_temperature = 0; static uint16_t remaining_capacity_ah = 0; static uint16_t fully_charged_capacity_ah = 0; static long inverter_timestamp = 0; @@ -165,6 +167,8 @@ void receive_can_inverter(CAN_frame rx_frame) { case 0x091: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; inverter_voltage = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]) * 0.1; + inverter_current = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]) * 0.1; + inverter_temperature = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 0.1; break; case 0x0D1: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;