From aa49fb10615c60cf5b63c7cb4e063ca3ba4d7107 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Fri, 4 Jul 2025 22:54:45 +0300 Subject: [PATCH] Eliminate BMW IX extended datalayer --- Software/src/battery/BMW-IX-BATTERY.cpp | 101 ++++++++------- Software/src/battery/BMW-IX-BATTERY.h | 26 +++- Software/src/battery/BMW-IX-HTML.cpp | 120 ++++++++++++++++++ Software/src/battery/BMW-IX-HTML.h | 128 ++------------------ Software/src/datalayer/datalayer_extended.h | 29 ----- 5 files changed, 208 insertions(+), 196 deletions(-) create mode 100644 Software/src/battery/BMW-IX-HTML.cpp diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 74797509..434dc3d6 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -101,36 +101,6 @@ void BmwIXBattery::update_values() { //This function maps all the values fetche datalayer.battery.info.number_of_cells = detected_number_of_cells; - 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; - - 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; - - 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; @@ -493,30 +463,26 @@ void BmwIXBattery::HandleIncomingUserRequest(void) { // Debug user request to open or close the contactors #ifdef DEBUG_LOG logging.print("User request: contactor close: "); - logging.print(datalayer_extended.bmwix.UserRequestContactorClose); + logging.print(userRequestContactorClose); logging.print(" User request: contactor open: "); - logging.println(datalayer_extended.bmwix.UserRequestContactorOpen); + logging.println(userRequestContactorOpen); #endif // DEBUG_LOG - if ((datalayer_extended.bmwix.UserRequestContactorClose == false) && - (datalayer_extended.bmwix.UserRequestContactorOpen == false)) { + if ((userRequestContactorClose == false) && (userRequestContactorOpen == false)) { // do nothing - } else if ((datalayer_extended.bmwix.UserRequestContactorClose == true) && - (datalayer_extended.bmwix.UserRequestContactorOpen == false)) { + } else if ((userRequestContactorClose == true) && (userRequestContactorOpen == false)) { BmwIxCloseContactors(); // set user request to false - datalayer_extended.bmwix.UserRequestContactorClose = false; - } else if ((datalayer_extended.bmwix.UserRequestContactorClose == false) && - (datalayer_extended.bmwix.UserRequestContactorOpen == true)) { + userRequestContactorClose = false; + } else if ((userRequestContactorClose == false) && (userRequestContactorOpen == true)) { BmwIxOpenContactors(); // set user request to false - datalayer_extended.bmwix.UserRequestContactorOpen = false; - } else if ((datalayer_extended.bmwix.UserRequestContactorClose == true) && - (datalayer_extended.bmwix.UserRequestContactorOpen == true)) { + userRequestContactorOpen = false; + } else if ((userRequestContactorClose == true) && (userRequestContactorOpen == true)) { // these flasgs should not be true at the same time, therefore open contactors, as that is the safest state BmwIxOpenContactors(); // set user request to false - datalayer_extended.bmwix.UserRequestContactorClose = false; - datalayer_extended.bmwix.UserRequestContactorOpen = false; + userRequestContactorClose = false; + userRequestContactorOpen = false; // print error, as both these flags shall not be true at the same time #ifdef DEBUG_LOG logging.println( @@ -695,3 +661,50 @@ void BmwIXBattery::HandleBmwIxOpenContactorsRequest(uint16_t counter_10ms) { } } } + +// Getter implementations for HTML renderer +int BmwIXBattery::get_battery_voltage_after_contactor() const { + return battery_voltage_after_contactor; +} +unsigned long BmwIXBattery::get_min_cell_voltage_data_age() const { + return millis() - min_cell_voltage_lastchanged; +} +unsigned long BmwIXBattery::get_max_cell_voltage_data_age() const { + return millis() - max_cell_voltage_lastchanged; +} +int BmwIXBattery::get_T30_Voltage() const { + return terminal30_12v_voltage; +} +int BmwIXBattery::get_balancing_status() const { + return balancing_status; +} +int BmwIXBattery::get_hvil_status() const { + return hvil_status; +} +unsigned long BmwIXBattery::get_bms_uptime() const { + return sme_uptime; +} +int BmwIXBattery::get_allowable_charge_amps() const { + return allowable_charge_amps; +} +int BmwIXBattery::get_allowable_discharge_amps() const { + return allowable_discharge_amps; +} +int BmwIXBattery::get_iso_safety_positive() const { + return iso_safety_positive; +} +int BmwIXBattery::get_iso_safety_negative() const { + return iso_safety_negative; +} +int BmwIXBattery::get_iso_safety_parallel() const { + return iso_safety_parallel; +} +int BmwIXBattery::get_pyro_status_pss1() const { + return pyro_status_pss1; +} +int BmwIXBattery::get_pyro_status_pss4() const { + return pyro_status_pss4; +} +int BmwIXBattery::get_pyro_status_pss6() const { + return pyro_status_pss6; +} diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index f7ef924a..af11a73e 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -11,6 +11,8 @@ class BmwIXBattery : public CanBattery { public: + BmwIXBattery() : renderer(*this) {} + virtual void setup(void); virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); @@ -19,12 +21,32 @@ class BmwIXBattery : public CanBattery { bool supports_contactor_close() { return true; } - void request_open_contactors() { datalayer_extended.bmwix.UserRequestContactorOpen = true; } - void request_close_contactors() { datalayer_extended.bmwix.UserRequestContactorClose = true; } + void request_open_contactors() { userRequestContactorOpen = true; } + void request_close_contactors() { userRequestContactorClose = true; } static constexpr const char* Name = "BMW iX and i4-7 platform"; + // Getter methods for HTML renderer + int get_battery_voltage_after_contactor() const; + unsigned long get_min_cell_voltage_data_age() const; + unsigned long get_max_cell_voltage_data_age() const; + int get_T30_Voltage() const; + int get_balancing_status() const; + int get_hvil_status() const; + unsigned long get_bms_uptime() const; + int get_allowable_charge_amps() const; + int get_allowable_discharge_amps() const; + int get_iso_safety_positive() const; + int get_iso_safety_negative() const; + int get_iso_safety_parallel() const; + int get_pyro_status_pss1() const; + int get_pyro_status_pss4() const; + int get_pyro_status_pss6() const; + private: + bool userRequestContactorClose = false; + bool userRequestContactorOpen = false; + BmwIXHtmlRenderer renderer; static const int MAX_PACK_VOLTAGE_DV = 4650; //4650 = 465.0V static const int MIN_PACK_VOLTAGE_DV = 3000; diff --git a/Software/src/battery/BMW-IX-HTML.cpp b/Software/src/battery/BMW-IX-HTML.cpp new file mode 100644 index 00000000..60802c49 --- /dev/null +++ b/Software/src/battery/BMW-IX-HTML.cpp @@ -0,0 +1,120 @@ +#include "BMW-IX-HTML.h" +#include "../include.h" +#include "BMW-IX-BATTERY.h" + +String BmwIXHtmlRenderer::get_status_html() { + String content; + + content += "

Battery Voltage after Contactor: " + String(batt.get_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(batt.get_min_cell_voltage_data_age()) + " ms

"; + content += "

Max Cell Voltage Data Age: " + String(batt.get_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(batt.get_T30_Voltage()) + " mV

"; + content += "

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

"; + content += "

Balancing: "; + switch (batt.get_balancing_status()) { + case 0: + content += "0 No balancing mode active

"; + break; + case 1: + content += "1 Voltage-Controlled Balancing Mode"; + break; + case 2: + content += "2 Time-Controlled Balancing Mode with Demand Calculation at End of Charging"; + break; + case 3: + content += "3 Time-Controlled Balancing Mode with Demand Calculation at Resting Voltage"; + break; + case 4: + content += "4 No balancing mode active, qualifier invalid"; + break; + default: + content += "Unknown"; + } + content += "

HVIL Status: "; + switch (batt.get_hvil_status()) { + case 0: + content += "Error (Loop Open)

"; + break; + case 1: + content += "OK (Loop Closed)"; + break; + default: + content += "Unknown"; + } + content += "

BMS Uptime: " + String(batt.get_bms_uptime()) + " seconds

"; + content += "

BMS Allowed Charge Amps: " + String(batt.get_allowable_charge_amps()) + " A

"; + content += "

BMS Allowed Disharge Amps: " + String(batt.get_allowable_discharge_amps()) + " A

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

HV Isolation (2147483647kOhm = maximum/invalid)

"; + content += "

Isolation Positive: " + String(batt.get_iso_safety_positive()) + " kOhm

"; + content += "

Isolation Negative: " + String(batt.get_iso_safety_negative()) + " kOhm

"; + content += "

Isolation Parallel: " + String(batt.get_iso_safety_parallel()) + " kOhm

"; + content += "

Pyro Status PSS1: "; + switch (batt.get_pyro_status_pss1()) { + case 0: + content += "0 Value Invalid

"; + break; + case 1: + content += "1 Successfully Blown"; + break; + case 2: + content += "2 Disconnected"; + break; + case 3: + content += "3 Not Activated - Pyro Intact"; + break; + case 4: + content += "4 Unknown"; + break; + default: + content += "Unknown"; + } + content += "

Pyro Status PSS4: "; + switch (batt.get_pyro_status_pss4()) { + case 0: + content += "0 Value Invalid

"; + break; + case 1: + content += "1 Successfully Blown"; + break; + case 2: + content += "2 Disconnected"; + break; + case 3: + content += "3 Not Activated - Pyro Intact"; + break; + case 4: + content += "4 Unknown"; + break; + default: + content += "Unknown"; + } + content += "

Pyro Status PSS6: "; + switch (batt.get_pyro_status_pss6()) { + case 0: + content += "0 Value Invalid

"; + break; + case 1: + content += "1 Successfully Blown"; + break; + case 2: + content += "2 Disconnected"; + break; + case 3: + content += "3 Not Activated - Pyro Intact"; + break; + case 4: + content += "4 Unknown"; + break; + default: + content += "Unknown"; + } + + return content; +} diff --git a/Software/src/battery/BMW-IX-HTML.h b/Software/src/battery/BMW-IX-HTML.h index 27bd3d56..aada8182 100644 --- a/Software/src/battery/BMW-IX-HTML.h +++ b/Software/src/battery/BMW-IX-HTML.h @@ -2,132 +2,18 @@ #define _BMW_IX_HTML_H #include "../datalayer/datalayer.h" -#include "../datalayer/datalayer_extended.h" #include "src/devboard/webserver/BatteryHtmlRenderer.h" +class BmwIXBattery; + class BmwIXHtmlRenderer : public BatteryHtmlRenderer { + private: + BmwIXBattery& batt; + public: - String get_status_html() { - String content; + BmwIXHtmlRenderer(BmwIXBattery& b) : batt(b) {} - 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) + "

"; - content += "

Balancing: "; - switch (datalayer_extended.bmwix.balancing_status) { - case 0: - content += "0 No balancing mode active

"; - break; - case 1: - content += "1 Voltage-Controlled Balancing Mode"; - break; - case 2: - content += "2 Time-Controlled Balancing Mode with Demand Calculation at End of Charging"; - break; - case 3: - content += "3 Time-Controlled Balancing Mode with Demand Calculation at Resting Voltage"; - break; - case 4: - content += "4 No balancing mode active, qualifier invalid"; - break; - default: - content += "Unknown"; - } - content += "

HVIL Status: "; - switch (datalayer_extended.bmwix.hvil_status) { - case 0: - content += "Error (Loop Open)

"; - break; - case 1: - content += "OK (Loop Closed)"; - break; - default: - content += "Unknown"; - } - 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: "; - switch (datalayer_extended.bmwix.pyro_status_pss1) { - case 0: - content += "0 Value Invalid

"; - break; - case 1: - content += "1 Successfully Blown"; - break; - case 2: - content += "2 Disconnected"; - break; - case 3: - content += "3 Not Activated - Pyro Intact"; - break; - case 4: - content += "4 Unknown"; - break; - default: - content += "Unknown"; - } - content += "

Pyro Status PSS4: "; - switch (datalayer_extended.bmwix.pyro_status_pss4) { - case 0: - content += "0 Value Invalid

"; - break; - case 1: - content += "1 Successfully Blown"; - break; - case 2: - content += "2 Disconnected"; - break; - case 3: - content += "3 Not Activated - Pyro Intact"; - break; - case 4: - content += "4 Unknown"; - break; - default: - content += "Unknown"; - } - content += "

Pyro Status PSS6: "; - switch (datalayer_extended.bmwix.pyro_status_pss6) { - case 0: - content += "0 Value Invalid

"; - break; - case 1: - content += "1 Successfully Blown"; - break; - case 2: - content += "2 Disconnected"; - break; - case 3: - content += "3 Not Activated - Pyro Intact"; - break; - case 4: - content += "4 Unknown"; - break; - default: - content += "Unknown"; - } - - return content; - } + String get_status_html(); }; #endif diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index a78911c0..a758d400 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -40,34 +40,6 @@ typedef struct { int16_t battery_current_7E4 = 0; } DATALAYER_INFO_BOLTAMPERA; -typedef struct { - /** User requesting contactor open or close via WebUI*/ - bool UserRequestContactorClose = false; - bool UserRequestContactorOpen = false; - /** 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; - /** 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; - 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; - typedef struct { /** uint8_t */ /** Status isolation external, 0 not evaluated, 1 OK, 2 error active, 3 Invalid signal*/ @@ -851,7 +823,6 @@ typedef struct { class DataLayerExtended { public: DATALAYER_INFO_BOLTAMPERA boltampera; - DATALAYER_INFO_BMWIX bmwix; DATALAYER_INFO_BMWPHEV bmwphev; DATALAYER_INFO_BYDATTO3 bydAtto3; DATALAYER_INFO_CELLPOWER cellpower;