From 2b42641c6b859124e6acfb9e35cc96a769c8ef23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 28 Aug 2025 23:10:12 +0300 Subject: [PATCH 001/150] Correct SOH reading. Add all PIDs as comments. Add isolation resistance --- .../battery/HYUNDAI-IONIQ-28-BATTERY-HTML.cpp | 4 +- .../src/battery/HYUNDAI-IONIQ-28-BATTERY.cpp | 76 ++++++++++++++----- .../src/battery/HYUNDAI-IONIQ-28-BATTERY.h | 10 +-- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY-HTML.cpp b/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY-HTML.cpp index 819deeb4..3b013dc4 100644 --- a/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY-HTML.cpp +++ b/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY-HTML.cpp @@ -5,9 +5,7 @@ String HyundaiIoniq28BatteryHtmlRenderer::get_status_html() { String content; content += "

12V voltage: " + String(batt.get_lead_acid_voltage() / 10.0, 1) + "

"; content += "

Temperature, power relay: " + String(batt.get_power_relay_temperature()) + "

"; - content += "

Battery relay: " + String(batt.get_battery_relay_mode()) + "

"; content += "

Batterymanagement mode: " + String(batt.get_battery_management_mode()) + "

"; - content += "

BMS ignition: " + String(batt.get_battery_ignition_mode()) + "

"; - + content += "

Isolation resistance: " + String(batt.get_isolation_resistance()) + " kOhm

"; return content; } diff --git a/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.cpp b/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.cpp index c9b8cd4a..f89b7420 100644 --- a/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.cpp +++ b/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.cpp @@ -88,7 +88,11 @@ void HyundaiIoniq28Battery::handle_incoming_can_frame(CAN_frame rx_frame) { break; case 0x21: //First frame in PID group if (incoming_poll_group == 1) { //21 14 13 24 13 24 04 00 - batteryRelay = rx_frame.data.u8[7]; + //SOC = rx_frame.data.u8[1]; + //available_charge_power = 2 & 3 + //available_discharge_power = 4 & 5 + //status_bits? = 6 + //battery_current_highbyte = rx_frame.data.u8[7]; } else if (incoming_poll_group == 2) { //21 AD AD AD AD AD AD AC cellvoltages_mv[0] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[1] = (rx_frame.data.u8[2] * 20); @@ -113,11 +117,19 @@ void HyundaiIoniq28Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[68] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[69] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[70] = (rx_frame.data.u8[7] * 20); + } else if (incoming_poll_group == 5) { //21 0 0 0 0 0 0f0f + //battery_module_6_temperature = rx_frame.data.u8[6]; + //battery_module_7_temperature = rx_frame.data.u8[7]; } break; case 0x22: //Second datarow in PID group if (incoming_poll_group == 1) { //22 00 0C FF 17 16 17 17 - + //battery_current_lowbyte = rx_frame.data.u8[1]; + //battery_DC_voltage = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); + //battery_max_temperature = rx_frame.data.u8[4]; + //battery_min_temperature = rx_frame.data.u8[5]; + //battery_module_1_temperature = rx_frame.data.u8[6]; + //battery_module_2_temperature = rx_frame.data.u8[7]; } else if (incoming_poll_group == 2) { //22 AD AC AC AD AD AD AD cellvoltages_mv[7] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[8] = (rx_frame.data.u8[2] * 20); @@ -142,14 +154,26 @@ void HyundaiIoniq28Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[75] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[76] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[77] = (rx_frame.data.u8[7] * 20); + } else if (incoming_poll_group == 5) { //22 10 0d 0c 0e 0d 26 48 + //battery_module_8_temperature = rx_frame.data.u8[1]; + //battery_module_9_temperature = rx_frame.data.u8[2]; + //battery_module_10_temperature = rx_frame.data.u8[3]; + //battery_module_11_temperature = rx_frame.data.u8[4]; + //battery_module_12_temperature = rx_frame.data.u8[5]; + //available_charge_power = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); } else if (incoming_poll_group == 6) { batteryManagementMode = rx_frame.data.u8[5]; } break; - case 0x23: //Third datarow in PID group - if (incoming_poll_group == 1) { //23 17 17 17 00 17 AD 25 + case 0x23: //Third datarow in PID group + if (incoming_poll_group == 1) { //23 17 17 17 00 17 AD 25 + //battery_module_3_temperature = rx_frame.data.u8[1]; + //battery_module_4_temperature = rx_frame.data.u8[2]; + //battery_module_5_temperature = rx_frame.data.u8[3]; + //battery_inlet_temperature = rx_frame.data.u8[5]; CellVoltMax_mV = (rx_frame.data.u8[6] * 20); //(volts *50) *20 =mV - } else if (incoming_poll_group == 2) { //23 AD AD AD AD AB AD AD + //cellmaxvoltage_number = rx_frame.data.u8[7]; + } else if (incoming_poll_group == 2) { //23 AD AD AD AD AB AD AD cellvoltages_mv[14] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[15] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[16] = (rx_frame.data.u8[3] * 20); @@ -174,13 +198,22 @@ void HyundaiIoniq28Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[83] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[84] = (rx_frame.data.u8[7] * 20); } else if (incoming_poll_group == 5) { - heatertemp = rx_frame.data.u8[7]; + //available_discharge_power = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + //battery_cell_mV_deviation = rx_frame.data.u8[3]; + //airbag_h/wire_duty = rx_frame.data.u8[5]; + heatertemperature_1 = rx_frame.data.u8[6]; + heatertemperature_2 = rx_frame.data.u8[7]; } break; case 0x24: //Fourth datarow in PID group if (incoming_poll_group == 1) { //24 AA 4F 00 00 77 00 14 CellVoltMin_mV = (rx_frame.data.u8[1] * 20); //(volts *50) *20 =mV - } else if (incoming_poll_group == 2) { //24 AD AD AD AD AD AD AB + //mincellvoltage_number = rx_frame.data.u8[2]; + //fan_status = rx_frame.data.u8[3]; + //fan_feedback_signal = rx_frame.data.u8[4]; + //aux_battery_voltage = rx_frame.data.u8[5]; + //cumulative_charge_current_highbyte = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + } else if (incoming_poll_group == 2) { //24 AD AD AD AD AD AD AB cellvoltages_mv[21] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[22] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[23] = (rx_frame.data.u8[3] * 20); @@ -204,13 +237,19 @@ void HyundaiIoniq28Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[89] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[90] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[91] = (rx_frame.data.u8[7] * 20); - } else if (incoming_poll_group == 5) { - batterySOH = ((rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3]); + } else if (incoming_poll_group == 5) { //24 3 e8 5 3 e8 m34 6e + batterySOH = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + //max_deterioration_cell_number = rx_frame.data.u8[3] + //min_deterioration = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + //min_deterioration_cell_number = rx_frame.data.u8[6] + //SOC_display = rx_frame.data.u8[7] } break; case 0x25: //Fifth datarow in PID group if (incoming_poll_group == 1) { //25 5C A9 00 14 5F D3 00 - + //cumulative_charge_current_lowbyte = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + //cumulative_discharge_current = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[4] << 16) | (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); + //cumulative_charge_energy_highbyte = rx_frame.data.u8[7]; } else if (incoming_poll_group == 2) { //25 AD AD AD AD 00 00 00 cellvoltages_mv[28] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[29] = (rx_frame.data.u8[2] * 20); @@ -231,19 +270,22 @@ void HyundaiIoniq28Battery::handle_incoming_can_frame(CAN_frame rx_frame) { break; case 0x26: //Sixth datarow in PID group if (incoming_poll_group == 1) { //26 07 84 F9 00 07 42 8F + //cumulative_charge_energy_lowbyte = (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); + //cumulative_discharge_energy = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); } else if (incoming_poll_group == 5) { } break; case 0x27: //Seventh datarow in PID group if (incoming_poll_group == 1) { //27 03 3F A1 EB 00 19 99 - BMS_ign = rx_frame.data.u8[6]; - inverterVoltageFrameHigh = rx_frame.data.u8[7]; + //cumulative_operating_time = ((rx_frame.data.u8[1] << 24) | (rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + //bitfield (41 off, 45 car on) = rx_frame.data.u8[5]; + inverterVoltage = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); } break; case 0x28: //Eighth datarow in PID group if (incoming_poll_group == 1) { //28 7F FF 7F FF 03 E8 00 - inverterVoltage = (inverterVoltageFrameHigh << 8) + rx_frame.data.u8[1]; + isolation_resistance = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); } break; } @@ -378,10 +420,6 @@ uint8_t HyundaiIoniq28Battery::get_battery_management_mode() const { return batteryManagementMode; } -uint8_t HyundaiIoniq28Battery::get_battery_ignition_mode() const { - return BMS_ign; -} - -uint8_t HyundaiIoniq28Battery::get_battery_relay_mode() const { - return batteryRelay; +uint16_t HyundaiIoniq28Battery::get_isolation_resistance() const { + return isolation_resistance; } diff --git a/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.h b/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.h index 313915d5..4409e52c 100644 --- a/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.h +++ b/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.h @@ -25,10 +25,9 @@ class HyundaiIoniq28Battery : public CanBattery { // Getter methods for HTML renderer uint16_t get_lead_acid_voltage() const; + uint16_t get_isolation_resistance() const; int16_t get_power_relay_temperature() const; uint8_t get_battery_management_mode() const; - uint8_t get_battery_ignition_mode() const; - uint8_t get_battery_relay_mode() const; private: HyundaiIoniq28BatteryHtmlRenderer renderer; @@ -53,18 +52,17 @@ class HyundaiIoniq28Battery : public CanBattery { uint16_t allowedDischargePower = 0; uint16_t allowedChargePower = 0; uint16_t batteryVoltage = 3700; - uint16_t inverterVoltageFrameHigh = 0; uint16_t inverterVoltage = 0; + uint16_t isolation_resistance = 1000; uint16_t cellvoltages_mv[96]; uint16_t leadAcidBatteryVoltage = 120; int16_t batteryAmps = 0; int16_t temperatureMax = 0; int16_t temperatureMin = 0; uint8_t batteryManagementMode = 0; - uint8_t BMS_ign = 0; - uint8_t batteryRelay = 0; uint8_t counter_200 = 0; - int8_t heatertemp = 0; + int8_t heatertemperature_1 = 0; + int8_t heatertemperature_2 = 0; int8_t powerRelayTemperature = 0; bool startedUp = false; uint8_t incoming_poll_group = 0xFF; From 36493a89ccd69ef72dc7290695eb62bfc84d2e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 31 Aug 2025 17:50:26 +0300 Subject: [PATCH 002/150] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c6872409..e18215ba 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![GitHub release (with filter)](https://img.shields.io/github/v/release/dalathegreat/BYD-Battery-Emulator-For-Gen24?color=%23008000) ![GitHub Repo stars](https://img.shields.io/github/stars/dalathegreat/Battery-Emulator?style=flat&color=%23128512) ![GitHub forks](https://img.shields.io/github/forks/dalathegreat/Battery-Emulator?style=flat&color=%23128512) -![GitHub actions](https://img.shields.io/github/actions/workflow/status/dalathegreat/BYD-Battery-Emulator-For-Gen24/compile-common-image-lilygo.yml?color=0E810E) +![GitHub actions](https://img.shields.io/github/actions/workflow/status/dalathegreat/BYD-Battery-Emulator-For-Gen24/compile-common-image-lilygo-TCAN.yml?color=0E810E) ![Static Badge](https://img.shields.io/badge/made-with_love-blue?color=%23008000) ## What is Battery Emulator? From d38a8d6655fdd039568c788d431a3c5eded7ed44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 31 Aug 2025 17:50:51 +0300 Subject: [PATCH 003/150] Update Software.ino --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index 9367bedf..71cf186c 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -41,7 +41,7 @@ volatile unsigned long long bmsResetTimeOffset = 0; // The current software version, shown on webserver -const char* version_number = "9.0.RC4"; +const char* version_number = "9.0.RC5experimental"; // Interval timers volatile unsigned long currentMillis = 0; From dc4aa951098032d01d5753687c620e24da265241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 31 Aug 2025 21:57:41 +0300 Subject: [PATCH 004/150] Remove broken NTP BMS reset functionality --- Software/Software.ino | 14 -- Software/USER_SETTINGS.cpp | 8 - Software/USER_SETTINGS.h | 2 - Software/src/devboard/utils/events.cpp | 7 - Software/src/devboard/utils/events.h | 204 +++++++++++------------ Software/src/devboard/utils/ntp_time.cpp | 64 ------- Software/src/devboard/utils/ntp_time.h | 12 -- 7 files changed, 101 insertions(+), 210 deletions(-) delete mode 100644 Software/src/devboard/utils/ntp_time.cpp delete mode 100644 Software/src/devboard/utils/ntp_time.h diff --git a/Software/Software.ino b/Software/Software.ino index 71cf186c..bfd3ceab 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -35,11 +35,6 @@ #error You must select a target hardware in the USER_SETTINGS.h file! #endif -#ifdef PERIODIC_BMS_RESET_AT -#include "src/devboard/utils/ntp_time.h" -#endif -volatile unsigned long long bmsResetTimeOffset = 0; - // The current software version, shown on webserver const char* version_number = "9.0.RC5experimental"; @@ -152,15 +147,6 @@ void setup() { xTaskCreatePinnedToCore((TaskFunction_t)&core_loop, "core_loop", 4096, NULL, TASK_CORE_PRIO, &main_loop_task, esp32hal->CORE_FUNCTION_CORE()); -#ifdef PERIODIC_BMS_RESET_AT - bmsResetTimeOffset = getTimeOffsetfromNowUntil(PERIODIC_BMS_RESET_AT); - if (bmsResetTimeOffset == 0) { - set_event(EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED, 0); - } else { - set_event(EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS, 0); - } -#endif - DEBUG_PRINTF("setup() complete\n"); } diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index edf41a9a..1bc74643 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -71,11 +71,3 @@ volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of cha volatile float CHARGER_MAX_POWER = 3300; // Max power capable of charger, as a ceiling for validating config volatile float CHARGER_MAX_A = 11.5; // Max current output (amps) of charger volatile float CHARGER_END_A = 1.0; // Current at which charging is considered complete - -#ifdef PERIODIC_BMS_RESET_AT -// A list of rules for your zone can be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h -const char* time_zone = - "GMT0BST,M3.5.0/1,M10.5.0"; // TimeZone rule for Europe/London including daylight adjustment rules (optional) -const char* ntpServer1 = "pool.ntp.org"; -const char* ntpServer2 = "time.nist.gov"; -#endif diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 9a2a254d..bdef00da 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -90,8 +90,6 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! //#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF -// PERIODIC_BMS_RESET_AT Uses NTP server, internet required. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp -//#define PERIODIC_BMS_RESET_AT 525 /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 5085ff8a..19e877b3 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -125,8 +125,6 @@ void init_events(void) { events.entries[EVENT_EQUIPMENT_STOP].level = EVENT_LEVEL_ERROR; events.entries[EVENT_SD_INIT_FAILED].level = EVENT_LEVEL_WARNING; events.entries[EVENT_PERIODIC_BMS_RESET].level = EVENT_LEVEL_INFO; - events.entries[EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS].level = EVENT_LEVEL_INFO; - events.entries[EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED].level = EVENT_LEVEL_WARNING; events.entries[EVENT_BATTERY_TEMP_DEVIATION_HIGH].level = EVENT_LEVEL_WARNING; events.entries[EVENT_GPIO_CONFLICT].level = EVENT_LEVEL_ERROR; events.entries[EVENT_GPIO_NOT_DEFINED].level = EVENT_LEVEL_ERROR; @@ -365,11 +363,6 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { return "SD card initialization failed, check hardware. Power must be removed to reset the SD card."; case EVENT_PERIODIC_BMS_RESET: return "BMS Reset Event Completed."; - case EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS: - return "Successfully syncronised with the NTP Server. BMS will reset every 24 hours at defined time"; - case EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED: - return "Failed to syncronise with the NTP Server. BMS will reset every 24 hours from when the emulator was " - "powered on"; case EVENT_GPIO_CONFLICT: return "GPIO Pin Conflict: The pin used by '" + esp32hal->failed_allocator() + "' is already allocated by '" + esp32hal->conflicting_allocator() + "'. Please check your configuration and assign different pins."; diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 6b90cf44..8f85b13b 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -9,109 +9,107 @@ #define GENERATE_ENUM(ENUM) ENUM, #define GENERATE_STRING(STRING) #STRING, -#define EVENTS_ENUM_TYPE(XX) \ - XX(EVENT_CANMCP2517FD_INIT_FAILURE) \ - XX(EVENT_CANMCP2515_INIT_FAILURE) \ - XX(EVENT_CANFD_BUFFER_FULL) \ - XX(EVENT_CAN_BUFFER_FULL) \ - XX(EVENT_CAN_CORRUPTED_WARNING) \ - XX(EVENT_CAN_BATTERY_MISSING) \ - XX(EVENT_CAN_BATTERY2_MISSING) \ - XX(EVENT_CAN_CHARGER_MISSING) \ - XX(EVENT_CAN_INVERTER_MISSING) \ - XX(EVENT_CAN_NATIVE_TX_FAILURE) \ - XX(EVENT_CHARGE_LIMIT_EXCEEDED) \ - XX(EVENT_CONTACTOR_WELDED) \ - XX(EVENT_CONTACTOR_OPEN) \ - XX(EVENT_CPU_OVERHEATING) \ - XX(EVENT_CPU_OVERHEATED) \ - XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \ - XX(EVENT_WATER_INGRESS) \ - XX(EVENT_12V_LOW) \ - XX(EVENT_SOC_PLAUSIBILITY_ERROR) \ - XX(EVENT_SOC_UNAVAILABLE) \ - XX(EVENT_STALE_VALUE) \ - XX(EVENT_KWH_PLAUSIBILITY_ERROR) \ - XX(EVENT_BALANCING_START) \ - XX(EVENT_BALANCING_END) \ - XX(EVENT_BATTERY_EMPTY) \ - XX(EVENT_BATTERY_FULL) \ - XX(EVENT_BATTERY_FUSE) \ - XX(EVENT_BATTERY_FROZEN) \ - XX(EVENT_BATTERY_CAUTION) \ - XX(EVENT_BATTERY_CHG_STOP_REQ) \ - XX(EVENT_BATTERY_DISCHG_STOP_REQ) \ - XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \ - XX(EVENT_BATTERY_OVERHEAT) \ - XX(EVENT_BATTERY_OVERVOLTAGE) \ - XX(EVENT_BATTERY_UNDERVOLTAGE) \ - XX(EVENT_BATTERY_VALUE_UNAVAILABLE) \ - XX(EVENT_BATTERY_ISOLATION) \ - XX(EVENT_BATTERY_REQUESTS_HEAT) \ - XX(EVENT_BATTERY_WARMED_UP) \ - XX(EVENT_VOLTAGE_DIFFERENCE) \ - XX(EVENT_SOH_DIFFERENCE) \ - XX(EVENT_SOH_LOW) \ - XX(EVENT_HVIL_FAILURE) \ - XX(EVENT_PRECHARGE_FAILURE) \ - XX(EVENT_INTERNAL_OPEN_FAULT) \ - XX(EVENT_INVERTER_OPEN_CONTACTOR) \ - XX(EVENT_INTERFACE_MISSING) \ - XX(EVENT_MODBUS_INVERTER_MISSING) \ - XX(EVENT_NO_ENABLE_DETECTED) \ - XX(EVENT_ERROR_OPEN_CONTACTOR) \ - XX(EVENT_CELL_CRITICAL_UNDER_VOLTAGE) \ - XX(EVENT_CELL_CRITICAL_OVER_VOLTAGE) \ - XX(EVENT_CELL_UNDER_VOLTAGE) \ - XX(EVENT_CELL_OVER_VOLTAGE) \ - XX(EVENT_CELL_DEVIATION_HIGH) \ - XX(EVENT_UNKNOWN_EVENT_SET) \ - XX(EVENT_OTA_UPDATE) \ - XX(EVENT_OTA_UPDATE_TIMEOUT) \ - XX(EVENT_DUMMY_INFO) \ - XX(EVENT_DUMMY_DEBUG) \ - XX(EVENT_DUMMY_WARNING) \ - XX(EVENT_DUMMY_ERROR) \ - XX(EVENT_PERSISTENT_SAVE_INFO) \ - XX(EVENT_SERIAL_RX_WARNING) \ - XX(EVENT_SERIAL_RX_FAILURE) \ - XX(EVENT_SERIAL_TX_FAILURE) \ - XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \ - XX(EVENT_SMA_PAIRING) \ - XX(EVENT_TASK_OVERRUN) \ - XX(EVENT_RESET_UNKNOWN) \ - XX(EVENT_RESET_POWERON) \ - XX(EVENT_RESET_EXT) \ - XX(EVENT_RESET_SW) \ - XX(EVENT_RESET_PANIC) \ - XX(EVENT_RESET_INT_WDT) \ - XX(EVENT_RESET_TASK_WDT) \ - XX(EVENT_RESET_WDT) \ - XX(EVENT_RESET_DEEPSLEEP) \ - XX(EVENT_RESET_BROWNOUT) \ - XX(EVENT_RESET_SDIO) \ - XX(EVENT_RESET_USB) \ - XX(EVENT_RESET_JTAG) \ - XX(EVENT_RESET_EFUSE) \ - XX(EVENT_RESET_PWR_GLITCH) \ - XX(EVENT_RESET_CPU_LOCKUP) \ - XX(EVENT_RJXZS_LOG) \ - XX(EVENT_PAUSE_BEGIN) \ - XX(EVENT_PAUSE_END) \ - XX(EVENT_PID_FAILED) \ - XX(EVENT_WIFI_CONNECT) \ - XX(EVENT_WIFI_DISCONNECT) \ - XX(EVENT_MQTT_CONNECT) \ - XX(EVENT_MQTT_DISCONNECT) \ - XX(EVENT_EQUIPMENT_STOP) \ - XX(EVENT_AUTOMATIC_PRECHARGE_FAILURE) \ - XX(EVENT_SD_INIT_FAILED) \ - XX(EVENT_PERIODIC_BMS_RESET) \ - XX(EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS) \ - XX(EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED) \ - XX(EVENT_BATTERY_TEMP_DEVIATION_HIGH) \ - XX(EVENT_GPIO_NOT_DEFINED) \ - XX(EVENT_GPIO_CONFLICT) \ +#define EVENTS_ENUM_TYPE(XX) \ + XX(EVENT_CANMCP2517FD_INIT_FAILURE) \ + XX(EVENT_CANMCP2515_INIT_FAILURE) \ + XX(EVENT_CANFD_BUFFER_FULL) \ + XX(EVENT_CAN_BUFFER_FULL) \ + XX(EVENT_CAN_CORRUPTED_WARNING) \ + XX(EVENT_CAN_BATTERY_MISSING) \ + XX(EVENT_CAN_BATTERY2_MISSING) \ + XX(EVENT_CAN_CHARGER_MISSING) \ + XX(EVENT_CAN_INVERTER_MISSING) \ + XX(EVENT_CAN_NATIVE_TX_FAILURE) \ + XX(EVENT_CHARGE_LIMIT_EXCEEDED) \ + XX(EVENT_CONTACTOR_WELDED) \ + XX(EVENT_CONTACTOR_OPEN) \ + XX(EVENT_CPU_OVERHEATING) \ + XX(EVENT_CPU_OVERHEATED) \ + XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \ + XX(EVENT_WATER_INGRESS) \ + XX(EVENT_12V_LOW) \ + XX(EVENT_SOC_PLAUSIBILITY_ERROR) \ + XX(EVENT_SOC_UNAVAILABLE) \ + XX(EVENT_STALE_VALUE) \ + XX(EVENT_KWH_PLAUSIBILITY_ERROR) \ + XX(EVENT_BALANCING_START) \ + XX(EVENT_BALANCING_END) \ + XX(EVENT_BATTERY_EMPTY) \ + XX(EVENT_BATTERY_FULL) \ + XX(EVENT_BATTERY_FUSE) \ + XX(EVENT_BATTERY_FROZEN) \ + XX(EVENT_BATTERY_CAUTION) \ + XX(EVENT_BATTERY_CHG_STOP_REQ) \ + XX(EVENT_BATTERY_DISCHG_STOP_REQ) \ + XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \ + XX(EVENT_BATTERY_OVERHEAT) \ + XX(EVENT_BATTERY_OVERVOLTAGE) \ + XX(EVENT_BATTERY_UNDERVOLTAGE) \ + XX(EVENT_BATTERY_VALUE_UNAVAILABLE) \ + XX(EVENT_BATTERY_ISOLATION) \ + XX(EVENT_BATTERY_REQUESTS_HEAT) \ + XX(EVENT_BATTERY_WARMED_UP) \ + XX(EVENT_VOLTAGE_DIFFERENCE) \ + XX(EVENT_SOH_DIFFERENCE) \ + XX(EVENT_SOH_LOW) \ + XX(EVENT_HVIL_FAILURE) \ + XX(EVENT_PRECHARGE_FAILURE) \ + XX(EVENT_INTERNAL_OPEN_FAULT) \ + XX(EVENT_INVERTER_OPEN_CONTACTOR) \ + XX(EVENT_INTERFACE_MISSING) \ + XX(EVENT_MODBUS_INVERTER_MISSING) \ + XX(EVENT_NO_ENABLE_DETECTED) \ + XX(EVENT_ERROR_OPEN_CONTACTOR) \ + XX(EVENT_CELL_CRITICAL_UNDER_VOLTAGE) \ + XX(EVENT_CELL_CRITICAL_OVER_VOLTAGE) \ + XX(EVENT_CELL_UNDER_VOLTAGE) \ + XX(EVENT_CELL_OVER_VOLTAGE) \ + XX(EVENT_CELL_DEVIATION_HIGH) \ + XX(EVENT_UNKNOWN_EVENT_SET) \ + XX(EVENT_OTA_UPDATE) \ + XX(EVENT_OTA_UPDATE_TIMEOUT) \ + XX(EVENT_DUMMY_INFO) \ + XX(EVENT_DUMMY_DEBUG) \ + XX(EVENT_DUMMY_WARNING) \ + XX(EVENT_DUMMY_ERROR) \ + XX(EVENT_PERSISTENT_SAVE_INFO) \ + XX(EVENT_SERIAL_RX_WARNING) \ + XX(EVENT_SERIAL_RX_FAILURE) \ + XX(EVENT_SERIAL_TX_FAILURE) \ + XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \ + XX(EVENT_SMA_PAIRING) \ + XX(EVENT_TASK_OVERRUN) \ + XX(EVENT_RESET_UNKNOWN) \ + XX(EVENT_RESET_POWERON) \ + XX(EVENT_RESET_EXT) \ + XX(EVENT_RESET_SW) \ + XX(EVENT_RESET_PANIC) \ + XX(EVENT_RESET_INT_WDT) \ + XX(EVENT_RESET_TASK_WDT) \ + XX(EVENT_RESET_WDT) \ + XX(EVENT_RESET_DEEPSLEEP) \ + XX(EVENT_RESET_BROWNOUT) \ + XX(EVENT_RESET_SDIO) \ + XX(EVENT_RESET_USB) \ + XX(EVENT_RESET_JTAG) \ + XX(EVENT_RESET_EFUSE) \ + XX(EVENT_RESET_PWR_GLITCH) \ + XX(EVENT_RESET_CPU_LOCKUP) \ + XX(EVENT_RJXZS_LOG) \ + XX(EVENT_PAUSE_BEGIN) \ + XX(EVENT_PAUSE_END) \ + XX(EVENT_PID_FAILED) \ + XX(EVENT_WIFI_CONNECT) \ + XX(EVENT_WIFI_DISCONNECT) \ + XX(EVENT_MQTT_CONNECT) \ + XX(EVENT_MQTT_DISCONNECT) \ + XX(EVENT_EQUIPMENT_STOP) \ + XX(EVENT_AUTOMATIC_PRECHARGE_FAILURE) \ + XX(EVENT_SD_INIT_FAILED) \ + XX(EVENT_PERIODIC_BMS_RESET) \ + XX(EVENT_BATTERY_TEMP_DEVIATION_HIGH) \ + XX(EVENT_GPIO_NOT_DEFINED) \ + XX(EVENT_GPIO_CONFLICT) \ XX(EVENT_NOF_EVENTS) typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE; diff --git a/Software/src/devboard/utils/ntp_time.cpp b/Software/src/devboard/utils/ntp_time.cpp deleted file mode 100644 index 5221a36a..00000000 --- a/Software/src/devboard/utils/ntp_time.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "ntp_time.h" -#include -#include "../../devboard/utils/logging.h" -#include "time.h" - -const unsigned long millisInADay = 24 * 60 * 60 * 1000; // 24 hours in milliseconds - -unsigned long long getNtpTimeInMillis() { - configTzTime(time_zone, ntpServer1, ntpServer2); - struct tm timeinfo; - - // Wait for time to be set - for (int i = 0; i < 5; i++) { - if (getLocalTime(&timeinfo)) { - logging.println("Time retrieved from NTP Server"); - break; - } - logging.println("Waiting for NTP time..."); - } - - if (!getLocalTime(&timeinfo)) { - logging.println("Failed to obtain time"); - return 0; - } - - // Convert to milliseconds - time_t epochTime = mktime(&timeinfo); - return static_cast(epochTime) * 1000; -} - -// Function to calculate the difference in milliseconds to the next target time -unsigned long long millisToNextTargetTime(unsigned long long currentMillis, int targetTime) { - int hour = targetTime / 100; - int minute = targetTime % 100; - - time_t currentTime = currentMillis / 1000; // Convert milliseconds to seconds - struct tm* timeinfo = localtime(¤tTime); - - // Set timeinfo to the target time on the next day - timeinfo->tm_hour = hour; - timeinfo->tm_min = minute; - timeinfo->tm_sec = 0; - - // Increment day if the current time is past the target time - if (mktime(timeinfo) <= currentTime) { - timeinfo->tm_mday += 1; - } - time_t nextTargetTime = mktime(timeinfo); - unsigned long long nextTargetMillis = static_cast(nextTargetTime) * 1000; - return nextTargetMillis - currentMillis; -} - -unsigned long long getTimeOffsetfromNowUntil(int targetTime) { - logging.println("Getting time offset from now until " + String(targetTime)); - unsigned long long timeinMillis = getNtpTimeInMillis(); - if (timeinMillis != 0) { - logging.println("Time in millis: " + String(timeinMillis)); - unsigned long long timeOffsetUntilTargetTime = millisInADay - (millisToNextTargetTime(timeinMillis, targetTime)); - logging.println("Time offset until target time: " + String(timeOffsetUntilTargetTime)); - return timeOffsetUntilTargetTime; - } else - - return 0; -} diff --git a/Software/src/devboard/utils/ntp_time.h b/Software/src/devboard/utils/ntp_time.h deleted file mode 100644 index d4946104..00000000 --- a/Software/src/devboard/utils/ntp_time.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __NTPTIME_H__ -#define __NTPTIME_H__ - -extern const char* ntpServer1; -extern const char* ntpServer2; -extern const char* time_zone; - -unsigned long long getNtpTimeInMillis(); -unsigned long long millisToNextTargetTime(unsigned long long currentMillis, int targetTime); -unsigned long long getTimeOffsetfromNowUntil(int targetTime); - -#endif From 13df59f80687b845d103776fd8fb624b827bd383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 31 Aug 2025 22:54:57 +0300 Subject: [PATCH 005/150] Make performance profiling configurable from webserver --- Software/Software.ino | 87 +++++++++---------- Software/USER_SETTINGS.h | 1 - .../comm_contactorcontrol.cpp | 3 +- Software/src/communication/nvm/comm_nvm.cpp | 1 + Software/src/datalayer/datalayer.h | 6 +- Software/src/devboard/utils/time_meas.h | 6 -- .../src/devboard/webserver/settings_html.cpp | 7 ++ Software/src/devboard/webserver/webserver.cpp | 37 ++++---- 8 files changed, 74 insertions(+), 74 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index bfd3ceab..98fe5f8e 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -42,10 +42,11 @@ const char* version_number = "9.0.RC5experimental"; volatile unsigned long currentMillis = 0; unsigned long previousMillis10ms = 0; unsigned long previousMillisUpdateVal = 0; -#ifdef FUNCTION_TIME_MEASUREMENT // Task time measurement for debugging MyTimer core_task_timer_10s(INTERVAL_10_S); -#endif +uint64_t start_time_10ms = 0; +uint64_t start_time_values = 0; +uint64_t start_time_cantx = 0; TaskHandle_t main_loop_task; TaskHandle_t connectivity_loop_task; TaskHandle_t logging_loop_task; @@ -248,24 +249,24 @@ void core_loop(void*) { set_event(EVENT_TASK_OVERRUN, (currentMillis - previousMillis10ms)); } previousMillis10ms = currentMillis; -#ifdef FUNCTION_TIME_MEASUREMENT - START_TIME_MEASUREMENT(time_10ms); -#endif + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(10ms); + } led_exe(); handle_contactors(); // Take care of startup precharge/contactor closing #ifdef PRECHARGE_CONTROL handle_precharge_control(currentMillis); #endif // PRECHARGE_CONTROL -#ifdef FUNCTION_TIME_MEASUREMENT - END_TIME_MEASUREMENT_MAX(time_10ms, datalayer.system.status.time_10ms_us); -#endif + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(10ms, datalayer.system.status.time_10ms_us); + } } if (currentMillis - previousMillisUpdateVal >= INTERVAL_1_S) { previousMillisUpdateVal = currentMillis; // Order matters on the update_loop! -#ifdef FUNCTION_TIME_MEASUREMENT - START_TIME_MEASUREMENT(time_values); -#endif + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(values); + } update_pause_state(); // Check if we are OK to send CAN or need to pause // Fetch battery values @@ -285,48 +286,46 @@ void core_loop(void*) { inverter->update_values(); } -#ifdef FUNCTION_TIME_MEASUREMENT - END_TIME_MEASUREMENT_MAX(time_values, datalayer.system.status.time_values_us); -#endif + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(values, datalayer.system.status.time_values_us); + } + } + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(cantx); } -#ifdef FUNCTION_TIME_MEASUREMENT - START_TIME_MEASUREMENT(cantx); -#endif // Let all transmitter objects send their messages for (auto& transmitter : transmitters) { transmitter->transmit(currentMillis); } -#ifdef FUNCTION_TIME_MEASUREMENT - END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us); - END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us); -#endif -#ifdef FUNCTION_TIME_MEASUREMENT - if (datalayer.system.status.core_task_10s_max_us > datalayer.system.status.core_task_max_us) { - // Update worst case total time - datalayer.system.status.core_task_max_us = datalayer.system.status.core_task_10s_max_us; - // Record snapshots of task times - datalayer.system.status.time_snap_comm_us = datalayer.system.status.time_comm_us; - datalayer.system.status.time_snap_10ms_us = datalayer.system.status.time_10ms_us; - datalayer.system.status.time_snap_values_us = datalayer.system.status.time_values_us; - datalayer.system.status.time_snap_cantx_us = datalayer.system.status.time_cantx_us; - datalayer.system.status.time_snap_ota_us = datalayer.system.status.time_ota_us; - } + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us); + END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us); + if (datalayer.system.status.core_task_10s_max_us > datalayer.system.status.core_task_max_us) { + // Update worst case total time + datalayer.system.status.core_task_max_us = datalayer.system.status.core_task_10s_max_us; + // Record snapshots of task times + datalayer.system.status.time_snap_comm_us = datalayer.system.status.time_comm_us; + datalayer.system.status.time_snap_10ms_us = datalayer.system.status.time_10ms_us; + datalayer.system.status.time_snap_values_us = datalayer.system.status.time_values_us; + datalayer.system.status.time_snap_cantx_us = datalayer.system.status.time_cantx_us; + datalayer.system.status.time_snap_ota_us = datalayer.system.status.time_ota_us; + } - datalayer.system.status.core_task_max_us = - MAX(datalayer.system.status.core_task_10s_max_us, datalayer.system.status.core_task_max_us); - if (core_task_timer_10s.elapsed()) { - datalayer.system.status.time_ota_us = 0; - datalayer.system.status.time_comm_us = 0; - datalayer.system.status.time_10ms_us = 0; - datalayer.system.status.time_values_us = 0; - datalayer.system.status.time_cantx_us = 0; - datalayer.system.status.core_task_10s_max_us = 0; - datalayer.system.status.wifi_task_10s_max_us = 0; - datalayer.system.status.mqtt_task_10s_max_us = 0; + datalayer.system.status.core_task_max_us = + MAX(datalayer.system.status.core_task_10s_max_us, datalayer.system.status.core_task_max_us); + if (core_task_timer_10s.elapsed()) { + datalayer.system.status.time_ota_us = 0; + datalayer.system.status.time_comm_us = 0; + datalayer.system.status.time_10ms_us = 0; + datalayer.system.status.time_values_us = 0; + datalayer.system.status.time_cantx_us = 0; + datalayer.system.status.core_task_10s_max_us = 0; + datalayer.system.status.wifi_task_10s_max_us = 0; + datalayer.system.status.mqtt_task_10s_max_us = 0; + } } -#endif // FUNCTION_TIME_MEASUREMENT esp_task_wdt_reset(); // Reset watchdog to prevent reset vTaskDelayUntil(&xLastWakeTime, xFrequency); } diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index bdef00da..fdf4340b 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -123,7 +123,6 @@ #define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. #define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) -//#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) /* MQTT options */ // #define MQTT // Enable this line to enable MQTT diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index 8983807e..c7a0e877 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -297,7 +297,7 @@ void handle_BMSpower() { if (periodic_bms_reset) { // Check if 24 hours have passed since the last power removal - if ((currentTime + bmsResetTimeOffset) - lastPowerRemovalTime >= powerRemovalInterval) { + if (currentTime - lastPowerRemovalTime >= powerRemovalInterval) { start_bms_reset(); } } @@ -329,7 +329,6 @@ void start_bms_reset() { if (!datalayer.system.status.BMS_reset_in_progress) { lastPowerRemovalTime = currentTime; // Record the time when BMS reset was started // we are now resetting at the correct time. We don't need to offset anymore - bmsResetTimeOffset = 0; // Set a flag to let the rest of the system know we are cutting power to the BMS. // The battery CAN sending routine will then know not to try guto send anything towards battery while active datalayer.system.status.BMS_reset_in_progress = true; diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 3c83f9c2..bd8a8802 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -144,6 +144,7 @@ void init_stored_settings() { remote_bms_reset = settings.getBool("REMBMSRESET", false); use_canfd_as_can = settings.getBool("CANFDASCAN", false); + datalayer.system.info.performance_measurement_active = settings.getBool("PERFPROFILE", false); datalayer.system.info.CAN_usb_logging_active = settings.getBool("CANLOGUSB", false); datalayer.system.info.usb_logging_active = settings.getBool("USBENABLED", false); datalayer.system.info.web_logging_active = settings.getBool("WEBENABLED", false); diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 5ead9832..83649469 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -259,12 +259,13 @@ struct DATALAYER_SYSTEM_INFO_TYPE { bool can_native_send_fail = false; /** bool, MCP2515 CAN failed to send flag */ bool can_2515_send_fail = false; - /** uint16_t, MCP2518 CANFD failed to send flag */ + /** bool, MCP2518 CANFD failed to send flag */ bool can_2518_send_fail = false; + /** bool, determines if detailed performance measurement should be shown on webserver */ + bool performance_measurement_active = false; }; struct DATALAYER_SYSTEM_STATUS_TYPE { -#ifdef FUNCTION_TIME_MEASUREMENT /** Core task measurement variable */ int64_t core_task_max_us = 0; /** Core task measurement variable, reset each 10 seconds */ @@ -305,7 +306,6 @@ struct DATALAYER_SYSTEM_STATUS_TYPE { * This will show the performance of CAN TX when the total time reached a new worst case */ int64_t time_snap_cantx_us = 0; -#endif /** uint8_t */ /** A counter set each time a new message comes from inverter. * This value then gets decremented every second. Incase we reach 0 diff --git a/Software/src/devboard/utils/time_meas.h b/Software/src/devboard/utils/time_meas.h index 30f1e5eb..df2c8b0c 100644 --- a/Software/src/devboard/utils/time_meas.h +++ b/Software/src/devboard/utils/time_meas.h @@ -7,7 +7,6 @@ /** Start time measurement in microseconds * Input parameter must be a unique "tag", e.g: START_TIME_MEASUREMENT(wifi); */ -#ifdef FUNCTION_TIME_MEASUREMENT #define START_TIME_MEASUREMENT(x) int64_t start_time_##x = esp_timer_get_time() /** End time measurement in microseconds * Input parameters are the unique tag and the name of the ALREADY EXISTING @@ -21,10 +20,5 @@ * This will log the maximum value in the destination variable. */ #define END_TIME_MEASUREMENT_MAX(x, y) y = MAX(y, esp_timer_get_time() - start_time_##x) -#else -#define START_TIME_MEASUREMENT(x) ; -#define END_TIME_MEASUREMENT(x, y) ; -#define END_TIME_MEASUREMENT_MAX(x, y) ; -#endif #endif diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 0a9d4163..62060cfb 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -283,6 +283,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return settings.getBool("WIFIAPENABLED", wifiap_enabled) ? "checked" : ""; } + if (var == "PERFPROFILE") { + return settings.getBool("PERFPROFILE") ? "checked" : ""; + } + if (var == "CANLOGUSB") { return settings.getBool("CANLOGUSB") ? "checked" : ""; } @@ -970,6 +974,9 @@ const char* getCANInterfaceName(CAN_Interface interface) { + + + diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index d9ab1ad3..f0b5c633 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -411,7 +411,7 @@ void init_webserver() { const char* boolSettingNames[] = { "DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED", "REMBMSRESET", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", "CANLOGSD", "WIFIAPENABLED", "MQTTENABLED", - "HADISC", "MQTTTOPICS", "INVICNT", "GTWRHD", "DIGITALHVIL", + "HADISC", "MQTTTOPICS", "INVICNT", "GTWRHD", "DIGITALHVIL", "PERFPROFILE", }; // Handles the form POST from UI to save settings of the common image @@ -914,23 +914,24 @@ String processor(const String& var) { #endif // HW_STARK content += " @ " + String(datalayer.system.info.CPU_temperature, 1) + " °C"; content += "

Uptime: " + get_uptime() + "

"; -#ifdef FUNCTION_TIME_MEASUREMENT - // Load information - content += "

Core task max load: " + String(datalayer.system.status.core_task_max_us) + " us

"; - content += "

Core task max load last 10 s: " + String(datalayer.system.status.core_task_10s_max_us) + " us

"; - content += - "

MQTT function (MQTT task) max load last 10 s: " + String(datalayer.system.status.mqtt_task_10s_max_us) + - " us

"; - content += - "

WIFI function (MQTT task) max load last 10 s: " + String(datalayer.system.status.wifi_task_10s_max_us) + - " us

"; - content += "

Max load @ worst case execution of core task:

"; - content += "

10ms function timing: " + String(datalayer.system.status.time_snap_10ms_us) + " us

"; - content += "

Values function timing: " + String(datalayer.system.status.time_snap_values_us) + " us

"; - content += "

CAN/serial RX function timing: " + String(datalayer.system.status.time_snap_comm_us) + " us

"; - content += "

CAN TX function timing: " + String(datalayer.system.status.time_snap_cantx_us) + " us

"; - content += "

OTA function timing: " + String(datalayer.system.status.time_snap_ota_us) + " us

"; -#endif // FUNCTION_TIME_MEASUREMENT + if (datalayer.system.info.performance_measurement_active) { + // Load information + content += "

Core task max load: " + String(datalayer.system.status.core_task_max_us) + " us

"; + content += + "

Core task max load last 10 s: " + String(datalayer.system.status.core_task_10s_max_us) + " us

"; + content += + "

MQTT function (MQTT task) max load last 10 s: " + String(datalayer.system.status.mqtt_task_10s_max_us) + + " us

"; + content += + "

WIFI function (MQTT task) max load last 10 s: " + String(datalayer.system.status.wifi_task_10s_max_us) + + " us

"; + content += "

Max load @ worst case execution of core task:

"; + content += "

10ms function timing: " + String(datalayer.system.status.time_snap_10ms_us) + " us

"; + content += "

Values function timing: " + String(datalayer.system.status.time_snap_values_us) + " us

"; + content += "

CAN/serial RX function timing: " + String(datalayer.system.status.time_snap_comm_us) + " us

"; + content += "

CAN TX function timing: " + String(datalayer.system.status.time_snap_cantx_us) + " us

"; + content += "

OTA function timing: " + String(datalayer.system.status.time_snap_ota_us) + " us

"; + } wl_status_t status = WiFi.status(); // Display ssid of network connected to and, if connected to the WiFi, its own IP From 7ded4f16622a1dfa9decd64938a3206305ec884d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 31 Aug 2025 23:52:44 +0300 Subject: [PATCH 006/150] Remove user voltage set ability from USER_SETTINGS, now common --- Software/USER_SETTINGS.h | 78 +----------------------------- Software/src/battery/BATTERIES.cpp | 22 ++------- 2 files changed, 6 insertions(+), 94 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index fdf4340b..8c450453 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -4,77 +4,9 @@ #include #include "src/devboard/utils/types.h" -/* This file contains all the battery/inverter protocol settings Battery-Emulator software */ -/* To switch between batteries/inverters, uncomment a line to enable, comment out to disable. */ -/* There are also some options for battery limits and extra functionality */ -/* To edit battery specific limits, see also the USER_SETTINGS.cpp file*/ +/* This file is being transitioned towards COMMON_IMAGE. Use v8.16 if you are taking this software into use! */ -/* Select battery used */ -//#define BMW_I3_BATTERY -//#define BMW_IX_BATTERY -//#define BMW_PHEV_BATTERY -//#define BOLT_AMPERA_BATTERY -//#define BYD_ATTO_3_BATTERY -//#define FOXESS_BATTERY -//#define CELLPOWER_BMS -//#define CHADEMO_BATTERY //NOTE: inherently enables CONTACTOR_CONTROL below -//#define GEELY_GEOMETRY_C_BATTERY -//#define HYUNDAI_IONIQ_28_BATTERY -//#define CMFA_EV_BATTERY -//#define IMIEV_CZERO_ION_BATTERY -//#define JAGUAR_IPACE_BATTERY -//#define KIA_E_GMP_BATTERY -//#define KIA_HYUNDAI_64_BATTERY -//#define KIA_HYUNDAI_64_FD_BATTERY -//#define KIA_HYUNDAI_HYBRID_BATTERY -//#define MEB_BATTERY -//#define MG_5_BATTERY -//#define MG_HS_PHEV_BATTERY -//#define NISSAN_LEAF_BATTERY -//#define ORION_BMS -//#define PYLON_BATTERY -//#define DALY_BMS -//#define RJXZS_BMS -//#define RANGE_ROVER_PHEV_BATTERY -//#define RELION_BATTERY -//#define RENAULT_KANGOO_BATTERY -//#define RENAULT_TWIZY_BATTERY -//#define RENAULT_ZOE_GEN1_BATTERY -//#define RENAULT_ZOE_GEN2_BATTERY -//#define SONO_BATTERY -//#define SAMSUNG_SDI_LV_BATTERY -//#define SANTA_FE_PHEV_BATTERY -//#define SIMPBMS_BATTERY -//#define STELLANTIS_ECMP_BATTERY -//#define TESLA_MODEL_3Y_BATTERY -//#define TESLA_MODEL_SX_BATTERY -//#define VOLVO_SPA_BATTERY -//#define VOLVO_SPA_HYBRID_BATTERY -//#define TEST_FAKE_BATTERY -//#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires separate CAN setup) - -/* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/Battery-Emulator/wiki */ -//#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus -//#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus -//#define BYD_CAN_DEYE //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus, with Deye specific fixes -//#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 -//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU -//#define FERROAMP_CAN //Enable this line to emulate a "Pylon 4x96V Force H2" over CAN Bus -//#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus -//#define GROWATT_HV_CAN //Enable this line to emulate a "Growatt High Voltage v1.10 battery" over CAN bus -//#define GROWATT_LV_CAN //Enable this line to emulate a "48V Growatt Low Voltage battery" over CAN bus -//#define PYLON_LV_CAN //Enable this line to emulate a "48V Pylontech battery" over CAN bus -//#define PYLON_CAN //Enable this line to emulate a "High Voltage Pylontech battery" over CAN bus -//#define SCHNEIDER_CAN //Enable this line to emulate a "Schneider Version 2: SE BMS" over CAN bus -//#define SMA_BYD_H_CAN //Enable this line to emulate a "BYD Battery-Box H 8.9kWh, 7 mod" (SMA compatible) over CAN bus -//#define SMA_BYD_HVS_CAN //Enable this line to emulate a "BYD Battery-Box HVS 10.2KW battery" (SMA compatible) over CAN bus -//#define SMA_LV_CAN //Enable this line to emulate a "SMA Sunny Island 48V battery" over CAN bus -//#define SMA_TRIPOWER_CAN //Enable this line to emulate a "SMA Home Storage battery" over CAN bus -//#define SOFAR_CAN //Enable this line to emulate a "Sofar Energy Storage Inverter High Voltage BMS General Protocol (Extended Frame)" over CAN bus -//#define SOLAX_CAN //Enable this line to emulate a "SolaX Triple Power LFP" over CAN bus -//#define SOLXPOW_CAN //Enable this line to emulate a "Solxpow compatible battery" over CAN bus -//#define SOL_ARK_LV_CAN //Enable this line to emulate a "Sol-Ark compatible LV battery" over CAN bus -//#define SUNGROW_CAN //Enable this line to emulate a "Sungrow SBR064" over CAN bus +//#define COMMON_IMAGE /* Select hardware used for Battery-Emulator */ //#define HW_LILYGO @@ -164,12 +96,6 @@ // 3000 = 300.0V, Target discharge voltage (Value can be tuned on the fly via webserver). Not used unless BATTERY_USE_VOLTAGE_LIMITS = true #define BATTERY_MAX_DISCHARGE_VOLTAGE 3000 -/* Pack/cell voltage limits for custom-BMS batteries (RJXZS, Daly, etc.) */ -//#define MAX_CUSTOM_PACK_VOLTAGE_DV 5000 // 5000 = 500.0V , Maximum pack voltage in decivolts -//#define MIN_CUSTOM_PACK_VOLTAGE_DV 2500 // 2500 = 250.0V , Minimum pack voltage in decivolts -//#define MAX_CUSTOM_CELL_VOLTAGE_MV 4250 // 4250 = 4.250V , Maximum cell voltage in millivolts (4250 = 4.250V) -//#define MIN_CUSTOM_CELL_VOLTAGE_MV 2650 // 2650 = 2.650V , Minimum cell voltage in millivolts (2650 = 2.650V) - /* Do not change any code below this line */ /* Only change battery specific settings above and in "USER_SETTINGS.cpp" */ typedef struct { diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index 10134bf2..e76f35cf 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -329,22 +329,8 @@ uint16_t user_selected_tesla_GTW_mapRegion = 2; uint16_t user_selected_tesla_GTW_chassisType = 2; uint16_t user_selected_tesla_GTW_packEnergy = 1; -/* User-selected voltages used for custom-BMS batteries (RJXZS etc.) */ -#if defined(MAX_CUSTOM_PACK_VOLTAGE_DV) && defined(MIN_CUSTOM_PACK_VOLTAGE_DV) && \ - defined(MAX_CUSTOM_CELL_VOLTAGE_MV) && defined(MIN_CUSTOM_CELL_VOLTAGE_MV) -// Use USER_SETTINGS.h values for cell/pack voltage defaults -uint16_t user_selected_max_pack_voltage_default_dV = MAX_CUSTOM_PACK_VOLTAGE_DV; -uint16_t user_selected_min_pack_voltage_default_dV = MIN_CUSTOM_PACK_VOLTAGE_DV; -uint16_t user_selected_max_cell_voltage_default_mV = MAX_CUSTOM_CELL_VOLTAGE_MV; -uint16_t user_selected_min_cell_voltage_default_mV = MIN_CUSTOM_CELL_VOLTAGE_MV; -#else // Use 0V for user selected cell/pack voltage defaults (COMMON_IMAGE will replace with saved values from NVM) -uint16_t user_selected_max_pack_voltage_default_dV = 0; -uint16_t user_selected_min_pack_voltage_default_dV = 0; -uint16_t user_selected_max_cell_voltage_default_mV = 0; -uint16_t user_selected_min_cell_voltage_default_mV = 0; -#endif -uint16_t user_selected_max_pack_voltage_dV = user_selected_max_pack_voltage_default_dV; -uint16_t user_selected_min_pack_voltage_dV = user_selected_min_pack_voltage_default_dV; -uint16_t user_selected_max_cell_voltage_mV = user_selected_max_cell_voltage_default_mV; -uint16_t user_selected_min_cell_voltage_mV = user_selected_min_cell_voltage_default_mV; +uint16_t user_selected_max_pack_voltage_dV = 0; +uint16_t user_selected_min_pack_voltage_dV = 0; +uint16_t user_selected_max_cell_voltage_mV = 0; +uint16_t user_selected_min_cell_voltage_mV = 0; From 9031d3e5cf4ea591ae8db9f9673d5c79cf413e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 13:25:59 +0300 Subject: [PATCH 007/150] Move more settings to common-image --- Software/USER_SETTINGS.h | 9 --- Software/src/battery/CHADEMO-BATTERY.h | 3 - .../comm_contactorcontrol.cpp | 61 +++++-------------- .../contactorcontrol/comm_contactorcontrol.h | 3 + Software/src/communication/nvm/comm_nvm.cpp | 3 + .../src/devboard/webserver/settings_html.cpp | 56 +++++++++++++---- Software/src/devboard/webserver/webserver.cpp | 9 +++ 7 files changed, 76 insertions(+), 68 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 8c450453..08cb36b6 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -14,15 +14,6 @@ //#define HW_3LB //#define HW_DEVKIT -/* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ -#define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) -//#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) -//#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) -//#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. -//#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! -//#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF -//#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF - /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement diff --git a/Software/src/battery/CHADEMO-BATTERY.h b/Software/src/battery/CHADEMO-BATTERY.h index 8e603f4e..613a8057 100644 --- a/Software/src/battery/CHADEMO-BATTERY.h +++ b/Software/src/battery/CHADEMO-BATTERY.h @@ -9,9 +9,6 @@ #ifdef CHADEMO_BATTERY #define SELECTED_BATTERY_CLASS ChademoBattery - -//Contactor control is required for CHADEMO support -#define CONTACTOR_CONTROL #endif class ChademoBattery : public CanBattery { diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index c7a0e877..a88ff9d0 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -3,45 +3,16 @@ #include "../../devboard/safety/safety.h" #include "../../inverter/INVERTERS.h" -#ifdef CONTACTOR_CONTROL -const bool contactor_control_enabled_default = true; -#else -const bool contactor_control_enabled_default = false; -#endif -bool contactor_control_enabled = contactor_control_enabled_default; - -#ifdef PWM_CONTACTOR_CONTROL -const bool pwn_contactor_control_default = true; -#else -const bool pwn_contactor_control_default = false; -#endif -bool pwm_contactor_control = pwn_contactor_control_default; - -#ifdef PERIODIC_BMS_RESET -const bool periodic_bms_reset_default = true; -#else -const bool periodic_bms_reset_default = false; -#endif -bool periodic_bms_reset = periodic_bms_reset_default; - -#ifdef REMOTE_BMS_RESET -const bool remote_bms_reset_default = true; -#else -const bool remote_bms_reset_default = false; -#endif -bool remote_bms_reset = remote_bms_reset_default; - -#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY -const bool contactor_control_enabled_double_battery_default = true; -#else -const bool contactor_control_enabled_double_battery_default = false; -#endif -bool contactor_control_enabled_double_battery = contactor_control_enabled_double_battery_default; - // TODO: Ensure valid values at run-time +// User can update all these values via Settings page +bool contactor_control_enabled = false; //Should GPIO contactor control be performed? +uint16_t precharge_time_ms = 100; //Precharge time in ms. Adjust depending on capacitance in inverter +bool pwm_contactor_control = false; //Should the contactors be economized via PWM after they are engaged? +bool contactor_control_enabled_double_battery = false; //Should a contactor for the secondary battery be operated? +bool remote_bms_reset = false; //Is it possible to actuate BMS reset via MQTT? +bool periodic_bms_reset = false; //Should periodic BMS reset be performed each 24h? // Parameters - enum State { DISCONNECTED, START_PRECHARGE, PRECHARGE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED }; State contactorStatus = DISCONNECTED; @@ -60,11 +31,11 @@ const int OFF = 0; 500 // Time after negative contactor is turned on, to start precharge (not actual precharge time!) #define PRECHARGE_COMPLETED_TIME_MS \ 1000 // After successful precharge, resistor is turned off after this delay (and contactors are economized if PWM enabled) -#define PWM_Freq 20000 // 20 kHz frequency, beyond audible range -#define PWM_Res 10 // 10 Bit resolution 0 to 1023, maps 'nicely' to 0% 100% -#define PWM_HOLD_DUTY 250 -#define PWM_OFF_DUTY 0 +uint16_t pwm_frequency = 20000; +uint16_t pwm_hold_duty = 250; #define PWM_ON_DUTY 1023 +#define PWM_RESOLUTION 10 +#define PWM_OFF_DUTY 0 //No need to have this userconfigurable #define PWM_Positive_Channel 0 #define PWM_Negative_Channel 1 static unsigned long prechargeStartTime = 0; @@ -108,8 +79,8 @@ bool init_contactors() { if (pwm_contactor_control) { // Setup PWM Channel Frequency and Resolution - ledcAttachChannel(posPin, PWM_Freq, PWM_Res, PWM_Positive_Channel); - ledcAttachChannel(negPin, PWM_Freq, PWM_Res, PWM_Negative_Channel); + ledcAttachChannel(posPin, pwm_frequency, PWM_RESOLUTION, PWM_Positive_Channel); + ledcAttachChannel(negPin, pwm_frequency, PWM_RESOLUTION, PWM_Negative_Channel); // Set all pins OFF (0% PWM) ledcWrite(posPin, PWM_OFF_DUTY); ledcWrite(negPin, PWM_OFF_DUTY); @@ -245,7 +216,7 @@ void handle_contactors() { break; case POSITIVE: - if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) { + if (currentTime - negativeStartTime >= precharge_time_ms) { set(posPin, ON, PWM_ON_DUTY); dbg_contactors("POSITIVE"); prechargeCompletedTime = currentTime; @@ -256,8 +227,8 @@ void handle_contactors() { case PRECHARGE_OFF: if (currentTime - prechargeCompletedTime >= PRECHARGE_COMPLETED_TIME_MS) { set(prechargePin, OFF); - set(negPin, ON, PWM_HOLD_DUTY); - set(posPin, ON, PWM_HOLD_DUTY); + set(negPin, ON, pwm_hold_duty); + set(posPin, ON, pwm_hold_duty); dbg_contactors("PRECHARGE_OFF"); contactorStatus = COMPLETED; datalayer.system.status.contactors_engaged = 1; diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h index 45551610..9441c121 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h @@ -10,6 +10,9 @@ extern bool contactor_control_enabled_double_battery; extern bool pwm_contactor_control; extern bool periodic_bms_reset; extern bool remote_bms_reset; +extern uint16_t precharge_time_ms; +extern uint16_t pwm_frequency; +extern uint16_t pwm_hold_duty; /** * @brief Handle BMS power output diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index bd8a8802..83d2b6c1 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -138,8 +138,11 @@ void init_stored_settings() { equipment_stop_behavior = (STOP_BUTTON_BEHAVIOR)settings.getUInt("EQSTOP", (int)STOP_BUTTON_BEHAVIOR::NOT_CONNECTED); user_selected_second_battery = settings.getBool("DBLBTR", false); contactor_control_enabled = settings.getBool("CNTCTRL", false); + precharge_time_ms = settings.getUInt("PRECHGMS", 100); contactor_control_enabled_double_battery = settings.getBool("CNTCTRLDBL", false); pwm_contactor_control = settings.getBool("PWMCNTCTRL", false); + pwm_frequency = settings.getUInt("PWMFREQ", 20000); + pwm_hold_duty = settings.getUInt("PWMHOLD", 250); periodic_bms_reset = settings.getBool("PERBMSRESET", false); remote_bms_reset = settings.getBool("REMBMSRESET", false); use_canfd_as_can = settings.getBool("CANFDASCAN", false); diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 62060cfb..cc4ffc14 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -557,6 +557,18 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return String(settings.getUInt("CANFREQ", 8)); } + if (var == "PRECHGMS") { + return String(settings.getUInt("PRECHGMS", 100)); + } + + if (var == "PWMFREQ") { + return String(settings.getUInt("PWMFREQ", 20000)); + } + + if (var == "PWMHOLD") { + return String(settings.getUInt("PWMHOLD", 250)); + } + if (var == "DIGITALHVIL") { return settings.getBool("DIGITALHVIL") ? "checked" : ""; } @@ -781,6 +793,16 @@ const char* getCANInterfaceName(CAN_Interface interface) { display: contents; } + form .if-pwmcntctrl { display: none; } + form[data-pwmcntctrl="true"] .if-pwmcntctrl { + display: contents; + } + + form .if-cntctrl { display: none; } + form[data-cntctrl="true"] .if-cntctrl { + display: contents; + } + form .if-sofar { display: none; } form[data-inverter="17"] .if-sofar { display: contents; @@ -932,7 +954,7 @@ const char* getCANInterfaceName(CAN_Interface interface) { - +
- + + + +
- + -
- - -
+
+ + - - + + + +
+ + + + + +
+ +
diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index f0b5c633..6b6102e4 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -515,6 +515,15 @@ void init_webserver() { } else if (p->name() == "CANFREQ") { auto type = atoi(p->value().c_str()); settings.saveUInt("CANFREQ", type); + } else if (p->name() == "PRECHGMS") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("PRECHGMS", type); + } else if (p->name() == "PWMFREQ") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("PWMFREQ", type); + } else if (p->name() == "PWMHOLD") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("PWMHOLD", type); } else if (p->name() == "GTWCOUNTRY") { auto type = atoi(p->value().c_str()); settings.saveUInt("GTWCOUNTRY", type); From 7ee0eb5e8887a1ed76b3a2da14edfaf247b544d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 15:03:56 +0300 Subject: [PATCH 008/150] Remove old method to compile, all is now Common Image --- Software/USER_SETTINGS.cpp | 16 ------- Software/USER_SETTINGS.h | 2 - Software/src/battery/BATTERIES.cpp | 44 +------------------ Software/src/battery/BMW-I3-BATTERY.h | 4 -- Software/src/battery/BMW-IX-BATTERY.h | 4 -- Software/src/battery/BMW-PHEV-BATTERY.h | 4 -- Software/src/battery/BOLT-AMPERA-BATTERY.h | 4 -- Software/src/battery/BYD-ATTO-3-BATTERY.h | 3 -- Software/src/battery/CELLPOWER-BMS.h | 4 -- Software/src/battery/CHADEMO-BATTERY.h | 4 -- Software/src/battery/CMFA-EV-BATTERY.h | 4 -- Software/src/battery/DALY-BMS.h | 4 -- Software/src/battery/ECMP-BATTERY.h | 4 -- Software/src/battery/FOXESS-BATTERY.h | 4 -- .../src/battery/GEELY-GEOMETRY-C-BATTERY.h | 4 -- .../src/battery/HYUNDAI-IONIQ-28-BATTERY.h | 4 -- .../src/battery/IMIEV-CZERO-ION-BATTERY.h | 4 -- Software/src/battery/JAGUAR-IPACE-BATTERY.h | 4 -- Software/src/battery/KIA-64FD-BATTERY.h | 4 -- Software/src/battery/KIA-E-GMP-BATTERY.h | 4 -- Software/src/battery/KIA-HYUNDAI-64-BATTERY.h | 4 -- .../src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h | 4 -- Software/src/battery/MEB-BATTERY.h | 4 -- Software/src/battery/MG-5-BATTERY.h | 4 -- Software/src/battery/MG-HS-PHEV-BATTERY.h | 4 -- Software/src/battery/NISSAN-LEAF-BATTERY.h | 4 -- Software/src/battery/ORION-BMS.h | 4 -- Software/src/battery/PYLON-BATTERY.h | 4 -- .../src/battery/RANGE-ROVER-PHEV-BATTERY.h | 4 -- Software/src/battery/RELION-LV-BATTERY.h | 4 -- Software/src/battery/RENAULT-KANGOO-BATTERY.h | 4 -- Software/src/battery/RENAULT-TWIZY.h | 4 -- .../src/battery/RENAULT-ZOE-GEN1-BATTERY.h | 4 -- .../src/battery/RENAULT-ZOE-GEN2-BATTERY.h | 4 -- Software/src/battery/RJXZS-BMS.h | 4 -- Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h | 4 -- Software/src/battery/SANTA-FE-PHEV-BATTERY.h | 4 -- Software/src/battery/SIMPBMS-BATTERY.h | 4 -- Software/src/battery/SONO-BATTERY.h | 4 -- Software/src/battery/Shunts.cpp | 20 --------- Software/src/battery/TESLA-BATTERY.h | 7 --- Software/src/battery/TEST-FAKE-BATTERY.h | 4 -- Software/src/battery/VOLVO-SPA-BATTERY.h | 4 -- .../src/battery/VOLVO-SPA-HYBRID-BATTERY.h | 4 -- Software/src/charger/CHARGERS.cpp | 7 +-- Software/src/communication/nvm/comm_nvm.cpp | 3 -- Software/src/devboard/mqtt/mqtt.cpp | 31 ++----------- .../src/devboard/webserver/settings_html.cpp | 8 +--- Software/src/devboard/webserver/webserver.cpp | 22 ++-------- Software/src/devboard/wifi/wifi.cpp | 12 +---- Software/src/inverter/INVERTERS.cpp | 26 ----------- Software/src/inverter/INVERTERS.h | 5 --- platformio.ini | 15 +------ 53 files changed, 12 insertions(+), 361 deletions(-) diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 1bc74643..134c50d3 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -21,25 +21,14 @@ volatile CAN_Configuration can_config = { .shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your shunt connected to? }; -#ifdef COMMON_IMAGE std::string ssid; std::string password; std::string passwordAP; -#else -std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h -std::string password = WIFI_PASSWORD; // Set in USER_SECRETS.h -std::string passwordAP = AP_PASSWORD; // Set in USER_SECRETS.h -#endif const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection -#ifdef COMMON_IMAGE std::string http_username; std::string http_password; -#else -std::string http_username = HTTP_USERNAME; // Set in USER_SECRETS.h -std::string http_password = HTTP_PASSWORD; // Set in USER_SECRETS.h -#endif // Set your Static IP address. Only used incase WIFICONFIG is set in USER_SETTINGS.h IPAddress local_IP(192, 168, 10, 150); @@ -47,13 +36,8 @@ IPAddress gateway(192, 168, 10, 1); IPAddress subnet(255, 255, 255, 0); // MQTT -#ifdef COMMON_IMAGE std::string mqtt_user; std::string mqtt_password; -#else -std::string mqtt_user = MQTT_USER; // Set in USER_SECRETS.h -std::string mqtt_password = MQTT_PASSWORD; // Set in USER_SECRETS.h -#endif const char* mqtt_topic_name = "BE"; // Custom MQTT topic name. Previously, the name was automatically set to "battery-emulator_esp32-XXXXXX" diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 08cb36b6..9e8283a0 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -6,8 +6,6 @@ /* This file is being transitioned towards COMMON_IMAGE. Use v8.16 if you are taking this software into use! */ -//#define COMMON_IMAGE - /* Select hardware used for Battery-Emulator */ //#define HW_LILYGO //#define HW_STARK diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index e76f35cf..b24751ab 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -3,10 +3,6 @@ #include "CanBattery.h" #include "RS485Battery.h" -#if !defined(COMMON_IMAGE) && !defined(SELECTED_BATTERY_CLASS) -#error No battery selected! Choose one from the USER_SETTINGS.h file or build COMMON_IMAGE. -#endif - Battery* battery = nullptr; Battery* battery2 = nullptr; @@ -149,11 +145,6 @@ const battery_chemistry_enum battery_chemistry_default = battery_chemistry_enum: battery_chemistry_enum user_selected_battery_chemistry = battery_chemistry_default; -#ifdef COMMON_IMAGE -#ifdef SELECTED_BATTERY_CLASS -#error "Compile time SELECTED_BATTERY_CLASS should not be defined with COMMON_IMAGE" -#endif - BatteryType user_selected_battery_type = BatteryType::NissanLeaf; bool user_selected_second_battery = false; @@ -287,39 +278,6 @@ void setup_battery() { } } } -#else // Battery selection has been made at build-time - -void setup_battery() { - // Instantiate the battery only once just in case this function gets called multiple times. - if (battery == nullptr) { -#ifdef TESLA_MODEL_3Y_BATTERY - battery = new SELECTED_BATTERY_CLASS(user_selected_battery_chemistry); -#else - battery = new SELECTED_BATTERY_CLASS(); -#endif - } - battery->setup(); - -#ifdef DOUBLE_BATTERY - if (battery2 == nullptr) { -#if defined(BMW_I3_BATTERY) - battery2 = - new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer.system.status.battery2_allowed_contactor_closing, - can_config.battery_double, esp32hal->WUP_PIN2()); -#elif defined(KIA_HYUNDAI_64_BATTERY) - battery2 = new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer_extended.KiaHyundai64_2, - &datalayer.system.status.battery2_allowed_contactor_closing, - can_config.battery_double); -#elif defined(SANTA_FE_PHEV_BATTERY) || defined(TEST_FAKE_BATTERY) - battery2 = new SELECTED_BATTERY_CLASS(&datalayer.battery2, can_config.battery_double); -#else - battery2 = new SELECTED_BATTERY_CLASS(&datalayer.battery2, nullptr, can_config.battery_double); -#endif - } - battery2->setup(); -#endif -} -#endif /* User-selected Tesla settings */ bool user_selected_tesla_digital_HVIL = false; @@ -329,7 +287,7 @@ uint16_t user_selected_tesla_GTW_mapRegion = 2; uint16_t user_selected_tesla_GTW_chassisType = 2; uint16_t user_selected_tesla_GTW_packEnergy = 1; -// Use 0V for user selected cell/pack voltage defaults (COMMON_IMAGE will replace with saved values from NVM) +// Use 0V for user selected cell/pack voltage defaults (On boot will be replaced with saved values from NVM) uint16_t user_selected_max_pack_voltage_dV = 0; uint16_t user_selected_min_pack_voltage_dV = 0; uint16_t user_selected_max_cell_voltage_mV = 0; diff --git a/Software/src/battery/BMW-I3-BATTERY.h b/Software/src/battery/BMW-I3-BATTERY.h index 436c2604..adb42908 100644 --- a/Software/src/battery/BMW-I3-BATTERY.h +++ b/Software/src/battery/BMW-I3-BATTERY.h @@ -6,10 +6,6 @@ #include "BMW-I3-HTML.h" #include "CanBattery.h" -#ifdef BMW_I3_BATTERY -#define SELECTED_BATTERY_CLASS BmwI3Battery -#endif - class BmwI3Battery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 074b4286..7bc54095 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -4,10 +4,6 @@ #include "BMW-IX-HTML.h" #include "CanBattery.h" -#ifdef BMW_IX_BATTERY -#define SELECTED_BATTERY_CLASS BmwIXBattery -#endif - class BmwIXBattery : public CanBattery { public: BmwIXBattery() : renderer(*this) {} diff --git a/Software/src/battery/BMW-PHEV-BATTERY.h b/Software/src/battery/BMW-PHEV-BATTERY.h index b35c9edc..553e514e 100644 --- a/Software/src/battery/BMW-PHEV-BATTERY.h +++ b/Software/src/battery/BMW-PHEV-BATTERY.h @@ -3,10 +3,6 @@ #include "BMW-PHEV-HTML.h" #include "CanBattery.h" -#ifdef BMW_PHEV_BATTERY -#define SELECTED_BATTERY_CLASS BmwPhevBattery -#endif - class BmwPhevBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.h b/Software/src/battery/BOLT-AMPERA-BATTERY.h index d7d08da4..05b28f80 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.h +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.h @@ -3,10 +3,6 @@ #include "BOLT-AMPERA-HTML.h" #include "CanBattery.h" -#ifdef BOLT_AMPERA_BATTERY -#define SELECTED_BATTERY_CLASS BoltAmperaBattery -#endif - class BoltAmperaBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.h b/Software/src/battery/BYD-ATTO-3-BATTERY.h index 9e8f7497..a85c70ca 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.h +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.h @@ -24,9 +24,6 @@ static const int RAMPDOWN_POWER_ALLOWED = 10000; // Power to start ramp down from, set a lower value to limit the power even further as SOC decreases /* Do not modify the rows below */ -#ifdef BYD_ATTO_3_BATTERY -#define SELECTED_BATTERY_CLASS BydAttoBattery -#endif class BydAttoBattery : public CanBattery { public: diff --git a/Software/src/battery/CELLPOWER-BMS.h b/Software/src/battery/CELLPOWER-BMS.h index ba8be709..75251848 100644 --- a/Software/src/battery/CELLPOWER-BMS.h +++ b/Software/src/battery/CELLPOWER-BMS.h @@ -3,10 +3,6 @@ #include "CELLPOWER-HTML.h" #include "CanBattery.h" -#ifdef CELLPOWER_BMS -#define SELECTED_BATTERY_CLASS CellPowerBms -#endif - class CellPowerBms : public CanBattery { public: CellPowerBms() : CanBattery(CAN_Speed::CAN_SPEED_250KBPS) {} diff --git a/Software/src/battery/CHADEMO-BATTERY.h b/Software/src/battery/CHADEMO-BATTERY.h index 613a8057..fa0eaa5a 100644 --- a/Software/src/battery/CHADEMO-BATTERY.h +++ b/Software/src/battery/CHADEMO-BATTERY.h @@ -7,10 +7,6 @@ #include "CHADEMO-BATTERY-HTML.h" #include "CanBattery.h" -#ifdef CHADEMO_BATTERY -#define SELECTED_BATTERY_CLASS ChademoBattery -#endif - class ChademoBattery : public CanBattery { public: ChademoBattery() { diff --git a/Software/src/battery/CMFA-EV-BATTERY.h b/Software/src/battery/CMFA-EV-BATTERY.h index 048e386a..3f649240 100644 --- a/Software/src/battery/CMFA-EV-BATTERY.h +++ b/Software/src/battery/CMFA-EV-BATTERY.h @@ -4,10 +4,6 @@ #include "CMFA-EV-HTML.h" #include "CanBattery.h" -#ifdef CMFA_EV_BATTERY -#define SELECTED_BATTERY_CLASS CmfaEvBattery -#endif - class CmfaEvBattery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/DALY-BMS.h b/Software/src/battery/DALY-BMS.h index 4b9c6998..1bb7acb8 100644 --- a/Software/src/battery/DALY-BMS.h +++ b/Software/src/battery/DALY-BMS.h @@ -3,10 +3,6 @@ #include "RS485Battery.h" -#ifdef DALY_BMS -#define SELECTED_BATTERY_CLASS DalyBms -#endif - class DalyBms : public RS485Battery { public: void setup(); diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h index 63284818..fe4aa58a 100644 --- a/Software/src/battery/ECMP-BATTERY.h +++ b/Software/src/battery/ECMP-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" #include "ECMP-HTML.h" -#ifdef STELLANTIS_ECMP_BATTERY -#define SELECTED_BATTERY_CLASS EcmpBattery -#endif - class EcmpBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/FOXESS-BATTERY.h b/Software/src/battery/FOXESS-BATTERY.h index c3471d09..a10d62fd 100644 --- a/Software/src/battery/FOXESS-BATTERY.h +++ b/Software/src/battery/FOXESS-BATTERY.h @@ -2,10 +2,6 @@ #define FOXESS_BATTERY_H #include "CanBattery.h" -#ifdef FOXESS_BATTERY -#define SELECTED_BATTERY_CLASS FoxessBattery -#endif - class FoxessBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h index adee75e4..0de25c99 100644 --- a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h +++ b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h @@ -4,10 +4,6 @@ #include "CanBattery.h" #include "GEELY-GEOMETRY-C-HTML.h" -#ifdef GEELY_GEOMETRY_C_BATTERY -#define SELECTED_BATTERY_CLASS GeelyGeometryCBattery -#endif - class GeelyGeometryCBattery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.h b/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.h index a6cff594..613e3628 100644 --- a/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.h +++ b/Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.h @@ -6,10 +6,6 @@ #include "CanBattery.h" #include "HYUNDAI-IONIQ-28-BATTERY-HTML.h" -#ifdef HYUNDAI_IONIQ_28_BATTERY -#define SELECTED_BATTERY_CLASS HyundaiIoniq28Battery -#endif - class HyundaiIoniq28Battery : public CanBattery { public: // Use the default constructor to create the first or single battery. diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h index d905aa30..90a3b6b1 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h @@ -2,10 +2,6 @@ #define IMIEV_CZERO_ION_BATTERY_H #include "CanBattery.h" -#ifdef IMIEV_CZERO_ION_BATTERY -#define SELECTED_BATTERY_CLASS ImievCZeroIonBattery -#endif - class ImievCZeroIonBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.h b/Software/src/battery/JAGUAR-IPACE-BATTERY.h index aae6e428..20cc25e1 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.h +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" -#ifdef JAGUAR_IPACE_BATTERY -#define SELECTED_BATTERY_CLASS JaguarIpaceBattery -#endif - class JaguarIpaceBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/KIA-64FD-BATTERY.h b/Software/src/battery/KIA-64FD-BATTERY.h index 2b2806c9..5a8638a6 100644 --- a/Software/src/battery/KIA-64FD-BATTERY.h +++ b/Software/src/battery/KIA-64FD-BATTERY.h @@ -5,10 +5,6 @@ #define ESTIMATE_SOC_FROM_CELLVOLTAGE -#ifdef KIA_HYUNDAI_64_FD_BATTERY -#define SELECTED_BATTERY_CLASS Kia64FDBattery -#endif - class Kia64FDBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.h b/Software/src/battery/KIA-E-GMP-BATTERY.h index 461f7d4a..2e71c6ff 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.h +++ b/Software/src/battery/KIA-E-GMP-BATTERY.h @@ -5,10 +5,6 @@ #define ESTIMATE_SOC_FROM_CELLVOLTAGE -#ifdef KIA_E_GMP_BATTERY -#define SELECTED_BATTERY_CLASS KiaEGmpBattery -#endif - class KiaEGmpBattery : public CanBattery { public: KiaEGmpBattery() : renderer(*this) {} diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h index 1e991465..832c0e9a 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h @@ -5,10 +5,6 @@ #include "CanBattery.h" #include "KIA-HYUNDAI-64-HTML.h" -#ifdef KIA_HYUNDAI_64_BATTERY -#define SELECTED_BATTERY_CLASS KiaHyundai64Battery -#endif - class KiaHyundai64Battery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h index 95e84e45..3bd9f499 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h @@ -2,10 +2,6 @@ #define KIA_HYUNDAI_HYBRID_BATTERY_H #include "CanBattery.h" -#ifdef KIA_HYUNDAI_HYBRID_BATTERY -#define SELECTED_BATTERY_CLASS KiaHyundaiHybridBattery -#endif - class KiaHyundaiHybridBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/MEB-BATTERY.h b/Software/src/battery/MEB-BATTERY.h index 0751fe6e..d4ea6c60 100644 --- a/Software/src/battery/MEB-BATTERY.h +++ b/Software/src/battery/MEB-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" #include "MEB-HTML.h" -#ifdef MEB_BATTERY -#define SELECTED_BATTERY_CLASS MebBattery -#endif - class MebBattery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/MG-5-BATTERY.h b/Software/src/battery/MG-5-BATTERY.h index 21db48ab..3f8b8650 100644 --- a/Software/src/battery/MG-5-BATTERY.h +++ b/Software/src/battery/MG-5-BATTERY.h @@ -2,10 +2,6 @@ #define MG_5_BATTERY_H #include "CanBattery.h" -#ifdef MG_5_BATTERY -#define SELECTED_BATTERY_CLASS Mg5Battery -#endif - class Mg5Battery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/MG-HS-PHEV-BATTERY.h b/Software/src/battery/MG-HS-PHEV-BATTERY.h index 81ef6dc9..7a9ade7b 100644 --- a/Software/src/battery/MG-HS-PHEV-BATTERY.h +++ b/Software/src/battery/MG-HS-PHEV-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" -#ifdef MG_HS_PHEV_BATTERY -#define SELECTED_BATTERY_CLASS MgHsPHEVBattery -#endif - class MgHsPHEVBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.h b/Software/src/battery/NISSAN-LEAF-BATTERY.h index 034b7b78..99a5691b 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.h +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.h @@ -6,10 +6,6 @@ #include "CanBattery.h" #include "NISSAN-LEAF-HTML.h" -#ifdef NISSAN_LEAF_BATTERY -#define SELECTED_BATTERY_CLASS NissanLeafBattery -#endif - class NissanLeafBattery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/ORION-BMS.h b/Software/src/battery/ORION-BMS.h index eaf03c59..45d267d6 100644 --- a/Software/src/battery/ORION-BMS.h +++ b/Software/src/battery/ORION-BMS.h @@ -4,10 +4,6 @@ #include "../system_settings.h" #include "CanBattery.h" -#ifdef ORION_BMS -#define SELECTED_BATTERY_CLASS OrionBms -#endif - class OrionBms : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/PYLON-BATTERY.h b/Software/src/battery/PYLON-BATTERY.h index bc88ba99..f6b5d75b 100644 --- a/Software/src/battery/PYLON-BATTERY.h +++ b/Software/src/battery/PYLON-BATTERY.h @@ -4,10 +4,6 @@ #include "../datalayer/datalayer.h" #include "CanBattery.h" -#ifdef PYLON_BATTERY -#define SELECTED_BATTERY_CLASS PylonBattery -#endif - class PylonBattery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h index 2207188a..82dc4f01 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" -#ifdef RANGE_ROVER_PHEV_BATTERY -#define SELECTED_BATTERY_CLASS RangeRoverPhevBattery -#endif - class RangeRoverPhevBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/RELION-LV-BATTERY.h b/Software/src/battery/RELION-LV-BATTERY.h index 53c59431..bee6f09b 100644 --- a/Software/src/battery/RELION-LV-BATTERY.h +++ b/Software/src/battery/RELION-LV-BATTERY.h @@ -4,10 +4,6 @@ #include "../system_settings.h" #include "CanBattery.h" -#ifdef RELION_BATTERY -#define SELECTED_BATTERY_CLASS RelionBattery -#endif - class RelionBattery : public CanBattery { public: RelionBattery() : CanBattery(CAN_Speed::CAN_SPEED_250KBPS) {} diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.h b/Software/src/battery/RENAULT-KANGOO-BATTERY.h index 77eb0b3f..0fc8c8cf 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.h +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" -#ifdef RENAULT_KANGOO_BATTERY -#define SELECTED_BATTERY_CLASS RenaultKangooBattery -#endif - class RenaultKangooBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/RENAULT-TWIZY.h b/Software/src/battery/RENAULT-TWIZY.h index d9c71f7d..00891cb4 100644 --- a/Software/src/battery/RENAULT-TWIZY.h +++ b/Software/src/battery/RENAULT-TWIZY.h @@ -2,10 +2,6 @@ #define RENAULT_TWIZY_BATTERY_H #include "CanBattery.h" -#ifdef RENAULT_TWIZY_BATTERY -#define SELECTED_BATTERY_CLASS RenaultTwizyBattery -#endif - class RenaultTwizyBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h index d004f373..1e5d7631 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h @@ -4,10 +4,6 @@ #include "CanBattery.h" #include "RENAULT-ZOE-GEN1-HTML.h" -#ifdef RENAULT_ZOE_GEN1_BATTERY -#define SELECTED_BATTERY_CLASS RenaultZoeGen1Battery -#endif - class RenaultZoeGen1Battery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h index 0c540877..04a60465 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h @@ -4,10 +4,6 @@ #include "CanBattery.h" #include "RENAULT-ZOE-GEN2-HTML.h" -#ifdef RENAULT_ZOE_GEN2_BATTERY -#define SELECTED_BATTERY_CLASS RenaultZoeGen2Battery -#endif - class RenaultZoeGen2Battery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/RJXZS-BMS.h b/Software/src/battery/RJXZS-BMS.h index d616f31a..6d549752 100644 --- a/Software/src/battery/RJXZS-BMS.h +++ b/Software/src/battery/RJXZS-BMS.h @@ -4,10 +4,6 @@ #include "../system_settings.h" #include "CanBattery.h" -#ifdef RJXZS_BMS -#define SELECTED_BATTERY_CLASS RjxzsBms -#endif - class RjxzsBms : public CanBattery { public: RjxzsBms() : CanBattery(CAN_Speed::CAN_SPEED_250KBPS) {} diff --git a/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h index 61da5b9f..b46a22fe 100644 --- a/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h +++ b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h @@ -4,10 +4,6 @@ #include "../datalayer/datalayer.h" #include "CanBattery.h" -#ifdef SAMSUNG_SDI_LV_BATTERY -#define SELECTED_BATTERY_CLASS SamsungSdiLVBattery -#endif - class SamsungSdiLVBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h index 9e9ec2bf..5fbabaff 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h @@ -3,10 +3,6 @@ #include "../datalayer/datalayer.h" #include "CanBattery.h" -#ifdef SANTA_FE_PHEV_BATTERY -#define SELECTED_BATTERY_CLASS SantaFePhevBattery -#endif - class SantaFePhevBattery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/SIMPBMS-BATTERY.h b/Software/src/battery/SIMPBMS-BATTERY.h index 9295c635..3d7cce8b 100644 --- a/Software/src/battery/SIMPBMS-BATTERY.h +++ b/Software/src/battery/SIMPBMS-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" -#ifdef SIMPBMS_BATTERY -#define SELECTED_BATTERY_CLASS SimpBmsBattery -#endif - class SimpBmsBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/SONO-BATTERY.h b/Software/src/battery/SONO-BATTERY.h index 6721a301..1544c02a 100644 --- a/Software/src/battery/SONO-BATTERY.h +++ b/Software/src/battery/SONO-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" -#ifdef SONO_BATTERY -#define SELECTED_BATTERY_CLASS SonoBattery -#endif - class SonoBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/Shunts.cpp b/Software/src/battery/Shunts.cpp index 45578f2a..b8f5fcc7 100644 --- a/Software/src/battery/Shunts.cpp +++ b/Software/src/battery/Shunts.cpp @@ -4,11 +4,6 @@ CanShunt* shunt = nullptr; ShuntType user_selected_shunt_type = ShuntType::None; -#ifdef COMMON_IMAGE -#ifdef SELECTED_SHUNT_CLASS -#error "Compile time SELECTED_SHUNT_CLASS should not be defined with COMMON_IMAGE" -#endif - void setup_can_shunt() { if (shunt) { return; @@ -30,21 +25,6 @@ void setup_can_shunt() { } } -#else -void setup_can_shunt() { - if (shunt) { - return; - } - -#if defined(SELECTED_SHUNT_CLASS) - shunt = new SELECTED_SHUNT_CLASS(); - if (shunt) { - shunt->setup(); - } -#endif -} -#endif - extern std::vector supported_shunt_types() { std::vector types; diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index fca5a83b..6276cf3c 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -4,13 +4,6 @@ #include "CanBattery.h" #include "TESLA-HTML.h" -#ifdef TESLA_MODEL_3Y_BATTERY -#define SELECTED_BATTERY_CLASS TeslaModel3YBattery -#endif -#ifdef TESLA_MODEL_SX_BATTERY -#define SELECTED_BATTERY_CLASS TeslaModelSXBattery -#endif - // 0x7FF gateway config, "Gen3" vehicles only, not applicable to Gen2 "classic" Model S and Model X // These are user configurable from the Webserver UI extern bool user_selected_tesla_digital_HVIL; diff --git a/Software/src/battery/TEST-FAKE-BATTERY.h b/Software/src/battery/TEST-FAKE-BATTERY.h index 012a0363..b2d6bae5 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.h +++ b/Software/src/battery/TEST-FAKE-BATTERY.h @@ -3,10 +3,6 @@ #include "../datalayer/datalayer.h" #include "CanBattery.h" -#ifdef TEST_FAKE_BATTERY -#define SELECTED_BATTERY_CLASS TestFakeBattery -#endif - class TestFakeBattery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.h b/Software/src/battery/VOLVO-SPA-BATTERY.h index b5d4fcad..3c5dbbce 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.h +++ b/Software/src/battery/VOLVO-SPA-BATTERY.h @@ -4,10 +4,6 @@ #include "CanBattery.h" #include "VOLVO-SPA-HTML.h" -#ifdef VOLVO_SPA_BATTERY -#define SELECTED_BATTERY_CLASS VolvoSpaBattery -#endif - class VolvoSpaBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h index 62339c0a..4e44baef 100644 --- a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h @@ -3,10 +3,6 @@ #include "CanBattery.h" #include "VOLVO-SPA-HYBRID-HTML.h" -#ifdef VOLVO_SPA_HYBRID_BATTERY -#define SELECTED_BATTERY_CLASS VolvoSpaHybridBattery -#endif - class VolvoSpaHybridBattery : public CanBattery { public: virtual void setup(void); diff --git a/Software/src/charger/CHARGERS.cpp b/Software/src/charger/CHARGERS.cpp index 2ab85110..22e7d8c5 100644 --- a/Software/src/charger/CHARGERS.cpp +++ b/Software/src/charger/CHARGERS.cpp @@ -30,16 +30,11 @@ extern const char* name_for_charger_type(ChargerType type) { } void setup_charger() { -#ifdef COMMON_IMAGE + switch (user_selected_charger_type) { case ChargerType::ChevyVolt: charger = new ChevyVoltCharger(); case ChargerType::NissanLeaf: charger = new NissanLeafCharger(); } -#else -#ifdef SELECTED_CHARGER_CLASS - charger = new SELECTED_CHARGER_CLASS(); -#endif -#endif } diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 83d2b6c1..9e72d8cc 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -87,7 +87,6 @@ void init_stored_settings() { datalayer.battery.settings.user_set_bms_reset_duration_ms = temp; } -#ifdef COMMON_IMAGE user_selected_battery_type = (BatteryType)settings.getUInt("BATTTYPE", (int)BatteryType::None); user_selected_battery_chemistry = (battery_chemistry_enum)settings.getUInt("BATTCHEM", (int)battery_chemistry_enum::NCA); @@ -168,8 +167,6 @@ void init_stored_settings() { mqtt_user = settings.getString("MQTTUSER").c_str(); mqtt_password = settings.getString("MQTTPASSWORD").c_str(); -#endif - settings.end(); } diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index f23d3be4..36452c84 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -15,29 +15,11 @@ #include "mqtt.h" #include "mqtt_client.h" -#ifdef MQTT -const bool mqtt_enabled_default = true; -#else -const bool mqtt_enabled_default = false; -#endif +bool mqtt_enabled = false; +bool ha_autodiscovery_enabled = false; -bool mqtt_enabled = mqtt_enabled_default; - -#ifdef HA_AUTODISCOVERY -const bool ha_autodiscovery_enabled_default = true; -#else -const bool ha_autodiscovery_enabled_default = false; -#endif - -bool ha_autodiscovery_enabled = ha_autodiscovery_enabled_default; - -#ifdef COMMON_IMAGE const int mqtt_port_default = 0; const char* mqtt_server_default = ""; -#else -const int mqtt_port_default = MQTT_PORT; -const char* mqtt_server_default = MQTT_SERVER; -#endif int mqtt_port = mqtt_port_default; std::string mqtt_server = mqtt_server_default; @@ -626,7 +608,7 @@ bool init_mqtt(void) { } if (mqtt_manual_topic_object_name) { -#ifdef COMMON_IMAGE + BatteryEmulatorSettingsStore settings; topic_name = settings.getString("MQTTTOPIC", mqtt_topic_name); object_id_prefix = settings.getString("MQTTOBJIDPREFIX", mqtt_object_id_prefix); @@ -649,13 +631,6 @@ bool init_mqtt(void) { device_id = ha_device_id; } -#else - // Use custom topic name, object ID prefix, and device name from user settings - topic_name = mqtt_topic_name; - object_id_prefix = mqtt_object_id_prefix; - device_name = mqtt_device_name; - device_id = ha_device_id; -#endif } else { // Use default naming based on WiFi hostname for topic, object ID prefix, and device name topic_name = "battery-emulator_" + String(WiFi.getHostname()); diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index cc4ffc14..7414d53f 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -135,12 +135,6 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return String(ssid.c_str()); } -#ifndef COMMON_IMAGE - if (var == "COMMONIMAGEDIVCLASS") { - return "hidden"; - } -#endif - if (var == "SAVEDCLASS") { if (!settingsUpdated) { return "hidden"; @@ -839,7 +833,7 @@ const char* getCANInterfaceName(CAN_Interface interface) {

SSID: %SSID%

Password: ########

-
diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 6b6102e4..8ef745fa 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -23,21 +23,10 @@ extern std::string http_username; extern std::string http_password; -#ifdef WEBSERVER -const bool webserver_enabled_default = true; -#else -const bool webserver_enabled_default = false; -#endif +bool webserver_enabled = + true; // Global flag to enable or disable the webserver //Old method to disable was with #ifdef WEBSERVER -bool webserver_enabled = webserver_enabled_default; // Global flag to enable or disable the webserver - -#ifndef COMMON_IMAGE -const bool webserver_auth_default = WEBSERVER_AUTH_REQUIRED; -#else -const bool webserver_auth_default = false; -#endif - -bool webserver_auth = webserver_auth_default; +bool webserver_auth = false; // Create AsyncWebServer object on port 80 AsyncWebServer server(80); @@ -401,7 +390,6 @@ void init_webserver() { request->send(200, "text/html", "OK"); }); -#ifdef COMMON_IMAGE struct BoolSetting { const char* name; bool existingValue; @@ -557,7 +545,6 @@ void init_webserver() { settingsUpdated = settings.were_settings_updated(); request->redirect("/settings"); }); -#endif // Route for editing SSID def_route_with_auth("/updateSSID", server, HTTP_GET, [](AsyncWebServerRequest* request) { @@ -908,9 +895,6 @@ String processor(const String& var) { content += "
"; content += "

Software: " + String(version_number); -#ifdef COMMON_IMAGE - content += " (Common image) "; -#endif // Show hardware used: #ifdef HW_LILYGO content += " Hardware: LilyGo T-CAN485"; diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 53425b0d..44adc907 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -12,17 +12,7 @@ const bool wifi_enabled_default = false; bool wifi_enabled = wifi_enabled_default; -#ifdef COMMON_IMAGE -const bool wifiap_enabled_default = true; -#else -#ifdef WIFIAP -const bool wifiap_enabled_default = true; -#else -const bool wifiap_enabled_default = false; -#endif -#endif - -bool wifiap_enabled = wifiap_enabled_default; +bool wifiap_enabled = true; //Old method was with ifdef #ifdef MDNSRESPONDER const bool mdns_enabled_default = true; diff --git a/Software/src/inverter/INVERTERS.cpp b/Software/src/inverter/INVERTERS.cpp index cbd64f4b..37b88d2d 100644 --- a/Software/src/inverter/INVERTERS.cpp +++ b/Software/src/inverter/INVERTERS.cpp @@ -96,11 +96,6 @@ extern const char* name_for_inverter_type(InverterProtocolType type) { return nullptr; } -#ifdef COMMON_IMAGE -#ifdef SELECTED_INVERTER_CLASS -#error "Compile time SELECTED_INVERTER_CLASS should not be defined with COMMON_IMAGE" -#endif - bool setup_inverter() { if (inverter) { return true; @@ -205,24 +200,3 @@ bool setup_inverter() { return false; } - -#else -bool setup_inverter() { - if (inverter) { - // The inverter is setup only once. - return true; - } - -#ifdef SELECTED_INVERTER_CLASS - inverter = new SELECTED_INVERTER_CLASS(); - - if (inverter) { - return inverter->setup(); - } - - return false; -#else - return true; -#endif -} -#endif diff --git a/Software/src/inverter/INVERTERS.h b/Software/src/inverter/INVERTERS.h index b8207f7d..08d411ef 100644 --- a/Software/src/inverter/INVERTERS.h +++ b/Software/src/inverter/INVERTERS.h @@ -7,11 +7,6 @@ extern InverterProtocol* inverter; #include "../../USER_SETTINGS.h" #include "AFORE-CAN.h" - -#ifdef BYD_CAN_DEYE -#define BYD_CAN -#endif - #include "BYD-CAN.h" #include "BYD-MODBUS.h" #include "FERROAMP-CAN.h" diff --git a/platformio.ini b/platformio.ini index b411b41c..f4a37b8f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -28,7 +28,7 @@ monitor_speed = 115200 monitor_filters = default, time, log2file board_build.partitions = min_spiffs.csv framework = arduino -build_flags = -I include -DHW_LILYGO -DCOMMON_IMAGE +build_flags = -I include -DHW_LILYGO lib_deps = [env:stark_330] @@ -38,17 +38,7 @@ monitor_speed = 115200 monitor_filters = default, time, log2file, esp32_exception_decoder board_build.partitions = min_spiffs.csv framework = arduino -build_flags = -I include -DHW_STARK -DCOMMON_IMAGE -lib_deps = - -[env:stark_330_debuglog] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30/platform-espressif32.zip -board = esp32dev -monitor_speed = 115200 -monitor_filters = default, time, log2file, esp32_exception_decoder -board_build.partitions = min_spiffs.csv -framework = arduino -build_flags = -I include -DHW_STARK -DCOMMON_IMAGE -DDEBUG_VIA_USB +build_flags = -I include -DHW_STARK lib_deps = [env:lilygo_2CAN_330] @@ -62,7 +52,6 @@ framework = arduino build_flags = -I include -D HW_LILYGO2CAN - -D COMMON_IMAGE -D BOARD_HAS_PSRAM -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 ;1 is to use the USB port as a serial port From 21b2b06dabf31760001c2f863d4a6aebecaa6bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 15:23:02 +0300 Subject: [PATCH 009/150] Remove USER_SECRETS --- .../compile-common-image-lilygo-2CAN.yml | 4 ---- .../compile-common-image-lilygo-TCAN.yml | 4 ---- .../workflows/compile-common-image-stark.yml | 4 ---- Software/Software.ino | 1 - Software/USER_SECRETS.TEMPLATE.h | 22 ------------------- Software/USER_SETTINGS.cpp | 1 - Software/src/devboard/mqtt/mqtt.cpp | 1 - Software/src/devboard/webserver/webserver.cpp | 1 - 8 files changed, 38 deletions(-) delete mode 100644 Software/USER_SECRETS.TEMPLATE.h diff --git a/.github/workflows/compile-common-image-lilygo-2CAN.yml b/.github/workflows/compile-common-image-lilygo-2CAN.yml index 9972c4c4..d6083cd7 100644 --- a/.github/workflows/compile-common-image-lilygo-2CAN.yml +++ b/.github/workflows/compile-common-image-lilygo-2CAN.yml @@ -44,10 +44,6 @@ jobs: - name: Install PlatformIO Core run: pip install --upgrade platformio - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - name: Build image for Lilygo run: pio run -e lilygo_2CAN_330 diff --git a/.github/workflows/compile-common-image-lilygo-TCAN.yml b/.github/workflows/compile-common-image-lilygo-TCAN.yml index aee0a9bc..e5908572 100644 --- a/.github/workflows/compile-common-image-lilygo-TCAN.yml +++ b/.github/workflows/compile-common-image-lilygo-TCAN.yml @@ -44,10 +44,6 @@ jobs: - name: Install PlatformIO Core run: pip install --upgrade platformio - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - name: Build image for Lilygo run: pio run -e lilygo_330 diff --git a/.github/workflows/compile-common-image-stark.yml b/.github/workflows/compile-common-image-stark.yml index 8f763dc0..eba9d656 100644 --- a/.github/workflows/compile-common-image-stark.yml +++ b/.github/workflows/compile-common-image-stark.yml @@ -44,10 +44,6 @@ jobs: - name: Install PlatformIO Core run: pip install --upgrade platformio - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - name: Build image for Stark CMR run: pio run -e stark_330 diff --git a/Software/Software.ino b/Software/Software.ino index 98fe5f8e..e26fc42f 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -1,7 +1,6 @@ /* Do not change any code below this line unless you are sure what you are doing */ /* Only change battery specific settings in "USER_SETTINGS.h" */ #include "HardwareSerial.h" -#include "USER_SECRETS.h" #include "USER_SETTINGS.h" #include "esp_system.h" #include "esp_task_wdt.h" diff --git a/Software/USER_SECRETS.TEMPLATE.h b/Software/USER_SECRETS.TEMPLATE.h deleted file mode 100644 index d2faf71f..00000000 --- a/Software/USER_SECRETS.TEMPLATE.h +++ /dev/null @@ -1,22 +0,0 @@ -/* This file should be renamed to USER_SECRETS.h to be able to use the software! -It contains all the credentials that should never be made public */ -#ifndef COMMON_IMAGE - -//Password to the access point generated by the Battery-Emulator -#define AP_PASSWORD "123456789" // Minimum of 8 characters; set to blank if you want the access point to be open - -//Name and password of Wifi network you want the emulator to connect to -#define WIFI_SSID "REPLACE_WITH_YOUR_SSID" // Maximum of 63 characters -#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD" // Minimum of 8 characters - -//Set WEBSERVER_AUTH_REQUIRED to true to require a password when accessing the webserver homepage. Improves cybersecurity. -#define WEBSERVER_AUTH_REQUIRED false -#define HTTP_USERNAME "admin" // Username for webserver authentication -#define HTTP_PASSWORD "admin" // Password for webserver authentication - -//MQTT credentials -#define MQTT_SERVER "192.168.xxx.yyy" // MQTT server address -#define MQTT_PORT 1883 // MQTT server port -#define MQTT_USER "" // MQTT username, leave blank for no authentication -#define MQTT_PASSWORD "" // MQTT password, leave blank for no authentication -#endif diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 134c50d3..48cf2c9b 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -1,6 +1,5 @@ #include "USER_SETTINGS.h" #include -#include "USER_SECRETS.h" #include "src/devboard/hal/hal.h" /* This file contains all the battery settings and limits */ diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index 36452c84..108baf6d 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -4,7 +4,6 @@ #include #include #include -#include "../../../USER_SECRETS.h" #include "../../../USER_SETTINGS.h" #include "../../battery/BATTERIES.h" #include "../../communication/contactorcontrol/comm_contactorcontrol.h" diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 8ef745fa..70c862e4 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -2,7 +2,6 @@ #include #include #include -#include "../../../USER_SECRETS.h" #include "../../battery/BATTERIES.h" #include "../../battery/Battery.h" #include "../../charger/CHARGERS.h" From 024ff58965cf43f70fa1caa5c5c61898a2261920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 15:34:28 +0300 Subject: [PATCH 010/150] Remove secrets copy from tests --- .github/workflows/unit-tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 3b385bc8..081538cc 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -13,7 +13,6 @@ jobs: - name: Configure and build with CMake run: | - cp Software/USER_SECRETS.TEMPLATE.h Software/USER_SECRETS.h cd test mkdir build cd build From cf68489bf862ef32aebbb7eb6089f7081e0947ed Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Sep 2025 16:29:53 +0000 Subject: [PATCH 011/150] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-clang-format: v20.1.8 → v21.1.0](https://github.com/pre-commit/mirrors-clang-format/compare/v20.1.8...v21.1.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3563e969..cc342f1e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ ci: repos: - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v20.1.8 + rev: v21.1.0 hooks: - id: clang-format args: [-Werror] # change formatting warnings to errors, hook includes -i (Inplace edit) by default From 5c3aaf0a22b4ac9a30c0fa10cc45fa9c350d7932 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Sep 2025 16:31:01 +0000 Subject: [PATCH 012/150] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../webserver/advanced_battery_html.cpp | 75 ++++--------------- Software/src/inverter/KOSTAL-RS485.h | 2 +- Software/src/inverter/PYLON-CAN.cpp | 2 +- Software/src/inverter/SOLXPOW-CAN.cpp | 2 +- 4 files changed, 19 insertions(+), 62 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index c3ea86d1..2f9e6ebe 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -8,83 +8,40 @@ // Available generic battery commands that are taken into use based on what the selected battery supports. std::vector battery_commands = { {"clearIsolation", "Clear isolation fault", "clear any active isolation fault?", - [](Battery* b) { return b && b->supports_clear_isolation(); }, - [](Battery* b) { - b->clear_isolation(); - }}, + [](Battery* b) { return b && b->supports_clear_isolation(); }, [](Battery* b) { b->clear_isolation(); }}, {"chademoRestart", "Restart", "restart the V2X session?", - [](Battery* b) { return b && b->supports_chademo_restart(); }, - [](Battery* b) { - b->chademo_restart(); - }}, + [](Battery* b) { return b && b->supports_chademo_restart(); }, [](Battery* b) { b->chademo_restart(); }}, {"chademoStop", "Stop", "stop V2X?", [](Battery* b) { return b && b->supports_chademo_restart(); }, - [](Battery* b) { - b->chademo_restart(); - }}, + [](Battery* b) { b->chademo_restart(); }}, {"resetBMS", "BMS reset", "reset the BMS?", [](Battery* b) { return b && b->supports_reset_BMS(); }, - [](Battery* b) { - b->reset_BMS(); - }}, + [](Battery* b) { b->reset_BMS(); }}, {"resetSOC", "SOC reset", "reset SOC?", [](Battery* b) { return b && b->supports_reset_SOC(); }, - [](Battery* b) { - b->reset_SOC(); - }}, + [](Battery* b) { b->reset_SOC(); }}, {"resetCrash", "Unlock crashed BMS", "reset crash data? Note this will unlock your BMS and enable contactor closing and SOC calculation.", - [](Battery* b) { return b && b->supports_reset_crash(); }, - [](Battery* b) { - b->reset_crash(); - }}, + [](Battery* b) { return b && b->supports_reset_crash(); }, [](Battery* b) { b->reset_crash(); }}, {"resetNVROL", "Perform NVROL reset", "trigger an NVROL reset? Battery will be unavailable for 30 seconds while this is active!", - [](Battery* b) { return b && b->supports_reset_NVROL(); }, - [](Battery* b) { - b->reset_NVROL(); - }}, + [](Battery* b) { return b && b->supports_reset_NVROL(); }, [](Battery* b) { b->reset_NVROL(); }}, {"resetContactor", "Perform contactor reset", "reset contactors?", - [](Battery* b) { return b && b->supports_contactor_reset(); }, - [](Battery* b) { - b->reset_contactor(); - }}, + [](Battery* b) { return b && b->supports_contactor_reset(); }, [](Battery* b) { b->reset_contactor(); }}, {"resetDTC", "Erase DTC", "erase DTCs?", [](Battery* b) { return b && b->supports_reset_DTC(); }, - [](Battery* b) { - b->reset_DTC(); - }}, + [](Battery* b) { b->reset_DTC(); }}, {"readDTC", "Read DTC (result must be checked in CANlog)", nullptr, - [](Battery* b) { return b && b->supports_read_DTC(); }, - [](Battery* b) { - b->read_DTC(); - }}, + [](Battery* b) { return b && b->supports_read_DTC(); }, [](Battery* b) { b->read_DTC(); }}, {"resetBECM", "Restart BECM module", "restart BECM??", [](Battery* b) { return b && b->supports_reset_DTC(); }, - [](Battery* b) { - b->reset_DTC(); - }}, + [](Battery* b) { b->reset_DTC(); }}, {"contactorClose", "Close Contactors", "a contactor close request?", - [](Battery* b) { return b && b->supports_contactor_close(); }, - [](Battery* b) { - b->request_close_contactors(); - }}, + [](Battery* b) { return b && b->supports_contactor_close(); }, [](Battery* b) { b->request_close_contactors(); }}, {"contactorOpen", "Open Contactors", "a contactor open request?", - [](Battery* b) { return b && b->supports_contactor_close(); }, - [](Battery* b) { - b->request_open_contactors(); - }}, + [](Battery* b) { return b && b->supports_contactor_close(); }, [](Battery* b) { b->request_open_contactors(); }}, {"resetSOH", "Reset degradation data", "reset degradation data?", - [](Battery* b) { return b && b->supports_reset_SOH(); }, - [](Battery* b) { - b->reset_SOH(); - }}, + [](Battery* b) { return b && b->supports_reset_SOH(); }, [](Battery* b) { b->reset_SOH(); }}, {"setFactoryMode", "Set Factory Mode", "set factory mode and disable isolation measurement?", - [](Battery* b) { return b && b->supports_factory_mode_method(); }, - [](Battery* b) { - b->set_factory_mode(); - }}, + [](Battery* b) { return b && b->supports_factory_mode_method(); }, [](Battery* b) { b->set_factory_mode(); }}, {"toggleSOC", "Toggle SOC method", "toggle SOC method? This will toggle between ESTIMATED and MEASURED SOC methods.", - [](Battery* b) { return b && b->supports_toggle_SOC_method(); }, - [](Battery* b) { - b->toggle_SOC_method(); - }}, + [](Battery* b) { return b && b->supports_toggle_SOC_method(); }, [](Battery* b) { b->toggle_SOC_method(); }}, }; String advanced_battery_processor(const String& var) { diff --git a/Software/src/inverter/KOSTAL-RS485.h b/Software/src/inverter/KOSTAL-RS485.h index 48c2bc34..aecc3620 100644 --- a/Software/src/inverter/KOSTAL-RS485.h +++ b/Software/src/inverter/KOSTAL-RS485.h @@ -22,7 +22,7 @@ class KostalInverterProtocol : public Rs485InverterProtocol { bool check_kostal_frame_crc(int len); // How many value updates we can go without inverter gets reported as missing \ - // e.g. value set to 12, 12*5sec=60seconds without comm before event is raised + // e.g. value set to 12, 12*5sec=60seconds without comm before event is raised const int RS485_HEALTHY = 12; const uint8_t KOSTAL_FRAMEHEADER[5] = {0x62, 0xFF, 0x02, 0xFF, 0x29}; diff --git a/Software/src/inverter/PYLON-CAN.cpp b/Software/src/inverter/PYLON-CAN.cpp index dabd778f..fa7fde5b 100644 --- a/Software/src/inverter/PYLON-CAN.cpp +++ b/Software/src/inverter/PYLON-CAN.cpp @@ -6,7 +6,7 @@ #define SEND_0 //If defined, the messages will have ID ending with 0 (useful for some inverters) //#define SEND_1 //If defined, the messages will have ID ending with 1 (useful for some inverters) #define INVERT_LOW_HIGH_BYTES //If defined, certain frames will have inverted low/high bytes \ - //useful for some inverters like Sofar that report the voltages incorrect otherwise + //useful for some inverters like Sofar that report the voltages incorrect otherwise //#define SET_30K_OFFSET //If defined, current values are sent with a 30k offest (useful for ferroamp) void PylonInverter:: diff --git a/Software/src/inverter/SOLXPOW-CAN.cpp b/Software/src/inverter/SOLXPOW-CAN.cpp index b29946f1..e54c0dfe 100644 --- a/Software/src/inverter/SOLXPOW-CAN.cpp +++ b/Software/src/inverter/SOLXPOW-CAN.cpp @@ -6,7 +6,7 @@ #define SEND_0 //If defined, the messages will have ID ending with 0 (useful for some inverters) //#define SEND_1 //If defined, the messages will have ID ending with 1 (useful for some inverters) #define INVERT_LOW_HIGH_BYTES //If defined, certain frames will have inverted low/high bytes \ - //useful for some inverters like Sofar that report the voltages incorrect otherwise + //useful for some inverters like Sofar that report the voltages incorrect otherwise //#define SET_30K_OFFSET //If defined, current values are sent with a 30k offest (useful for ferroamp) void SolxpowInverter:: From 12cc542a42d8338a2f739991e344a8b97603b894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 21:27:09 +0300 Subject: [PATCH 013/150] Make tests pass --- Software/src/battery/BMW-IX-BATTERY.cpp | 12 +-- Software/src/battery/BMW-PHEV-BATTERY.cpp | 34 +++----- Software/src/battery/BMW-PHEV-BATTERY.h | 2 + Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 1 + Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 1 + Software/src/battery/CHADEMO-BATTERY.cpp | 12 +-- Software/src/battery/CHADEMO-SHUNTS.cpp | 22 ++--- Software/src/battery/CMFA-EV-BATTERY.cpp | 1 + Software/src/battery/DALY-BMS.cpp | 12 +-- Software/src/battery/FOXESS-BATTERY.cpp | 1 + .../src/battery/GEELY-GEOMETRY-C-BATTERY.cpp | 1 + Software/src/battery/GEELY-GEOMETRY-C-HTML.h | 1 + .../src/battery/IMIEV-CZERO-ION-BATTERY.cpp | 12 +-- Software/src/battery/JAGUAR-IPACE-BATTERY.cpp | 7 +- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 77 +---------------- .../src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 1 + Software/src/battery/KIA-HYUNDAI-64-HTML.h | 1 + .../battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp | 1 + Software/src/battery/MEB-BATTERY.cpp | 3 +- Software/src/battery/MG-5-BATTERY.cpp | 3 +- Software/src/battery/MG-HS-PHEV-BATTERY.cpp | 3 +- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 6 +- .../src/battery/RANGE-ROVER-PHEV-BATTERY.cpp | 2 +- Software/src/battery/RENAULT-TWIZY.cpp | 1 + .../src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 3 +- .../src/battery/SANTA-FE-PHEV-BATTERY.cpp | 2 +- Software/src/battery/SIMPBMS-BATTERY.cpp | 2 +- Software/src/battery/SONO-BATTERY.cpp | 1 + Software/src/battery/TESLA-BATTERY.cpp | 57 ++++++------- Software/src/battery/TEST-FAKE-BATTERY.cpp | 6 -- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 2 +- .../src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp | 2 +- Software/src/devboard/utils/logging.h | 50 ++++++++++- Software/src/inverter/KOSTAL-RS485.cpp | 8 +- Software/src/inverter/KOSTAL-RS485.h | 1 - Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 58 ++++--------- Software/src/inverter/SMA-TRIPOWER-CAN.h | 9 -- Software/src/inverter/SOFAR-CAN.cpp | 5 +- test/CMakeLists.txt | 71 +++++++++++++++- test/emul/Arduino.cpp | 18 ++++ test/emul/Arduino.h | 82 +++++++++++++++++++ test/emul/HardwareSerial.h | 19 ++++- test/emul/Print.h | 2 +- test/emul/Stream.h | 6 +- 44 files changed, 362 insertions(+), 259 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index be16b640..93596ca8 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -37,7 +37,7 @@ uint8_t BmwIXBattery::increment_alive_counter(uint8_t counter) { return counter; } -static byte increment_C0_counter(byte counter) { +static uint8_t increment_C0_counter(uint8_t counter) { counter++; // Reset to 0xF0 if it exceeds 0xFE if (counter > 0xFE) { @@ -459,10 +459,12 @@ void BmwIXBattery::setup(void) { // Performs one time setup at startup void BmwIXBattery::HandleIncomingUserRequest(void) { // Debug user request to open or close the contactors - logging.print("User request: contactor close: "); - logging.print(userRequestContactorClose); - logging.print(" User request: contactor open: "); - logging.println(userRequestContactorOpen); + if (userRequestContactorClose) { + logging.printf("User request: contactor close"); + } + if (userRequestContactorOpen) { + logging.printf("User request: contactor open"); + } if ((userRequestContactorClose == false) && (userRequestContactorOpen == false)) { // do nothing } else if ((userRequestContactorClose == true) && (userRequestContactorOpen == false)) { diff --git a/Software/src/battery/BMW-PHEV-BATTERY.cpp b/Software/src/battery/BMW-PHEV-BATTERY.cpp index 8d76e34b..6e40142e 100644 --- a/Software/src/battery/BMW-PHEV-BATTERY.cpp +++ b/Software/src/battery/BMW-PHEV-BATTERY.cpp @@ -1,5 +1,6 @@ #include "BMW-PHEV-BATTERY.h" #include +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" @@ -149,15 +150,6 @@ uint8_t BmwPhevBattery::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 BmwPhevBattery::processCellVoltages() { const int startByte = 3; // Start reading at byte 3 const int numVoltages = 96; // Number of cell voltage values to process @@ -469,7 +461,7 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) { #endif // DEBUG_LOG && UDS_LOG transmit_can_frame(&BMW_6F1_REQUEST_CONTINUE_MULTIFRAME); gUDSContext.receivedInBatch = 0; // Reset batch count - Serial.println("Sent FC for next batch of 3 frames."); + logging.println("Sent FC for next batch of 3 frames."); } break; @@ -513,18 +505,18 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) { battery_current = ((int32_t)((gUDSContext.UDS_buffer[3] << 24) | (gUDSContext.UDS_buffer[4] << 16) | (gUDSContext.UDS_buffer[5] << 8) | gUDSContext.UDS_buffer[6])) * 0.1; - logging.print("Received current/amps measurement data: "); + logging.printf("Received current/amps measurement data: "); logging.print(battery_current); - logging.print(" - "); + logging.printf(" - "); for (uint16_t i = 0; i < gUDSContext.UDS_bytesReceived; i++) { // Optional leading zero for single-digit hex if (gUDSContext.UDS_buffer[i] < 0x10) { - logging.print("0"); + logging.printf("0"); } - logging.print(gUDSContext.UDS_buffer[i], HEX); - logging.print(" "); + logging.print(gUDSContext.UDS_buffer[i]); + logging.printf(" "); } - logging.println(); // new line at the end + logging.println(""); // new line at the end } //Cell Min/Max @@ -540,14 +532,14 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) { max_cell_voltage = (gUDSContext.UDS_buffer[11] << 8 | gUDSContext.UDS_buffer[12]) / 10; } else { logging.println("Cell Min Max Invalid 65535 or 0..."); - logging.print("Received data: "); + logging.printf("Received data: "); for (uint16_t i = 0; i < gUDSContext.UDS_bytesReceived; i++) { // Optional leading zero for single-digit hex if (gUDSContext.UDS_buffer[i] < 0x10) { - logging.print("0"); + logging.printf("0"); } - logging.print(gUDSContext.UDS_buffer[i], HEX); - logging.print(" "); + logging.print(gUDSContext.UDS_buffer[i]); + logging.printf(" "); } logging.println(); // new line at the end } @@ -678,7 +670,7 @@ void BmwPhevBattery::transmit_can(unsigned long currentMillis) { } void BmwPhevBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "BMW PHEV Battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; //Wakeup the SME wake_battery_via_canbus(); diff --git a/Software/src/battery/BMW-PHEV-BATTERY.h b/Software/src/battery/BMW-PHEV-BATTERY.h index 553e514e..0c6baa39 100644 --- a/Software/src/battery/BMW-PHEV-BATTERY.h +++ b/Software/src/battery/BMW-PHEV-BATTERY.h @@ -10,6 +10,8 @@ class BmwPhevBattery : public CanBattery { virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr const char* Name = "BMW PHEV Battery"; + BatteryHtmlRenderer& get_status_renderer() { return renderer; } private: diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index 7fec034d..b740c11b 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -1,4 +1,5 @@ #include "BOLT-AMPERA-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 14688bf9..7e4137fc 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -1,4 +1,5 @@ #include "BYD-ATTO-3-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index 07257708..40205fbe 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -120,7 +120,7 @@ void ChademoBattery::process_vehicle_charging_session(CAN_frame rx_frame) { uint8_t chargingrate = 0; if (x100_chg_lim.ConstantOfChargingRateIndication > 0) { chargingrate = x102_chg_session.StateOfCharge / x100_chg_lim.ConstantOfChargingRateIndication * 100; - logging.print("Charge Rate (kW): "); + logging.printf("Charge Rate (kW): "); logging.println(chargingrate); } @@ -220,9 +220,9 @@ void ChademoBattery::process_vehicle_charging_limits(CAN_frame rx_frame) { if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage && CHADEMO_Status > CHADEMO_NEGOTIATE) { logging.println("x200 minimum discharge voltage met or exceeded, stopping."); - logging.print("Measured: "); + logging.printf("Measured: "); logging.print(get_measured_voltage()); - logging.print("Minimum voltage: "); + logging.printf("Minimum voltage: "); logging.print(x200_discharge_limits.MinimumDischargeVoltage); CHADEMO_Status = CHADEMO_STOP; } @@ -240,9 +240,9 @@ void ChademoBattery::process_vehicle_discharge_estimate(CAN_frame rx_frame) { if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { previousMillis5000 = currentMillis; - logging.print("x201 availabile vehicle energy, completion time: "); + logging.printf("x201 availabile vehicle energy, completion time: "); logging.println(x201_discharge_estimate.AvailableVehicleEnergy); - logging.print("x201 approx vehicle completion time: "); + logging.printf("x201 approx vehicle completion time: "); logging.println(x201_discharge_estimate.ApproxDischargeCompletionTime); } } @@ -766,7 +766,7 @@ void ChademoBattery::handle_chademo_sequence() { /* check whether contactors ready, because externally dependent upon inverter allow during discharge */ if (contactors_ready) { logging.println("Contactors ready"); - logging.print("Voltage: "); + logging.printf("Voltage: "); logging.println(get_measured_voltage()); /* transition to POWERFLOW state if discharge compatible on both sides */ if (x109_evse_state.discharge_compatible && x102_chg_session.s.status.StatusVehicleDischargeCompatible && diff --git a/Software/src/battery/CHADEMO-SHUNTS.cpp b/Software/src/battery/CHADEMO-SHUNTS.cpp index aa1503f7..b539f315 100644 --- a/Software/src/battery/CHADEMO-SHUNTS.cpp +++ b/Software/src/battery/CHADEMO-SHUNTS.cpp @@ -22,7 +22,6 @@ #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" #include "CHADEMO-BATTERY.h" -#include "src/devboard/utils/logging.h" /* Initial frames received from ISA shunts provide invalid during initialization */ static int framecount = 0; @@ -87,17 +86,6 @@ void ISA_handleFrame(CAN_frame* frame) { case 0x510: case 0x511: - logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - logging.print(" "); - logging.print(frame->ID, HEX); - logging.print(" "); - logging.print(frame->DLC); - logging.print(" "); - for (int i = 0; i < frame->DLC; ++i) { - logging.print(frame->data.u8[i], HEX); - logging.print(" "); - } - logging.println(""); break; case 0x521: @@ -245,7 +233,7 @@ void ISA_initialize() { ISA_STOP(); delay(500); for (int i = 0; i < 8; i++) { - logging.print("ISA Initialization "); + logging.printf("ISA Initialization "); logging.println(i); outframe.data.u8[0] = (0x20 + i); @@ -382,7 +370,7 @@ void ISA_initCurrent() { } void ISA_getCONFIG(uint8_t i) { - logging.print("ISA Get Config "); + logging.printf("ISA Get Config "); logging.println(i); outframe.data.u8[0] = (0x60 + i); @@ -398,7 +386,7 @@ void ISA_getCONFIG(uint8_t i) { } void ISA_getCAN_ID(uint8_t i) { - logging.print("ISA Get CAN ID "); + logging.printf("ISA Get CAN ID "); logging.println(i); outframe.data.u8[0] = (0x50 + i); @@ -418,8 +406,8 @@ void ISA_getCAN_ID(uint8_t i) { } void ISA_getINFO(uint8_t i) { - logging.print("ISA Get INFO "); - logging.println(i, HEX); + logging.printf("ISA Get INFO "); + logging.println(i); outframe.data.u8[0] = (0x70 + i); outframe.data.u8[1] = 0x00; diff --git a/Software/src/battery/CMFA-EV-BATTERY.cpp b/Software/src/battery/CMFA-EV-BATTERY.cpp index 6923c29e..c4856e27 100644 --- a/Software/src/battery/CMFA-EV-BATTERY.cpp +++ b/Software/src/battery/CMFA-EV-BATTERY.cpp @@ -1,4 +1,5 @@ #include "CMFA-EV-BATTERY.h" +#include //unit tests memcpy #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" diff --git a/Software/src/battery/DALY-BMS.cpp b/Software/src/battery/DALY-BMS.cpp index da93f6a4..bf9e00b8 100644 --- a/Software/src/battery/DALY-BMS.cpp +++ b/Software/src/battery/DALY-BMS.cpp @@ -16,7 +16,7 @@ static uint16_t voltage_dV = 0; static uint32_t remaining_capacity_mAh = 0; static uint16_t cellvoltages_mV[48] = {0}; static uint16_t cellvoltage_min_mV = 3700; -static uint16_t cellvoltage_max_mV = 3700; +static uint16_t cellvoltage_max_mV = 0; static uint16_t cell_count = 0; static uint16_t SOC = 0; static bool has_fault = false; @@ -109,12 +109,12 @@ uint32_t decode_uint32be(uint8_t data[8], uint8_t offset) { } void dump_buff(const char* msg, uint8_t* buff, uint8_t len) { - logging.print("[DALY-BMS] "); - logging.print(msg); + logging.printf("[DALY-BMS] "); + logging.printf(msg); for (int i = 0; i < len; i++) { - logging.print(buff[i] >> 4, HEX); - logging.print(buff[i] & 0xf, HEX); - logging.print(" "); + logging.print(buff[i] >> 4); + logging.print(buff[i] & 0xf); + logging.printf(" "); } logging.println(); } diff --git a/Software/src/battery/FOXESS-BATTERY.cpp b/Software/src/battery/FOXESS-BATTERY.cpp index 6ec0509e..22a9d3b8 100644 --- a/Software/src/battery/FOXESS-BATTERY.cpp +++ b/Software/src/battery/FOXESS-BATTERY.cpp @@ -1,4 +1,5 @@ #include "FOXESS-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" diff --git a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp index 6400f077..35b45829 100644 --- a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp +++ b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp @@ -1,4 +1,5 @@ #include "GEELY-GEOMETRY-C-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" diff --git a/Software/src/battery/GEELY-GEOMETRY-C-HTML.h b/Software/src/battery/GEELY-GEOMETRY-C-HTML.h index 7a51f488..0a5dff34 100644 --- a/Software/src/battery/GEELY-GEOMETRY-C-HTML.h +++ b/Software/src/battery/GEELY-GEOMETRY-C-HTML.h @@ -1,6 +1,7 @@ #ifndef _GEELY_GEOMETRY_C_HTML_H #define _GEELY_GEOMETRY_C_HTML_H +#include //For unit test #include "../datalayer/datalayer_extended.h" #include "../devboard/webserver/BatteryHtmlRenderer.h" diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index 694a6d09..d77820a9 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -1,4 +1,5 @@ #include "IMIEV-CZERO-ION-BATTERY.h" +#include //for unit tests #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" @@ -76,17 +77,8 @@ void ImievCZeroIonBattery:: if (!BMU_Detected) { logging.println("BMU not detected, check wiring!"); + //TODO: Raise event } - - logging.println("Battery Values"); - logging.print("BMU SOC: "); - logging.print(BMU_SOC); - logging.print(" BMU Current: "); - logging.print(BMU_Current); - logging.print(" BMU Battery Voltage: "); - logging.print(BMU_PackVoltage); - logging.print(" BMU_Power: "); - logging.print(BMU_Power); } void ImievCZeroIonBattery::handle_incoming_can_frame(CAN_frame rx_frame) { diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp index 2f43438f..4bda3f0c 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp @@ -1,4 +1,5 @@ #include "JAGUAR-IPACE-BATTERY.h" +#include //for unit tests #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" @@ -57,9 +58,9 @@ CAN_frame ipace_keep_alive = {.FD = false, .data = {0x9E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};*/ static void print_units(const char* header, int value, const char* units) { - logging.print(header); - logging.print(value); - logging.print(units); + logging.printf(header); + logging.printf("%d", value); + logging.printf(units); } void JaguarIpaceBattery::update_values() { diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index ba6b1c06..3da4f096 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -55,18 +55,6 @@ uint16_t KiaEGmpBattery::estimateSOC(uint16_t packVoltage, uint16_t cellCount, i // Calculate average cell voltage in millivolts uint16_t avgCellVoltage = compensatedPackVoltageMv / cellCount; - logging.print("Pack: "); - logging.print(packVoltage / 10.0); - logging.print("V, Current: "); - logging.print(currentAmps / 10.0); - logging.print("A, Drop: "); - logging.print(voltageDrop / 1000.0); - logging.print("V, Comp Pack: "); - logging.print(compensatedPackVoltageMv / 1000.0); - logging.print("V, Avg Cell: "); - logging.print(avgCellVoltage); - logging.println("mV"); - // Use the cell voltage lookup table to estimate SOC return estimateSOCFromCell(avgCellVoltage); } @@ -182,65 +170,6 @@ void KiaEGmpBattery::update_values() { if (leadAcidBatteryVoltage < 110) { set_event(EVENT_12V_LOW, leadAcidBatteryVoltage); } - - /* Safeties verified. Perform USB serial printout if configured to do so */ - - logging.println(); //sepatator - logging.println("Values from battery: "); - logging.print("SOC BMS: "); - logging.print((uint16_t)SOC_BMS / 10.0, 1); - logging.print("% | SOC Display: "); - logging.print((uint16_t)SOC_Display / 10.0, 1); - logging.print("% | SOH "); - logging.print((uint16_t)batterySOH / 10.0, 1); - logging.println("%"); - logging.print((int16_t)batteryAmps / 10.0, 1); - logging.print(" Amps | "); - logging.print((uint16_t)batteryVoltage / 10.0, 1); - logging.print(" Volts | "); - logging.print((int16_t)datalayer.battery.status.active_power_W); - logging.println(" Watts"); - logging.print("Allowed Charge "); - logging.print((uint16_t)allowedChargePower * 10); - logging.print(" W | Allowed Discharge "); - logging.print((uint16_t)allowedDischargePower * 10); - logging.println(" W"); - logging.print("MaxCellVolt "); - logging.print(CellVoltMax_mV); - logging.print(" mV No "); - logging.print(CellVmaxNo); - logging.print(" | MinCellVolt "); - logging.print(CellVoltMin_mV); - logging.print(" mV No "); - logging.println(CellVminNo); - logging.print("TempHi "); - logging.print((int16_t)temperatureMax); - logging.print("°C TempLo "); - logging.print((int16_t)temperatureMin); - logging.print("°C WaterInlet "); - logging.print((int8_t)temperature_water_inlet); - logging.print("°C PowerRelay "); - logging.print((int8_t)powerRelayTemperature * 2); - logging.println("°C"); - logging.print("Aux12volt: "); - logging.print((int16_t)leadAcidBatteryVoltage / 10.0, 1); - logging.println("V | "); - logging.print("BmsManagementMode "); - logging.print((uint8_t)batteryManagementMode, BIN); - if (bitRead((uint8_t)BMS_ign, 2) == 1) { - logging.print(" | BmsIgnition ON"); - } else { - logging.print(" | BmsIgnition OFF"); - } - - if (bitRead((uint8_t)batteryRelay, 0) == 1) { - logging.print(" | PowerRelay ON"); - } else { - logging.print(" | PowerRelay OFF"); - } - logging.print(" | Inverter "); - logging.print(inverterVoltage); - logging.println(" Volts"); } // Getter implementations for HTML renderer @@ -321,14 +250,10 @@ void KiaEGmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; break; case 0x7EC: - // print_canfd_frame(frame); switch (rx_frame.data.u8[0]) { case 0x10: //"PID Header" - // logging.println ("Send ack"); poll_data_pid = rx_frame.data.u8[4]; - // if (rx_frame.data.u8[4] == poll_data_pid) { - transmit_can_frame(&EGMP_7E4_ack); //Send ack to BMS if the same frame is sent as polled - // } + transmit_can_frame(&EGMP_7E4_ack); //Send ack to BMS break; case 0x21: //First frame in PID group if (poll_data_pid == 1) { diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index bc499862..af7ce7c4 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -1,4 +1,5 @@ #include "KIA-HYUNDAI-64-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" diff --git a/Software/src/battery/KIA-HYUNDAI-64-HTML.h b/Software/src/battery/KIA-HYUNDAI-64-HTML.h index a982f1e6..bb6f12fa 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-HTML.h +++ b/Software/src/battery/KIA-HYUNDAI-64-HTML.h @@ -1,6 +1,7 @@ #ifndef _KIA_HYUNDAI_64_HTML_H #define _KIA_HYUNDAI_64_HTML_H +#include //For unit test #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" #include "../devboard/webserver/BatteryHtmlRenderer.h" diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp index ff87dc4d..8c8d4ecb 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp @@ -1,4 +1,5 @@ #include "KIA-HYUNDAI-HYBRID-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" diff --git a/Software/src/battery/MEB-BATTERY.cpp b/Software/src/battery/MEB-BATTERY.cpp index 6969ad9d..e0237756 100644 --- a/Software/src/battery/MEB-BATTERY.cpp +++ b/Software/src/battery/MEB-BATTERY.cpp @@ -1,6 +1,7 @@ #include "MEB-BATTERY.h" #include #include // For std::min and std::max +#include //For unit test #include "../communication/can/comm_can.h" #include "../communication/can/obd.h" #include "../datalayer/datalayer.h" @@ -1262,8 +1263,6 @@ void MebBattery::handle_incoming_can_frame(CAN_frame rx_frame) { handle_obd_frame(rx_frame); break; default: - logging.printf("Unknown CAN frame received:\n"); - dump_can_frame(rx_frame, MSG_RX); break; } datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; diff --git a/Software/src/battery/MG-5-BATTERY.cpp b/Software/src/battery/MG-5-BATTERY.cpp index 90c486ca..f2e5f991 100644 --- a/Software/src/battery/MG-5-BATTERY.cpp +++ b/Software/src/battery/MG-5-BATTERY.cpp @@ -1,4 +1,5 @@ #include "MG-5-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" @@ -112,7 +113,7 @@ void Mg5Battery::transmit_can(unsigned long currentMillis) { } void Mg5Battery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "MG 5 battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 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; diff --git a/Software/src/battery/MG-HS-PHEV-BATTERY.cpp b/Software/src/battery/MG-HS-PHEV-BATTERY.cpp index a8395067..57d8476a 100644 --- a/Software/src/battery/MG-HS-PHEV-BATTERY.cpp +++ b/Software/src/battery/MG-HS-PHEV-BATTERY.cpp @@ -1,10 +1,11 @@ #include "MG-HS-PHEV-BATTERY.h" +#include //For unit test +#include //For unit test #include "../communication/can/comm_can.h" #include "../communication/contactorcontrol/comm_contactorcontrol.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" #include "../devboard/utils/logging.h" - /* MG HS PHEV 16.6kWh battery integration diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index be9900d9..17e4f3d3 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1,13 +1,13 @@ #include "NISSAN-LEAF-BATTERY.h" +#include //For unit test +#include "../charger/CHARGERS.h" +#include "../charger/CanCharger.h" #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" //For "More battery info" webpage #include "../devboard/utils/events.h" #include "../devboard/utils/logging.h" -#include "../charger/CHARGERS.h" -#include "../charger/CanCharger.h" - uint16_t Temp_fromRAW_to_F(uint16_t temperature); //Cryptographic functions void decodeChallengeData(unsigned int SeedInput, unsigned char* Crypt_Output_Buffer); diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp index e34cd9ef..7e31bad4 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp @@ -1,8 +1,8 @@ #include "RANGE-ROVER-PHEV-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" - /* TODO - LOG files from vehicle needed to determine CAN content needed to send towards battery! - BCCM_PMZ_A (0x18B 50ms) diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index 3fa74fb1..fd214296 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -1,5 +1,6 @@ #include "RENAULT-TWIZY.h" #include +#include //For unit test #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index 095fb6a1..71fc5e85 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -1,10 +1,9 @@ #include "RENAULT-ZOE-GEN1-BATTERY.h" +#include //For unit test #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" #include "../devboard/utils/events.h" -void transmit_can_frame(CAN_frame* tx_frame, int interface); - /* Information in this file is based of the OVMS V3 vehicle_renaultzoe.cpp component https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/blob/master/vehicle/OVMS.V3/components/vehicle_renaultzoe/src/vehicle_renaultzoe.cpp The Zoe BMS apparently does not send total pack voltage, so we use the polled 96x cellvoltages summed up as total voltage diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index 7cad62fd..e68829c5 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -1,8 +1,8 @@ #include "SANTA-FE-PHEV-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" - /* Credits go to maciek16c for these findings! https://github.com/maciek16c/hyundai-santa-fe-phev-battery https://openinverter.org/forum/viewtopic.php?p=62256 diff --git a/Software/src/battery/SIMPBMS-BATTERY.cpp b/Software/src/battery/SIMPBMS-BATTERY.cpp index bc58c580..27af92be 100644 --- a/Software/src/battery/SIMPBMS-BATTERY.cpp +++ b/Software/src/battery/SIMPBMS-BATTERY.cpp @@ -1,8 +1,8 @@ #include "SIMPBMS-BATTERY.h" +#include //For unit test #include "../battery/BATTERIES.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" - void SimpBmsBattery::update_values() { datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00 diff --git a/Software/src/battery/SONO-BATTERY.cpp b/Software/src/battery/SONO-BATTERY.cpp index c2243720..d99405d2 100644 --- a/Software/src/battery/SONO-BATTERY.cpp +++ b/Software/src/battery/SONO-BATTERY.cpp @@ -1,4 +1,5 @@ #include "SONO-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 8407eed9..3f338ee4 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1,4 +1,5 @@ #include "TESLA-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" //For Advanced Battery Insights webpage @@ -995,52 +996,52 @@ void TeslaBattery:: } printFaultCodesIfActive(); - logging.print("BMS Contactors State: "); - logging.print(getBMSContactorState(battery_contactor)); // Display what state the BMS thinks the contactors are in - logging.print(", HVIL: "); - logging.print(getHvilStatusState(battery_hvil_status)); - logging.print(", NegativeState: "); - logging.print(getContactorState(battery_packContNegativeState)); - logging.print(", PositiveState: "); + logging.printf("BMS Contactors State: "); + logging.printf(getBMSContactorState(battery_contactor)); // Display what state the BMS thinks the contactors are in + logging.printf(", HVIL: "); + logging.printf(getHvilStatusState(battery_hvil_status)); + logging.printf(", NegativeState: "); + logging.printf(getContactorState(battery_packContNegativeState)); + logging.printf(", PositiveState: "); logging.println(getContactorState(battery_packContPositiveState)); - logging.print("HVP Contactors setState: "); - logging.print( + logging.printf("HVP Contactors setState: "); + logging.printf( getContactorText(battery_packContactorSetState)); // Display what state the HVP has set the contactors to be in - logging.print(", Closing blocked: "); - logging.print(getNoYes(battery_packCtrsClosingBlocked)); + logging.printf(", Closing blocked: "); + logging.printf(getNoYes(battery_packCtrsClosingBlocked)); if (battery_packContactorSetState == 5) { - logging.print(" (already CLOSED)"); + logging.printf(" (already CLOSED)"); } - logging.print(", Pyrotest: "); + logging.printf(", Pyrotest: "); logging.println(getNoYes(battery_pyroTestInProgress)); - logging.print("Battery values: "); - logging.print("Real SOC: "); + logging.printf("Battery values: "); + logging.printf("Real SOC: "); logging.print(battery_soc_ui / 10.0, 1); - logging.print(", Battery voltage: "); + logging.printf(", Battery voltage: "); logging.print(battery_volts / 10.0, 1); - logging.print("V"); - logging.print(", Battery HV current: "); + logging.printf("V"); + logging.printf(", Battery HV current: "); logging.print(battery_amps / 10.0, 1); - logging.print("A"); - logging.print(", Fully charged?: "); + logging.printf("A"); + logging.printf(", Fully charged?: "); if (battery_full_charge_complete) - logging.print("YES, "); + logging.printf("YES, "); else - logging.print("NO, "); + logging.printf("NO, "); if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { - logging.print("LFP chemistry detected!"); + logging.printf("LFP chemistry detected!"); } logging.println(""); - logging.print("Cellstats, Max: "); + logging.printf("Cellstats, Max: "); logging.print(battery_cell_max_v); - logging.print("mV (cell "); + logging.printf("mV (cell "); logging.print(battery_BrickVoltageMaxNum); - logging.print("), Min: "); + logging.printf("), Min: "); logging.print(battery_cell_min_v); - logging.print("mV (cell "); + logging.printf("mV (cell "); logging.print(battery_BrickVoltageMinNum); - logging.print("), Imbalance: "); + logging.printf("), Imbalance: "); logging.print(battery_cell_deviation_mV); logging.println("mV."); diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index b7b18bc8..9803e7ee 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -3,12 +3,6 @@ #include "../datalayer/datalayer.h" #include "../devboard/utils/logging.h" -static void print_units(const char* header, int value, const char* units) { - logging.print(header); - logging.print(value); - logging.print(units); -} - void TestFakeBattery:: update_values() { /* This function puts fake values onto the parameters sent towards the inverter */ diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index e251f9c7..5efc48b8 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -1,10 +1,10 @@ #include "VOLVO-SPA-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" //For "More battery info" webpage #include "../devboard/utils/events.h" #include "../devboard/utils/logging.h" - void VolvoSpaBattery:: update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp index 7afc2ada..d99bc995 100644 --- a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp @@ -1,10 +1,10 @@ #include "VOLVO-SPA-HYBRID-BATTERY.h" +#include //For unit test #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../datalayer/datalayer_extended.h" //For "More battery info" webpage #include "../devboard/utils/events.h" #include "../devboard/utils/logging.h" - void VolvoSpaHybridBattery:: update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter uint8_t cnt = 0; diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h index 95ba6910..69a1f170 100644 --- a/Software/src/devboard/utils/logging.h +++ b/Software/src/devboard/utils/logging.h @@ -8,7 +8,6 @@ #ifndef UNIT_TEST // Real implementation for production -#include class Logging : public Print { void add_timestamp(size_t size); @@ -51,12 +50,61 @@ class Logging { (void)fmt; } + // Overloaded print methods for different data types + static void print(const char* str) { (void)str; } + static void print(char c) { (void)c; } + static void print(int8_t num) { (void)num; } + static void print(uint8_t num) { (void)num; } + static void print(int16_t num) { (void)num; } + static void print(uint16_t num) { (void)num; } + static void print(int32_t num) { (void)num; } + static void print(uint32_t num) { (void)num; } + static void print(int64_t num) { (void)num; } + static void print(uint64_t num) { (void)num; } + static void print(float num) { (void)num; } + static void print(double num) { (void)num; } + static void print(bool b) { (void)b; } + + static void print(double num, int precision) { + (void)num; + (void)precision; + } + + static void print(float num, int precision) { + (void)num; + (void)precision; + } + + static void print(int32_t num, int base) { + (void)num; + (void)base; + } + + static void print(uint32_t num, int base) { + (void)num; + (void)base; + } + static void println(const char* str) { (void)str; } + static void println(char c) { (void)c; } + static void println(int8_t num) { (void)num; } + static void println(uint8_t num) { (void)num; } + static void println(int16_t num) { (void)num; } + static void println(uint16_t num) { (void)num; } + static void println(int32_t num) { (void)num; } + static void println(uint32_t num) { (void)num; } + static void println(int64_t num) { (void)num; } + static void println(uint64_t num) { (void)num; } + static void println(float num) { (void)num; } + static void println(double num) { (void)num; } + static void println(bool b) { (void)b; } + static void println() {} // Empty println Logging() {} }; // Test macros - empty implementations +#define DEBUG_PRINT(fmt, ...) ((void)0) #define DEBUG_PRINTF(fmt, ...) ((void)0) #define DEBUG_PRINTLN(str) ((void)0) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 045733e8..7e88f67f 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -14,18 +14,18 @@ void KostalInverterProtocol::float2frame(uint8_t* arr, float value, uint8_t fram } static void dbg_timestamp(void) { - logging.print("["); + logging.printf("["); logging.print(millis()); - logging.print(" ms] "); + logging.printf(" ms] "); } static void dbg_frame(uint8_t* frame, int len, const char* prefix) { dbg_timestamp(); logging.print(prefix); - logging.print(": "); + logging.printf(": "); for (uint8_t i = 0; i < len; i++) { if (frame[i] < 0x10) { - logging.print("0"); + logging.printf("0"); } logging.print(frame[i], HEX); logging.print(" "); diff --git a/Software/src/inverter/KOSTAL-RS485.h b/Software/src/inverter/KOSTAL-RS485.h index 48c2bc34..5301aaed 100644 --- a/Software/src/inverter/KOSTAL-RS485.h +++ b/Software/src/inverter/KOSTAL-RS485.h @@ -20,7 +20,6 @@ class KostalInverterProtocol : public Rs485InverterProtocol { int baud_rate() { return 57600; } void float2frame(uint8_t* arr, float value, uint8_t framepointer); bool check_kostal_frame_crc(int len); - // How many value updates we can go without inverter gets reported as missing \ // e.g. value set to 12, 12*5sec=60seconds without comm before event is raised const int RS485_HEALTHY = 12; diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 172cd4c0..213c530b 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -137,17 +137,6 @@ void SmaTripowerInverter::map_can_frame_to_variable(CAN_frame rx_frame) { } } -void SmaTripowerInverter::pushFrame(CAN_frame* frame, std::function callback) { - if (listLength >= 20) { - return; //TODO: scream. - } - framesToSend[listLength] = { - .frame = frame, - .callback = callback, - }; - listLength++; -} - void SmaTripowerInverter::transmit_can(unsigned long currentMillis) { // Send CAN Message only if we're enabled by inverter @@ -155,18 +144,6 @@ void SmaTripowerInverter::transmit_can(unsigned long currentMillis) { return; } - if (listLength > 0 && currentMillis - previousMillis250ms >= INTERVAL_250_MS) { - previousMillis250ms = currentMillis; - // Send next frame. - Frame frame = framesToSend[0]; - transmit_can_frame(frame.frame); - frame.callback(); - for (int i = 0; i < listLength - 1; i++) { - framesToSend[i] = framesToSend[i + 1]; - } - listLength--; - } - if (!pairing_completed) { return; } @@ -174,19 +151,19 @@ void SmaTripowerInverter::transmit_can(unsigned long currentMillis) { // Send CAN Message every 2s if (currentMillis - previousMillis2s >= INTERVAL_2_S) { previousMillis2s = currentMillis; - pushFrame(&SMA_358); + transmit_can_frame(&SMA_358); } // Send CAN Message every 10s if (currentMillis - previousMillis10s >= INTERVAL_10_S) { previousMillis10s = currentMillis; - pushFrame(&SMA_518); - pushFrame(&SMA_4D8); - pushFrame(&SMA_3D8); + transmit_can_frame(&SMA_518); + transmit_can_frame(&SMA_4D8); + transmit_can_frame(&SMA_3D8); } // Send CAN Message every 60s (potentially SMA_458 is not required for stable operation) if (currentMillis - previousMillis60s >= INTERVAL_60_S) { previousMillis60s = currentMillis; - pushFrame(&SMA_458); + transmit_can_frame(&SMA_458); } } @@ -195,18 +172,17 @@ void SmaTripowerInverter::completePairing() { } void SmaTripowerInverter::transmit_can_init() { - listLength = 0; // clear all frames - pushFrame(&SMA_558); //Pairing start - Vendor - pushFrame(&SMA_598); //Serial - pushFrame(&SMA_5D8); //BYD - pushFrame(&SMA_618_0); //BATTERY - pushFrame(&SMA_618_1); //-Box Pr - pushFrame(&SMA_618_2); //emium H - pushFrame(&SMA_618_3); //VS - pushFrame(&SMA_358); - pushFrame(&SMA_3D8); - pushFrame(&SMA_458); - pushFrame(&SMA_4D8); - pushFrame(&SMA_518, [this]() { this->completePairing(); }); + transmit_can_frame(&SMA_558); //Pairing start - Vendor + transmit_can_frame(&SMA_598); //Serial + transmit_can_frame(&SMA_5D8); //BYD + transmit_can_frame(&SMA_618_0); //BATTERY + transmit_can_frame(&SMA_618_1); //-Box Pr + transmit_can_frame(&SMA_618_2); //emium H + transmit_can_frame(&SMA_618_3); //VS + transmit_can_frame(&SMA_358); + transmit_can_frame(&SMA_3D8); + transmit_can_frame(&SMA_458); + transmit_can_frame(&SMA_4D8); + transmit_can_frame(&SMA_518); } diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index 09397370..ace38bf9 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -24,7 +24,6 @@ class SmaTripowerInverter : public SmaInverterBase { const int THIRTY_MINUTES = 1200; void transmit_can_init(); - void pushFrame(CAN_frame* frame, std::function callback = []() {}); void completePairing(); unsigned long previousMillis250ms = 0; // will store last time a 250ms CAN Message was send @@ -33,14 +32,6 @@ class SmaTripowerInverter : public SmaInverterBase { unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send - typedef struct { - CAN_frame* frame; - std::function callback; - } Frame; - - unsigned short listLength = 0; - Frame framesToSend[20]; - uint32_t inverter_time = 0; uint16_t inverter_voltage = 0; int16_t inverter_current = 0; diff --git a/Software/src/inverter/SOFAR-CAN.cpp b/Software/src/inverter/SOFAR-CAN.cpp index 6779a3a2..23369be7 100644 --- a/Software/src/inverter/SOFAR-CAN.cpp +++ b/Software/src/inverter/SOFAR-CAN.cpp @@ -292,9 +292,8 @@ bool SofarInverter::setup() { // Performs one time setup at startup over CAN bu init_frame(SOFAR_783, 0x783); init_frame(SOFAR_784, 0x784); - String tempStr(datalayer.battery.settings.sofar_user_specified_battery_id); - strncpy(datalayer.system.info.inverter_brand, tempStr.c_str(), 7); - datalayer.system.info.inverter_brand[7] = '\0'; + snprintf(datalayer.system.info.inverter_brand, sizeof(datalayer.system.info.inverter_brand), "%s", + datalayer.battery.settings.sofar_user_specified_battery_id); return true; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b6103027..8d16116c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -85,11 +85,80 @@ add_executable(tests ../Software/USER_SETTINGS.cpp ../Software/src/battery/BATTERIES.cpp ../Software/src/battery/Battery.cpp + ../Software/src/battery/BMW-I3-BATTERY.cpp + ../Software/src/battery/BMW-I3-HTML.cpp + ../Software/src/battery/BMW-IX-BATTERY.cpp + ../Software/src/battery/BMW-IX-HTML.cpp + ../Software/src/battery/BMW-PHEV-BATTERY.cpp + ../Software/src/battery/BMW-SBOX.cpp + ../Software/src/battery/BOLT-AMPERA-BATTERY.cpp + ../Software/src/battery/BYD-ATTO-3-BATTERY.cpp ../Software/src/battery/CanBattery.cpp + ../Software/src/battery/CELLPOWER-BMS.cpp + ../Software/src/battery/CHADEMO-BATTERY.cpp + ../Software/src/battery/CHADEMO-SHUNTS.cpp + ../Software/src/battery/CMFA-EV-BATTERY.cpp + ../Software/src/battery/DALY-BMS.cpp + ../Software/src/battery/ECMP-BATTERY.cpp + ../Software/src/battery/FOXESS-BATTERY.cpp + ../Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp + ../Software/src/battery/HYUNDAI-IONIQ-28-BATTERY-HTML.cpp + ../Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.cpp + ../Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp + ../Software/src/battery/JAGUAR-IPACE-BATTERY.cpp + ../Software/src/battery/KIA-E-GMP-BATTERY.cpp + ../Software/src/battery/KIA-E-GMP-HTML.cpp + ../Software/src/battery/KIA-64FD-BATTERY.cpp + ../Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp + ../Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp + ../Software/src/battery/MEB-BATTERY.cpp + ../Software/src/battery/MG-5-BATTERY.cpp + ../Software/src/battery/MG-HS-PHEV-BATTERY.cpp ../Software/src/battery/NISSAN-LEAF-BATTERY.cpp - ../Software/src/inverter/INVERTERS.cpp + ../Software/src/battery/ORION-BMS.cpp + ../Software/src/battery/PYLON-BATTERY.cpp + ../Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp + ../Software/src/battery/RELION-LV-BATTERY.cpp + ../Software/src/battery/RENAULT-KANGOO-BATTERY.cpp + ../Software/src/battery/RENAULT-TWIZY.cpp + ../Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp + ../Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp + ../Software/src/battery/RJXZS-BMS.cpp + ../Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp + ../Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp + ../Software/src/battery/Shunts.cpp + ../Software/src/battery/SIMPBMS-BATTERY.cpp + ../Software/src/battery/SONO-BATTERY.cpp + ../Software/src/battery/TESLA-BATTERY.cpp + ../Software/src/battery/TEST-FAKE-BATTERY.cpp + ../Software/src/battery/VOLVO-SPA-BATTERY.cpp + ../Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp + ../Software/src/inverter/AFORE-CAN.cpp + ../Software/src/inverter/BYD-CAN.cpp ../Software/src/inverter/BYD-MODBUS.cpp + ../Software/src/inverter/FERROAMP-CAN.cpp + ../Software/src/inverter/FOXESS-CAN.cpp + ../Software/src/inverter/GROWATT-HV-CAN.cpp + ../Software/src/inverter/GROWATT-LV-CAN.cpp + ../Software/src/inverter/GROWATT-WIT-CAN.cpp + ../Software/src/inverter/INVERTERS.cpp + ../Software/src/inverter/KOSTAL-RS485.cpp + ../Software/src/inverter/ModbusInverterProtocol.cpp + ../Software/src/inverter/PYLON-CAN.cpp + ../Software/src/inverter/PYLON-LV-CAN.cpp + ../Software/src/inverter/SCHNEIDER-CAN.cpp + ../Software/src/inverter/SMA-BYD-H-CAN.cpp + ../Software/src/inverter/SMA-BYD-HVS-CAN.cpp + ../Software/src/inverter/SMA-LV-CAN.cpp + ../Software/src/inverter/SMA-TRIPOWER-CAN.cpp + ../Software/src/inverter/SOFAR-CAN.cpp + ../Software/src/inverter/SOL-ARK-LV-CAN.cpp + ../Software/src/inverter/SOLAX-CAN.cpp + ../Software/src/inverter/SOLXPOW-CAN.cpp + ../Software/src/inverter/SUNGROW-CAN.cpp ../Software/src/charger/CHARGERS.cpp + ../Software/src/charger/CHEVY-VOLT-CHARGER.cpp + ../Software/src/charger/NISSAN-LEAF-CHARGER.cpp emul/can.cpp emul/time.cpp emul/serial.cpp diff --git a/test/emul/Arduino.cpp b/test/emul/Arduino.cpp index bdaa38d8..aa0997e0 100644 --- a/test/emul/Arduino.cpp +++ b/test/emul/Arduino.cpp @@ -15,4 +15,22 @@ int max(int a, int b) { return (a > b) ? a : b; } +// Mock implementation for OBD +#include "../../Software/src/communication/can/obd.h" +void handle_obd_frame(CAN_frame& frame) { + (void)frame; +} +void transmit_obd_can_frame(unsigned int address, int interface, bool canFD) { + (void)interface; +} + +void start_bms_reset() {} + +#include "../../Software/src/communication/rs485/comm_rs485.h" + +// Mock implementation +void register_receiver(Rs485Receiver* receiver) { + (void)receiver; // Silence unused parameter warning +} + ESPClass ESP; diff --git a/test/emul/Arduino.h b/test/emul/Arduino.h index 5abc6edb..149191af 100644 --- a/test/emul/Arduino.h +++ b/test/emul/Arduino.h @@ -6,15 +6,97 @@ #include #include +#include +#include +#include +#include +#include + #include "HardwareSerial.h" #include "Logging.h" #include "Print.h" #include "esp-hal-gpio.h" +// Arduino base constants for print formatting +constexpr int BIN = 2; +constexpr int OCT = 8; +constexpr int DEC = 10; +constexpr int HEX = 16; +// Arduino type aliases +using byte = uint8_t; +#define boolean bool +// Arduino random functions +inline long random(long max) { + (void)max; + return 0; // Return a predictable value for testing +} + +inline long random(long min, long max) { + (void)min; + (void)max; + return min; // Return the minimum value for predictability +} + +// Also add randomSeed for completeness +inline void randomSeed(unsigned long seed) { + (void)seed; +} + +inline uint16_t word(uint8_t highByte, uint8_t lowByte) { + return (static_cast(highByte) << 8) | lowByte; +} + +inline uint16_t word(uint16_t w) { + return w; +} + +// Bit manipulation functions +inline uint8_t bitRead(uint8_t value, uint8_t bit) { + return (value >> bit) & 0x01; +} + +inline void bitSet(uint8_t& value, uint8_t bit) { + value |= (1UL << bit); +} + +inline void bitClear(uint8_t& value, uint8_t bit) { + value &= ~(1UL << bit); +} + +inline void bitWrite(uint8_t& value, uint8_t bit, uint8_t bitvalue) { + if (bitvalue) { + bitSet(value, bit); + } else { + bitClear(value, bit); + } +} + +// Byte extraction functions +inline uint8_t lowByte(uint16_t w) { + return static_cast(w & 0xFF); +} + +inline uint8_t highByte(uint16_t w) { + return static_cast(w >> 8); +} + +template +inline const T& min(const T& a, const T& b) { + return (a < b) ? a : b; +} + +template +inline const T& max(const T& a, const T& b) { + return (a > b) ? a : b; +} void pinMode(uint8_t pin, uint8_t mode); void digitalWrite(uint8_t pin, uint8_t val); int digitalRead(uint8_t pin); +inline int analogRead(uint8_t pin) { + (void)pin; + return 0; // Return 0 for predictable tests +} unsigned long micros(); // Can be previously declared as a macro in stupid eModbus diff --git a/test/emul/HardwareSerial.h b/test/emul/HardwareSerial.h index e20000a2..d53f9d5a 100644 --- a/test/emul/HardwareSerial.h +++ b/test/emul/HardwareSerial.h @@ -35,17 +35,28 @@ enum SerialConfig { class HardwareSerial : public Stream { public: - int available() { return 0; } + // Implement ALL pure virtual functions from base classes + int available() override { return 0; } + int read() override { return -1; } + int peek() override { return -1; } + void flush() override {} // Implement flush from Print + size_t write(uint8_t) override { return 0; } // Implement write from Print + + // Your existing methods uint32_t baudRate() { return 9600; } void begin(unsigned long baud, uint32_t config = SERIAL_8N1, int8_t rxPin = -1, int8_t txPin = -1, bool invert = false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 120) {} - int read() { return 0; } void setTxBufferSize(uint16_t size) {} void setRxBufferSize(uint16_t size) {} bool setRxFIFOFull(uint8_t fifoBytes) { return false; } - size_t write(uint8_t) { return 0; } -}; + // Add the buffer write method + size_t write(const uint8_t* buffer, size_t size) override { + (void)buffer; + (void)size; + return 0; + } +}; extern HardwareSerial Serial; extern HardwareSerial Serial1; extern HardwareSerial Serial2; diff --git a/test/emul/Print.h b/test/emul/Print.h index eb715272..256f82d8 100644 --- a/test/emul/Print.h +++ b/test/emul/Print.h @@ -5,7 +5,7 @@ class Print { public: virtual void flush() {} void printf(const char* format, ...) {} - virtual size_t write(uint8_t) = 0; + virtual size_t write(uint8_t) { return 0; } virtual size_t write(const char* s) { return 0; } virtual size_t write(const uint8_t* buffer, size_t size) { return 0; } }; diff --git a/test/emul/Stream.h b/test/emul/Stream.h index c1847603..774bca43 100644 --- a/test/emul/Stream.h +++ b/test/emul/Stream.h @@ -5,8 +5,10 @@ class Stream : public Print { public: - virtual int available() = 0; - virtual int read() = 0; + virtual int available() { return 0; } + virtual int read() { return -1; } + virtual int peek() { return -1; } + // flush() is already inherited from Print }; #endif From 6f76bdfeb08cbf7133426f667fdb726c1cdebd94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 21:30:48 +0300 Subject: [PATCH 014/150] Restore HEX printing --- Software/src/battery/BMW-PHEV-BATTERY.cpp | 4 ++-- Software/src/battery/DALY-BMS.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/BMW-PHEV-BATTERY.cpp b/Software/src/battery/BMW-PHEV-BATTERY.cpp index 6e40142e..d199ed13 100644 --- a/Software/src/battery/BMW-PHEV-BATTERY.cpp +++ b/Software/src/battery/BMW-PHEV-BATTERY.cpp @@ -513,7 +513,7 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) { if (gUDSContext.UDS_buffer[i] < 0x10) { logging.printf("0"); } - logging.print(gUDSContext.UDS_buffer[i]); + logging.print(gUDSContext.UDS_buffer[i], HEX); logging.printf(" "); } logging.println(""); // new line at the end @@ -538,7 +538,7 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) { if (gUDSContext.UDS_buffer[i] < 0x10) { logging.printf("0"); } - logging.print(gUDSContext.UDS_buffer[i]); + logging.print(gUDSContext.UDS_buffer[i], HEX); logging.printf(" "); } logging.println(); // new line at the end diff --git a/Software/src/battery/DALY-BMS.cpp b/Software/src/battery/DALY-BMS.cpp index bf9e00b8..e42b222a 100644 --- a/Software/src/battery/DALY-BMS.cpp +++ b/Software/src/battery/DALY-BMS.cpp @@ -112,8 +112,8 @@ void dump_buff(const char* msg, uint8_t* buff, uint8_t len) { logging.printf("[DALY-BMS] "); logging.printf(msg); for (int i = 0; i < len; i++) { - logging.print(buff[i] >> 4); - logging.print(buff[i] & 0xf); + logging.print(buff[i] >> 4, HEX); + logging.print(buff[i] & 0xf, HEX); logging.printf(" "); } logging.println(); From dabbcd8bcdafd76d4968dcaeebb18b1c0bdd3b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 22:03:00 +0300 Subject: [PATCH 015/150] Make LEAF interlock setting configurable --- Software/USER_SETTINGS.h | 6 ------ Software/src/battery/BATTERIES.cpp | 2 ++ Software/src/battery/BATTERIES.h | 1 + Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 13 +++++++------ Software/src/battery/NISSAN-LEAF-BATTERY.h | 2 ++ Software/src/communication/nvm/comm_nvm.cpp | 1 + Software/src/devboard/utils/types.h | 2 +- .../src/devboard/webserver/settings_html.cpp | 19 +++++++++++++++++-- Software/src/devboard/webserver/webserver.cpp | 2 +- 9 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 9e8283a0..099842bd 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -15,18 +15,12 @@ /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement -/* Select charger used (Optional) */ -//#define CHEVYVOLT_CHARGER //Enable this line to control a Chevrolet Volt charger connected to battery - for example, when generator charging or using an inverter without a charging function. -//#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging - /* Automatic Precharge settings (Optional) If you have a battery that expects an external voltage applied before opening contactors (within the battery), configure this section */ //#define PRECHARGE_CONTROL //Enable this line to control a modified HIA4V1 via PWM on the HIA4V1_PIN (see Wiki and HAL for pin definition) //#define INVERTER_DISCONNECT_CONTACTOR_IS_NORMALLY_OPEN //Enable this line if you use a normally open contactor instead of normally closed /* Other options */ //#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery -//#define LFP_CHEMISTRY //Tesla specific setting, enable this line to startup in LFP mode -//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting /* CAN options */ //#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery) #define CRYSTAL_FREQUENCY_MHZ 8 //CAN_ADDON option, what is your MCP2515 add-on boards crystal frequency? diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index b24751ab..f4639e26 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -279,6 +279,8 @@ void setup_battery() { } } +/* User-selected Nissan LEAF settings */ +bool user_selected_LEAF_interlock_mandatory = false; /* User-selected Tesla settings */ bool user_selected_tesla_digital_HVIL = false; uint16_t user_selected_tesla_GTW_country = 17477; diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 78e55398..22741186 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -62,6 +62,7 @@ extern uint16_t user_selected_min_pack_voltage_dV; extern uint16_t user_selected_max_cell_voltage_mV; extern uint16_t user_selected_min_cell_voltage_mV; +extern bool user_selected_LEAF_interlock_mandatory; extern bool user_selected_tesla_digital_HVIL; extern uint16_t user_selected_tesla_GTW_country; extern bool user_selected_tesla_GTW_rightHandDrive; diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 17e4f3d3..2bebb92f 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -150,13 +150,14 @@ void NissanLeafBattery:: clear_event(EVENT_BATTERY_CHG_DISCHG_STOP_REQ); } -#ifdef INTERLOCK_REQUIRED - if (!battery_Interlock) { - set_event(EVENT_HVIL_FAILURE, 0); - } else { - clear_event(EVENT_HVIL_FAILURE); + if (user_selected_LEAF_interlock_mandatory) { + //If user requires both large 80kW and small 6kW interlock to be seated for operation + if (!battery_Interlock) { + set_event(EVENT_HVIL_FAILURE, 0); + } else { + clear_event(EVENT_HVIL_FAILURE); + } } -#endif if (battery_HeatExist) { if (battery_Heating_Stop) { diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.h b/Software/src/battery/NISSAN-LEAF-BATTERY.h index 99a5691b..c6a5f868 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.h +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.h @@ -6,6 +6,8 @@ #include "CanBattery.h" #include "NISSAN-LEAF-HTML.h" +extern bool user_selected_LEAF_interlock_mandatory; + class NissanLeafBattery : public CanBattery { public: // Use this constructor for the second battery. diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 9e72d8cc..58ca7745 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -105,6 +105,7 @@ void init_stored_settings() { user_selected_inverter_battery_type = settings.getUInt("INVBTYPE", 0); user_selected_inverter_ignore_contactors = settings.getBool("INVICNT", false); user_selected_can_addon_crystal_frequency_mhz = settings.getUInt("CANFREQ", 8); + user_selected_LEAF_interlock_mandatory = settings.getBool("INTERLOCKREQ", false); user_selected_tesla_digital_HVIL = settings.getBool("DIGITALHVIL", false); user_selected_tesla_GTW_country = settings.getUInt("GTWCOUNTRY", 0); user_selected_tesla_GTW_rightHandDrive = settings.getBool("GTWRHD", false); diff --git a/Software/src/devboard/utils/types.h b/Software/src/devboard/utils/types.h index 846d6c43..fab3d4d9 100644 --- a/Software/src/devboard/utils/types.h +++ b/Software/src/devboard/utils/types.h @@ -9,7 +9,7 @@ using duration = std::chrono::duration>; enum bms_status_enum { STANDBY = 0, INACTIVE = 1, DARKSTART = 2, ACTIVE = 3, FAULT = 4, UPDATING = 5 }; enum real_bms_status_enum { BMS_DISCONNECTED = 0, BMS_STANDBY = 1, BMS_ACTIVE = 2, BMS_FAULT = 3 }; -enum battery_chemistry_enum { NCA = 1, NMC = 2, LFP = 3, Highest }; +enum battery_chemistry_enum { Autodetect = 0, NCA = 1, NMC = 2, LFP = 3, Highest }; enum class comm_interface { Modbus = 1, diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 7414d53f..0517962b 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -203,8 +203,9 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti name_for_comm_interface); } if (var == "BATTCHEM") { - return options_for_enum((battery_chemistry_enum)settings.getUInt("BATTCHEM", (int)battery_chemistry_enum::NCA), - name_for_chemistry); + return options_for_enum( + (battery_chemistry_enum)settings.getUInt("BATTCHEM", (int)battery_chemistry_enum::Autodetect), + name_for_chemistry); } if (var == "INVTYPE") { return options_for_enum_with_none( @@ -563,6 +564,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return String(settings.getUInt("PWMHOLD", 250)); } + if (var == "INTERLOCKREQ") { + return settings.getBool("INTERLOCKREQ") ? "checked" : ""; + } + if (var == "DIGITALHVIL") { return settings.getBool("DIGITALHVIL") ? "checked" : ""; } @@ -777,6 +782,11 @@ const char* getCANInterfaceName(CAN_Interface interface) { display: contents; } + form .if-nissan { display: none; } + form[data-battery="21"] .if-nissan { + display: contents; + } + form .if-tesla { display: none; } form[data-battery="32"] .if-tesla, form[data-battery="33"] .if-tesla { display: contents; @@ -841,6 +851,11 @@ const char* getCANInterfaceName(CAN_Interface interface) { %BATTTYPE% +
+ + +
+
diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 70c862e4..fe71aa61 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -398,7 +398,7 @@ void init_webserver() { const char* boolSettingNames[] = { "DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED", "REMBMSRESET", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", "CANLOGSD", "WIFIAPENABLED", "MQTTENABLED", - "HADISC", "MQTTTOPICS", "INVICNT", "GTWRHD", "DIGITALHVIL", "PERFPROFILE", + "HADISC", "MQTTTOPICS", "INVICNT", "GTWRHD", "DIGITALHVIL", "PERFPROFILE", "INTERLOCKREQ", }; // Handles the form POST from UI to save settings of the common image From 688ba0388c043ffd9f35cb30880a3158fe9314a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 23:12:21 +0300 Subject: [PATCH 016/150] Remove more USER_SETTINGS --- Software/USER_SETTINGS.h | 27 +-------------------- Software/src/battery/DALY-BMS.cpp | 1 - Software/src/battery/MG-HS-PHEV-BATTERY.cpp | 1 - Software/src/communication/can/comm_can.cpp | 16 +++--------- Software/src/communication/can/comm_can.h | 4 +++ Software/src/datalayer/datalayer.h | 23 ++++++++++-------- Software/src/inverter/BYD-CAN.cpp | 3 +++ Software/src/inverter/BYD-CAN.h | 6 +++-- 8 files changed, 28 insertions(+), 53 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 099842bd..f6c06dd7 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -7,7 +7,7 @@ /* This file is being transitioned towards COMMON_IMAGE. Use v8.16 if you are taking this software into use! */ /* Select hardware used for Battery-Emulator */ -//#define HW_LILYGO +#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT @@ -19,18 +19,7 @@ //#define PRECHARGE_CONTROL //Enable this line to control a modified HIA4V1 via PWM on the HIA4V1_PIN (see Wiki and HAL for pin definition) //#define INVERTER_DISCONNECT_CONTACTOR_IS_NORMALLY_OPEN //Enable this line if you use a normally open contactor instead of normally closed -/* Other options */ -//#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery -/* CAN options */ -//#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery) -#define CRYSTAL_FREQUENCY_MHZ 8 //CAN_ADDON option, what is your MCP2515 add-on boards crystal frequency? -//#define CANFD_ADDON //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board -#define CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ \ - ACAN2517FDSettings::OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency? -//#define USE_CANFD_INTERFACE_AS_CLASSIC_CAN // Enable this line if you intend to use the CANFD as normal CAN - /* Connectivity options */ -#define WIFI //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings //#define CUSTOM_HOSTNAME \ "battery-emulator" //Enable this line to use a custom hostname for the device, if disabled the default naming format 'esp32-XXXXXX' will be used. @@ -50,18 +39,6 @@ // This naming convention was in place until version 7.5.0. Users should check the version from which they are updating, as this change // may break compatibility with previous versions of MQTT naming. Please refer to USER_SETTINGS.cpp for configuration options. -/* Home Assistant options */ -#define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required - -/* Battery settings */ -// Predefined total energy capacity of the battery in Watt-hours (updates automatically from battery data when available) -#define BATTERY_WH_MAX 30000 -// Increases battery life. If true will rescale SOC between the configured min/max-percentage -#define BATTERY_USE_SCALED_SOC true -// 8000 = 80.0% , Max percentage the battery will charge to (Inverter gets 100% when reached) -#define BATTERY_MAXPERCENTAGE 8000 -// 2000 = 20.0% , Min percentage the battery will discharge to (Inverter gets 0% when reached) -#define BATTERY_MINPERCENTAGE 2000 // 500 = 50.0 °C , Max temperature (Will produce a battery overheat event if above) #define BATTERY_MAXTEMPERATURE 500 // -250 = -25.0 °C , Min temperature (Will produce a battery frozen event if below) @@ -98,8 +75,6 @@ extern volatile float CHARGER_MAX_POWER; extern volatile float CHARGER_MAX_A; extern volatile float CHARGER_END_A; -extern volatile unsigned long long bmsResetTimeOffset; - #include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h" // Equipment stop button behavior. Use NC button for safety reasons. diff --git a/Software/src/battery/DALY-BMS.cpp b/Software/src/battery/DALY-BMS.cpp index e42b222a..9cbeb794 100644 --- a/Software/src/battery/DALY-BMS.cpp +++ b/Software/src/battery/DALY-BMS.cpp @@ -72,7 +72,6 @@ void DalyBms::setup(void) { // Performs one time setup at startup datalayer.battery.info.min_design_voltage_dV = user_selected_min_pack_voltage_dV; datalayer.battery.info.max_cell_voltage_mV = user_selected_max_cell_voltage_mV; datalayer.battery.info.min_cell_voltage_mV = user_selected_min_cell_voltage_mV; - datalayer.battery.info.total_capacity_Wh = BATTERY_WH_MAX; datalayer.system.status.battery_allows_contactor_closing = true; auto rx_pin = esp32hal->RS485_RX_PIN(); diff --git a/Software/src/battery/MG-HS-PHEV-BATTERY.cpp b/Software/src/battery/MG-HS-PHEV-BATTERY.cpp index 57d8476a..daf7485f 100644 --- a/Software/src/battery/MG-HS-PHEV-BATTERY.cpp +++ b/Software/src/battery/MG-HS-PHEV-BATTERY.cpp @@ -373,6 +373,5 @@ void MgHsPHEVBattery::setup(void) { // Performs one time setup at startup 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.total_capacity_Wh = BATTERY_WH_MAX; datalayer.battery.info.number_of_cells = 90; } diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index 003e1988..eadb75d8 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -19,18 +19,9 @@ struct CanReceiverRegistration { static std::multimap can_receivers; -const uint8_t rx_queue_size = 10; // Receive Queue size volatile bool send_ok_native = 0; volatile bool send_ok_2515 = 0; volatile bool send_ok_2518 = 0; -static unsigned long previousMillis10 = 0; - -#ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN -const bool use_canfd_as_can_default = true; -#else -const bool use_canfd_as_can_default = false; -#endif -bool use_canfd_as_can = use_canfd_as_can_default; void map_can_frame_to_variable(CAN_frame* rx_frame, CAN_Interface interface); @@ -41,10 +32,9 @@ void register_can_receiver(CanReceiver* receiver, CAN_Interface interface, CAN_S ACAN_ESP32_Settings* settingsespcan; -uint8_t user_selected_can_addon_crystal_frequency_mhz = 0; static uint32_t QUARTZ_FREQUENCY; SPIClass SPI2515; - +uint8_t user_selected_can_addon_crystal_frequency_mhz = 0; ACAN2515* can2515; ACAN2515Settings* settings2515; @@ -53,7 +43,7 @@ static ACAN2515_Buffer16 gBuffer; SPIClass SPI2517; ACAN2517FD* canfd; ACAN2517FDSettings* settings2517; - +bool use_canfd_as_can = false; // Initialization functions bool native_can_initialized = false; @@ -190,7 +180,7 @@ bool init_CAN() { CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, bitRate, DataBitRateFactor::x4); // Arbitration bit rate: 250/500 kbit/s, data bit rate: 1/2 Mbit/s - // ListenOnly / Normal20B / NormalFD + // ListenOnly / Normal20B / NormalFDs settings2517->mRequestedMode = use_canfd_as_can ? ACAN2517FDSettings::Normal20B : ACAN2517FDSettings::NormalFD; const uint32_t errorCode2517 = canfd->begin(*settings2517, [] { canfd->isr(); }); diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h index 2b7ece97..91e58017 100644 --- a/Software/src/communication/can/comm_can.h +++ b/Software/src/communication/can/comm_can.h @@ -9,6 +9,10 @@ extern uint8_t user_selected_can_addon_crystal_frequency_mhz; void dump_can_frame(CAN_frame& frame, frameDirection msgDir); void transmit_can_frame_to_interface(const CAN_frame* tx_frame, int interface); +//These defines are not used if user updates values via Settings page +#define CRYSTAL_FREQUENCY_MHZ 8 +#define CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ ACAN2517FDSettings::OSC_40MHz + class CanReceiver; enum class CAN_Speed { diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 83649469..6ac56088 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -7,9 +7,11 @@ struct DATALAYER_BATTERY_INFO_TYPE { /** uint32_t */ - /** Total energy capacity in Watt-hours */ - uint32_t total_capacity_Wh = BATTERY_WH_MAX; - uint32_t reported_total_capacity_Wh = BATTERY_WH_MAX; + /** Total energy capacity in Watt-hours + * Automatically updates depending on battery integration OR from settings page + */ + uint32_t total_capacity_Wh = 30000; + uint32_t reported_total_capacity_Wh = 30000; /** uint16_t */ /** The maximum intended packvoltage, in deciVolt. 4900 = 490.0 V */ @@ -28,7 +30,7 @@ struct DATALAYER_BATTERY_INFO_TYPE { uint8_t number_of_cells; /** Other */ - /** Chemistry of the pack. NCA, NMC or LFP (so far) */ + /** Chemistry of the pack. Autodetect, or force specific chemistry */ battery_chemistry_enum chemistry = battery_chemistry_enum::NCA; }; @@ -114,16 +116,17 @@ struct DATALAYER_BATTERY_STATUS_TYPE { }; struct DATALAYER_BATTERY_SETTINGS_TYPE { - /** SOC scaling setting. Set to true to use SOC scaling */ - bool soc_scaling_active = BATTERY_USE_SCALED_SOC; + /** SOC scaling setting. Increases battery life. + * If true will rescale SOC between the configured min/max-percentage */ + bool soc_scaling_active = true; /** Minimum percentage setting. Set this value to the lowest real SOC * you want the inverter to be able to use. At this real SOC, the inverter - * will "see" 0% */ - int16_t min_percentage = BATTERY_MINPERCENTAGE; + * will "see" 0% , Example 2000 = 20.0%*/ + uint16_t min_percentage = 2000; /** Maximum percentage setting. Set this value to the highest real SOC * you want the inverter to be able to use. At this real SOC, the inverter - * will "see" 100% */ - uint16_t max_percentage = BATTERY_MAXPERCENTAGE; + * will "see" 100% Example 8000 = 80.0%*/ + uint16_t max_percentage = 8000; /** The user specified maximum allowed charge rate, in deciAmpere. 300 = 30.0 A */ uint16_t max_user_set_charge_dA = BATTERY_MAX_CHARGE_AMP; diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 0e9687b2..a779a270 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -85,6 +85,9 @@ void BydCanInverter:: //Temperature min BYD_210.data.u8[2] = (datalayer.battery.status.temperature_min_dC >> 8); BYD_210.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF); + //Capacity + BYD_250.data.u8[4] = (uint8_t)((datalayer.battery.info.reported_total_capacity_Wh / 100) >> 8); + BYD_250.data.u8[5] = (uint8_t)(datalayer.battery.info.reported_total_capacity_Wh / 100); } void BydCanInverter::map_can_frame_to_variable(CAN_frame rx_frame) { diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index 41f7f644..b61d0a5c 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -6,6 +6,7 @@ #endif #include "../../USER_SETTINGS.h" +#include "../datalayer/datalayer.h" #include "CanInverterProtocol.h" class BydCanInverter : public CanInverterProtocol { @@ -30,8 +31,9 @@ class BydCanInverter : public CanInverterProtocol { .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, + .data = {FW_MAJOR_VERSION, FW_MINOR_VERSION, 0x00, 0x66, + (uint8_t)((datalayer.battery.info.reported_total_capacity_Wh / 100) >> 8), + (uint8_t)(datalayer.battery.info.reported_total_capacity_Wh / 100), 0x02, 0x09}}; //0-1 FW version , Capacity kWh byte4&5 (example 24kWh = 240) CAN_frame BYD_290 = {.FD = false, .ext_ID = false, From 7328f7b99b1b195ad7f45e24582129096a5e81ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 23:22:34 +0300 Subject: [PATCH 017/150] Remove even more USER_SETTINGS --- Software/USER_SETTINGS.h | 13 +---------- Software/src/communication/nvm/comm_nvm.cpp | 7 +----- Software/src/devboard/mqtt/mqtt.cpp | 12 ++++------ Software/src/devboard/wifi/wifi.cpp | 26 ++++----------------- 4 files changed, 11 insertions(+), 47 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index f6c06dd7..3495ae44 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -7,7 +7,7 @@ /* This file is being transitioned towards COMMON_IMAGE. Use v8.16 if you are taking this software into use! */ /* Select hardware used for Battery-Emulator */ -#define HW_LILYGO +//#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT @@ -21,23 +21,12 @@ /* Connectivity options */ //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings -//#define CUSTOM_HOSTNAME \ - "battery-emulator" //Enable this line to use a custom hostname for the device, if disabled the default naming format 'esp32-XXXXXX' will be used. -#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. -#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. -#define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) /* MQTT options */ // #define MQTT // Enable this line to enable MQTT #define MQTT_QOS 0 // MQTT Quality of Service (0, 1, or 2) #define MQTT_PUBLISH_CELL_VOLTAGES // Enable this line to publish cell voltages to MQTT #define MQTT_TIMEOUT 2000 // MQTT timeout in milliseconds -#define MQTT_MANUAL_TOPIC_OBJECT_NAME -// Enable MQTT_MANUAL_TOPIC_OBJECT_NAME to use custom MQTT topic, object ID prefix, and device name. -// WARNING: If this is not defined, the previous default naming format 'battery-emulator_esp32-XXXXXX' (based on hardware ID) will be used. -// This naming convention was in place until version 7.5.0. Users should check the version from which they are updating, as this change -// may break compatibility with previous versions of MQTT naming. Please refer to USER_SETTINGS.cpp for configuration options. // 500 = 50.0 °C , Max temperature (Will produce a battery overheat event if above) #define BATTERY_MAXTEMPERATURE 500 diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 58ca7745..8869fc15 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -26,12 +26,7 @@ void init_stored_settings() { set_event(EVENT_EQUIPMENT_STOP, 1); } -#ifndef LOAD_SAVED_SETTINGS_ON_BOOT - settings.clear(); // If this clear function is executed, no settings will be read from storage - - //always save the equipment stop status - settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active); -#endif // LOAD_SAVED_SETTINGS_ON_BOOT + //settings.clear(); // If this clear function is executed, no settings will be read from storage. For dev esp32hal->set_default_configuration_values(); diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index 108baf6d..a031f1a5 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -23,13 +23,11 @@ const char* mqtt_server_default = ""; int mqtt_port = mqtt_port_default; std::string mqtt_server = mqtt_server_default; -#ifdef MQTT_MANUAL_TOPIC_OBJECT_NAME -const bool mqtt_manual_topic_object_name_default = true; -#else -const bool mqtt_manual_topic_object_name_default = false; -#endif - -bool mqtt_manual_topic_object_name = mqtt_manual_topic_object_name_default; +bool mqtt_manual_topic_object_name = + true; //TODO, should this be configurable from webserver? Or legacy option removed? +// If this is not true, the previous default naming format 'battery-emulator_esp32-XXXXXX' (based on hardware ID) will be used. +// This naming convention was in place until version 7.5.0. Users should check the version from which they are updating, as this change +// may break compatibility with previous versions of MQTT naming esp_mqtt_client_config_t mqtt_cfg; esp_mqtt_client_handle_t client; diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 44adc907..869d863f 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -4,29 +4,11 @@ #include "../utils/logging.h" #include "USER_SETTINGS.h" -#if defined(WIFI) || defined(WEBSERVER) -const bool wifi_enabled_default = true; -#else -const bool wifi_enabled_default = false; -#endif - -bool wifi_enabled = wifi_enabled_default; - -bool wifiap_enabled = true; //Old method was with ifdef - -#ifdef MDNSRESPONDER -const bool mdns_enabled_default = true; -#else -const bool mdns_enabled_default = false; -#endif -bool mdns_enabled = mdns_enabled_default; - -#ifdef CUSTOM_HOSTNAME -std::string custom_hostname = CUSTOM_HOSTNAME; -#else -std::string custom_hostname; -#endif +bool wifi_enabled = true; +bool wifiap_enabled = true; +bool mdns_enabled = true; //If true, allows battery monitor te be found by .local address +std::string custom_hostname; //If not set, the default naming format 'esp32-XXXXXX' will be used std::string ssidAP; // Configuration Parameters From aba193ca85ce39ba67aaa9dafe561d9e4079f253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 23:41:18 +0300 Subject: [PATCH 018/150] Remove more USER_SETTINGS --- Software/Software.ino | 8 ++++++++ Software/USER_SETTINGS.h | 19 ------------------- Software/src/battery/DALY-BMS.cpp | 5 +++-- Software/src/datalayer/datalayer.h | 18 +++++++++++------- Software/src/devboard/safety/safety.h | 4 +++- 5 files changed, 25 insertions(+), 29 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index e26fc42f..9d9f2c62 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -51,6 +51,14 @@ TaskHandle_t connectivity_loop_task; TaskHandle_t logging_loop_task; TaskHandle_t mqtt_loop_task; +/* Charger settings (Optional, when using generator charging) */ +volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack +volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger +volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of charger +volatile float CHARGER_MAX_POWER = 3300; // Max power capable of charger, as a ceiling for validating config +volatile float CHARGER_MAX_A = 11.5; // Max current output (amps) of charger +volatile float CHARGER_END_A = 1.0; // Current at which charging is considered complete + Logging logging; // Initialization diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 3495ae44..6b199614 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -22,29 +22,10 @@ /* Connectivity options */ //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings -/* MQTT options */ -// #define MQTT // Enable this line to enable MQTT #define MQTT_QOS 0 // MQTT Quality of Service (0, 1, or 2) #define MQTT_PUBLISH_CELL_VOLTAGES // Enable this line to publish cell voltages to MQTT #define MQTT_TIMEOUT 2000 // MQTT timeout in milliseconds -// 500 = 50.0 °C , Max temperature (Will produce a battery overheat event if above) -#define BATTERY_MAXTEMPERATURE 500 -// -250 = -25.0 °C , Min temperature (Will produce a battery frozen event if below) -#define BATTERY_MINTEMPERATURE -250 -// 150 = 15.0 °C , Max difference between min and max temperature (Will produce a battery temperature deviation event if greater) -#define BATTERY_MAX_TEMPERATURE_DEVIATION 150 -// 300 = 30.0A , Max charge in Amp (Some inverters needs to be limited) -#define BATTERY_MAX_CHARGE_AMP 300 -// 300 = 30.0A , Max discharge in Amp (Some inverters needs to be limited) -#define BATTERY_MAX_DISCHARGE_AMP 300 -// Enable this to manually set voltage limits on how much battery can be discharged/charged. Normally not used. -#define BATTERY_USE_VOLTAGE_LIMITS false -// 5000 = 500.0V , Target charge voltage (Value can be tuned on the fly via webserver). Not used unless BATTERY_USE_VOLTAGE_LIMITS = true -#define BATTERY_MAX_CHARGE_VOLTAGE 5000 -// 3000 = 300.0V, Target discharge voltage (Value can be tuned on the fly via webserver). Not used unless BATTERY_USE_VOLTAGE_LIMITS = true -#define BATTERY_MAX_DISCHARGE_VOLTAGE 3000 - /* Do not change any code below this line */ /* Only change battery specific settings above and in "USER_SETTINGS.cpp" */ typedef struct { diff --git a/Software/src/battery/DALY-BMS.cpp b/Software/src/battery/DALY-BMS.cpp index 9cbeb794..74f92703 100644 --- a/Software/src/battery/DALY-BMS.cpp +++ b/Software/src/battery/DALY-BMS.cpp @@ -27,8 +27,9 @@ void DalyBms::update_values() { datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) datalayer.battery.status.remaining_capacity_Wh = (remaining_capacity_mAh * (uint32_t)voltage_dV) / 10000; - datalayer.battery.status.max_charge_power_W = (BATTERY_MAX_CHARGE_AMP * voltage_dV) / 100; - datalayer.battery.status.max_discharge_power_W = (BATTERY_MAX_DISCHARGE_AMP * voltage_dV) / 100; + datalayer.battery.status.max_charge_power_W = (datalayer.battery.settings.max_user_set_charge_dA * voltage_dV) / 100; + datalayer.battery.status.max_discharge_power_W = + (datalayer.battery.settings.max_user_set_discharge_dA * voltage_dV) / 100; // limit power when SoC is low or high uint32_t adaptive_power_limit = 999999; diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 6ac56088..fddc057c 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -128,18 +128,22 @@ struct DATALAYER_BATTERY_SETTINGS_TYPE { * will "see" 100% Example 8000 = 80.0%*/ uint16_t max_percentage = 8000; - /** 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; + /** The user specified maximum allowed charge rate, in deciAmpere. 300 = 30.0 A + * Updates later on via Settings + */ + uint16_t max_user_set_charge_dA = 300; + /** The user specified maximum allowed discharge rate, in deciAmpere. 300 = 30.0 A + * Updates later on via Settings + */ + uint16_t max_user_set_discharge_dA = 300; /** User specified discharge/charge voltages in use. Set to true to use user specified values */ /** Some inverters like to see a specific target voltage for charge/discharge. Use these values to override automatic voltage limits*/ - bool user_set_voltage_limits_active = BATTERY_USE_VOLTAGE_LIMITS; + bool user_set_voltage_limits_active = false; /** The user specified maximum allowed charge voltage, in deciVolt. 4000 = 400.0 V */ - uint16_t max_user_set_charge_voltage_dV = BATTERY_MAX_CHARGE_VOLTAGE; + uint16_t max_user_set_charge_voltage_dV = 4500; /** The user specified maximum allowed discharge voltage, in deciVolt. 3000 = 300.0 V */ - uint16_t max_user_set_discharge_voltage_dV = BATTERY_MAX_DISCHARGE_VOLTAGE; + uint16_t max_user_set_discharge_voltage_dV = 3000; /** The user specified BMS reset period. Keeps track on how many milliseconds should we keep power off during daily BMS reset */ uint16_t user_set_bms_reset_duration_ms = 30000; diff --git a/Software/src/devboard/safety/safety.h b/Software/src/devboard/safety/safety.h index c402176c..432e05ce 100644 --- a/Software/src/devboard/safety/safety.h +++ b/Software/src/devboard/safety/safety.h @@ -3,7 +3,9 @@ #include #define MAX_CAN_FAILURES 50 - +#define BATTERY_MAX_TEMPERATURE_DEVIATION 150 // 150 = 15.0 °C +#define BATTERY_MAXTEMPERATURE 500 +#define BATTERY_MINTEMPERATURE -250 #define MAX_CHARGE_DISCHARGE_LIMIT_FAILURES 5 //battery pause status begin From 1cc4a021c261ca92e8a03f005bc9b0f4d37d4376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 1 Sep 2025 23:50:17 +0300 Subject: [PATCH 019/150] Convert .ino to .cpp file --- Software/{Software.ino => Software.cpp} | 503 ++++++++++++------------ 1 file changed, 247 insertions(+), 256 deletions(-) rename Software/{Software.ino => Software.cpp} (96%) diff --git a/Software/Software.ino b/Software/Software.cpp similarity index 96% rename from Software/Software.ino rename to Software/Software.cpp index 9d9f2c62..70fd5609 100644 --- a/Software/Software.ino +++ b/Software/Software.cpp @@ -1,5 +1,4 @@ -/* Do not change any code below this line unless you are sure what you are doing */ -/* Only change battery specific settings in "USER_SETTINGS.h" */ +#include #include "HardwareSerial.h" #include "USER_SETTINGS.h" #include "esp_system.h" @@ -51,130 +50,20 @@ TaskHandle_t connectivity_loop_task; TaskHandle_t logging_loop_task; TaskHandle_t mqtt_loop_task; -/* Charger settings (Optional, when using generator charging) */ -volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack -volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger -volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of charger -volatile float CHARGER_MAX_POWER = 3300; // Max power capable of charger, as a ceiling for validating config -volatile float CHARGER_MAX_A = 11.5; // Max current output (amps) of charger -volatile float CHARGER_END_A = 1.0; // Current at which charging is considered complete - Logging logging; -// Initialization -void setup() { - init_hal(); +static std::list transmitters; - init_serial(); - - // We print this after setting up serial, so that is also printed if configured to do so - logging.printf("Battery emulator %s build " __DATE__ " " __TIME__ "\n", version_number); - - init_events(); - - init_stored_settings(); - - if (wifi_enabled) { - xTaskCreatePinnedToCore((TaskFunction_t)&connectivity_loop, "connectivity_loop", 4096, NULL, TASK_CONNECTIVITY_PRIO, - &connectivity_loop_task, esp32hal->WIFICORE()); - } - - if (!led_init()) { - return; - } - - if (datalayer.system.info.CAN_SD_logging_active || datalayer.system.info.SD_logging_active) { - xTaskCreatePinnedToCore((TaskFunction_t)&logging_loop, "logging_loop", 4096, NULL, TASK_CONNECTIVITY_PRIO, - &logging_loop_task, esp32hal->WIFICORE()); - } - - if (!init_contactors()) { - return; - } - - if (!init_precharge_control()) { - return; - } - - setup_charger(); - - if (!setup_inverter()) { - return; - } - setup_battery(); - setup_can_shunt(); - - // Init CAN only after any CAN receivers have had a chance to register. - if (!init_CAN()) { - return; - } - - if (!init_rs485()) { - return; - } - - if (!init_equipment_stop_button()) { - return; - } - - // BOOT button at runtime is used as an input for various things - pinMode(0, INPUT_PULLUP); - - check_reset_reason(); - - // Initialize Task Watchdog for subscribed tasks - esp_task_wdt_config_t wdt_config = {// 5s should be enough for the connectivity tasks (which are all contending - // for the same core) to yield to each other and reset their watchdogs. - .timeout_ms = INTERVAL_5_S, - // We don't benefit from idle task watchdogs, our critical loops have their - // own. The idle watchdogs can cause nuisance reboots under heavy load. - .idle_core_mask = 0, - // Panic (and reboot) on timeout - .trigger_panic = true}; -#ifdef CONFIG_ESP_TASK_WDT - // ESP-IDF will have already initialized it, so reconfigure. - // Arduino and PlatformIO have different watchdog defaults, so we reconfigure - // for consistency. - esp_task_wdt_reconfigure(&wdt_config); -#else - // Otherwise initialize it for the first time. - esp_task_wdt_init(&wdt_config); -#endif - - // Start tasks - - if (mqtt_enabled) { - if (!init_mqtt()) { - return; - } - - xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, NULL, TASK_MQTT_PRIO, &mqtt_loop_task, - esp32hal->WIFICORE()); - } - - xTaskCreatePinnedToCore((TaskFunction_t)&core_loop, "core_loop", 4096, NULL, TASK_CORE_PRIO, &main_loop_task, - esp32hal->CORE_FUNCTION_CORE()); - - DEBUG_PRINTF("setup() complete\n"); +void register_transmitter(Transmitter* transmitter) { + transmitters.push_back(transmitter); + DEBUG_PRINTF("transmitter registered, total: %d\n", transmitters.size()); } -// Loop empty, all functionality runs in tasks -void loop() {} - -void logging_loop(void*) { - - init_logging_buffers(); - init_sdcard(); - - while (true) { - if (datalayer.system.info.SD_logging_active) { - write_log_to_sdcard(); - } - - if (datalayer.system.info.CAN_SD_logging_active) { - write_can_frame_to_sdcard(); - } - } +// Initialization functions +void init_serial() { + // Init Serial monitor + Serial.begin(115200); + while (!Serial) {} } void connectivity_loop(void*) { @@ -205,146 +94,22 @@ void connectivity_loop(void*) { } } -void mqtt_loop(void*) { - esp_task_wdt_add(NULL); // Register this task with WDT +void logging_loop(void*) { + + init_logging_buffers(); + init_sdcard(); while (true) { - START_TIME_MEASUREMENT(mqtt); - mqtt_loop(); - END_TIME_MEASUREMENT_MAX(mqtt, datalayer.system.status.mqtt_task_10s_max_us); - esp_task_wdt_reset(); // Reset watchdog - delay(1); + if (datalayer.system.info.SD_logging_active) { + write_log_to_sdcard(); + } + + if (datalayer.system.info.CAN_SD_logging_active) { + write_can_frame_to_sdcard(); + } } } -static std::list transmitters; - -void register_transmitter(Transmitter* transmitter) { - transmitters.push_back(transmitter); - DEBUG_PRINTF("transmitter registered, total: %d\n", transmitters.size()); -} - -void core_loop(void*) { - esp_task_wdt_add(NULL); // Register this task with WDT - TickType_t xLastWakeTime = xTaskGetTickCount(); - const TickType_t xFrequency = pdMS_TO_TICKS(1); // Convert 1ms to ticks - - while (true) { - - START_TIME_MEASUREMENT(all); - START_TIME_MEASUREMENT(comm); - - monitor_equipment_stop_button(); - - // Input, Runs as fast as possible - receive_can(); // Receive CAN messages - receive_rs485(); // Process serial2 RS485 interface - - END_TIME_MEASUREMENT_MAX(comm, datalayer.system.status.time_comm_us); - - if (webserver_enabled) { - START_TIME_MEASUREMENT(ota); - ElegantOTA.loop(); - END_TIME_MEASUREMENT_MAX(ota, datalayer.system.status.time_ota_us); - } - - // Process - currentMillis = millis(); - if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) { - if ((currentMillis - previousMillis10ms >= INTERVAL_10_MS_DELAYED) && - (milliseconds(currentMillis) > esp32hal->BOOTUP_TIME())) { - set_event(EVENT_TASK_OVERRUN, (currentMillis - previousMillis10ms)); - } - previousMillis10ms = currentMillis; - if (datalayer.system.info.performance_measurement_active) { - START_TIME_MEASUREMENT(10ms); - } - led_exe(); - handle_contactors(); // Take care of startup precharge/contactor closing -#ifdef PRECHARGE_CONTROL - handle_precharge_control(currentMillis); -#endif // PRECHARGE_CONTROL - if (datalayer.system.info.performance_measurement_active) { - END_TIME_MEASUREMENT_MAX(10ms, datalayer.system.status.time_10ms_us); - } - } - - if (currentMillis - previousMillisUpdateVal >= INTERVAL_1_S) { - previousMillisUpdateVal = currentMillis; // Order matters on the update_loop! - if (datalayer.system.info.performance_measurement_active) { - START_TIME_MEASUREMENT(values); - } - update_pause_state(); // Check if we are OK to send CAN or need to pause - - // Fetch battery values - if (battery) { - battery->update_values(); - } - - if (battery2) { - battery2->update_values(); - check_interconnect_available(); - } - update_calculated_values(); - update_machineryprotection(); // Check safeties - - // Update values heading towards inverter - if (inverter) { - inverter->update_values(); - } - - if (datalayer.system.info.performance_measurement_active) { - END_TIME_MEASUREMENT_MAX(values, datalayer.system.status.time_values_us); - } - } - if (datalayer.system.info.performance_measurement_active) { - START_TIME_MEASUREMENT(cantx); - } - - // Let all transmitter objects send their messages - for (auto& transmitter : transmitters) { - transmitter->transmit(currentMillis); - } - - if (datalayer.system.info.performance_measurement_active) { - END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us); - END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us); - if (datalayer.system.status.core_task_10s_max_us > datalayer.system.status.core_task_max_us) { - // Update worst case total time - datalayer.system.status.core_task_max_us = datalayer.system.status.core_task_10s_max_us; - // Record snapshots of task times - datalayer.system.status.time_snap_comm_us = datalayer.system.status.time_comm_us; - datalayer.system.status.time_snap_10ms_us = datalayer.system.status.time_10ms_us; - datalayer.system.status.time_snap_values_us = datalayer.system.status.time_values_us; - datalayer.system.status.time_snap_cantx_us = datalayer.system.status.time_cantx_us; - datalayer.system.status.time_snap_ota_us = datalayer.system.status.time_ota_us; - } - - datalayer.system.status.core_task_max_us = - MAX(datalayer.system.status.core_task_10s_max_us, datalayer.system.status.core_task_max_us); - if (core_task_timer_10s.elapsed()) { - datalayer.system.status.time_ota_us = 0; - datalayer.system.status.time_comm_us = 0; - datalayer.system.status.time_10ms_us = 0; - datalayer.system.status.time_values_us = 0; - datalayer.system.status.time_cantx_us = 0; - datalayer.system.status.core_task_10s_max_us = 0; - datalayer.system.status.wifi_task_10s_max_us = 0; - datalayer.system.status.mqtt_task_10s_max_us = 0; - } - } - esp_task_wdt_reset(); // Reset watchdog to prevent reset - vTaskDelayUntil(&xLastWakeTime, xFrequency); - } -} - -// Initialization functions -void init_serial() { - // Init Serial monitor - Serial.begin(115200); - while (!Serial) {} -} - void check_interconnect_available() { if (datalayer.battery.status.voltage_dV == 0 || datalayer.battery2.status.voltage_dV == 0) { return; // Both voltage values need to be available to start check @@ -589,3 +354,229 @@ void check_reset_reason() { break; } } + +void core_loop(void*) { + esp_task_wdt_add(NULL); // Register this task with WDT + TickType_t xLastWakeTime = xTaskGetTickCount(); + const TickType_t xFrequency = pdMS_TO_TICKS(1); // Convert 1ms to ticks + + while (true) { + + START_TIME_MEASUREMENT(all); + START_TIME_MEASUREMENT(comm); + + monitor_equipment_stop_button(); + + // Input, Runs as fast as possible + receive_can(); // Receive CAN messages + receive_rs485(); // Process serial2 RS485 interface + + END_TIME_MEASUREMENT_MAX(comm, datalayer.system.status.time_comm_us); + + if (webserver_enabled) { + START_TIME_MEASUREMENT(ota); + ElegantOTA.loop(); + END_TIME_MEASUREMENT_MAX(ota, datalayer.system.status.time_ota_us); + } + + // Process + currentMillis = millis(); + if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) { + if ((currentMillis - previousMillis10ms >= INTERVAL_10_MS_DELAYED) && + (milliseconds(currentMillis) > esp32hal->BOOTUP_TIME())) { + set_event(EVENT_TASK_OVERRUN, (currentMillis - previousMillis10ms)); + } + previousMillis10ms = currentMillis; + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(10ms); + } + led_exe(); + handle_contactors(); // Take care of startup precharge/contactor closing +#ifdef PRECHARGE_CONTROL + handle_precharge_control(currentMillis); +#endif // PRECHARGE_CONTROL + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(10ms, datalayer.system.status.time_10ms_us); + } + } + + if (currentMillis - previousMillisUpdateVal >= INTERVAL_1_S) { + previousMillisUpdateVal = currentMillis; // Order matters on the update_loop! + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(values); + } + update_pause_state(); // Check if we are OK to send CAN or need to pause + + // Fetch battery values + if (battery) { + battery->update_values(); + } + + if (battery2) { + battery2->update_values(); + check_interconnect_available(); + } + update_calculated_values(); + update_machineryprotection(); // Check safeties + + // Update values heading towards inverter + if (inverter) { + inverter->update_values(); + } + + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(values, datalayer.system.status.time_values_us); + } + } + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(cantx); + } + + // Let all transmitter objects send their messages + for (auto& transmitter : transmitters) { + transmitter->transmit(currentMillis); + } + + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us); + END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us); + if (datalayer.system.status.core_task_10s_max_us > datalayer.system.status.core_task_max_us) { + // Update worst case total time + datalayer.system.status.core_task_max_us = datalayer.system.status.core_task_10s_max_us; + // Record snapshots of task times + datalayer.system.status.time_snap_comm_us = datalayer.system.status.time_comm_us; + datalayer.system.status.time_snap_10ms_us = datalayer.system.status.time_10ms_us; + datalayer.system.status.time_snap_values_us = datalayer.system.status.time_values_us; + datalayer.system.status.time_snap_cantx_us = datalayer.system.status.time_cantx_us; + datalayer.system.status.time_snap_ota_us = datalayer.system.status.time_ota_us; + } + + datalayer.system.status.core_task_max_us = + MAX(datalayer.system.status.core_task_10s_max_us, datalayer.system.status.core_task_max_us); + if (core_task_timer_10s.elapsed()) { + datalayer.system.status.time_ota_us = 0; + datalayer.system.status.time_comm_us = 0; + datalayer.system.status.time_10ms_us = 0; + datalayer.system.status.time_values_us = 0; + datalayer.system.status.time_cantx_us = 0; + datalayer.system.status.core_task_10s_max_us = 0; + datalayer.system.status.wifi_task_10s_max_us = 0; + datalayer.system.status.mqtt_task_10s_max_us = 0; + } + } + esp_task_wdt_reset(); // Reset watchdog to prevent reset + vTaskDelayUntil(&xLastWakeTime, xFrequency); + } +} + +// Initialization +void setup() { + init_hal(); + + init_serial(); + + // We print this after setting up serial, so that is also printed if configured to do so + logging.printf("Battery emulator %s build " __DATE__ " " __TIME__ "\n", version_number); + + init_events(); + + init_stored_settings(); + + if (wifi_enabled) { + xTaskCreatePinnedToCore((TaskFunction_t)&connectivity_loop, "connectivity_loop", 4096, NULL, TASK_CONNECTIVITY_PRIO, + &connectivity_loop_task, esp32hal->WIFICORE()); + } + + if (!led_init()) { + return; + } + + if (datalayer.system.info.CAN_SD_logging_active || datalayer.system.info.SD_logging_active) { + xTaskCreatePinnedToCore((TaskFunction_t)&logging_loop, "logging_loop", 4096, NULL, TASK_CONNECTIVITY_PRIO, + &logging_loop_task, esp32hal->WIFICORE()); + } + + if (!init_contactors()) { + return; + } + + if (!init_precharge_control()) { + return; + } + + setup_charger(); + + if (!setup_inverter()) { + return; + } + setup_battery(); + setup_can_shunt(); + + // Init CAN only after any CAN receivers have had a chance to register. + if (!init_CAN()) { + return; + } + + if (!init_rs485()) { + return; + } + + if (!init_equipment_stop_button()) { + return; + } + + // BOOT button at runtime is used as an input for various things + pinMode(0, INPUT_PULLUP); + + check_reset_reason(); + + // Initialize Task Watchdog for subscribed tasks + esp_task_wdt_config_t wdt_config = {// 5s should be enough for the connectivity tasks (which are all contending + // for the same core) to yield to each other and reset their watchdogs. + .timeout_ms = INTERVAL_5_S, + // We don't benefit from idle task watchdogs, our critical loops have their + // own. The idle watchdogs can cause nuisance reboots under heavy load. + .idle_core_mask = 0, + // Panic (and reboot) on timeout + .trigger_panic = true}; +#ifdef CONFIG_ESP_TASK_WDT + // ESP-IDF will have already initialized it, so reconfigure. + // Arduino and PlatformIO have different watchdog defaults, so we reconfigure + // for consistency. + esp_task_wdt_reconfigure(&wdt_config); +#else + // Otherwise initialize it for the first time. + esp_task_wdt_init(&wdt_config); +#endif + + // Start tasks + + if (mqtt_enabled) { + if (!init_mqtt()) { + return; + } + + xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, NULL, TASK_MQTT_PRIO, &mqtt_loop_task, + esp32hal->WIFICORE()); + } + + xTaskCreatePinnedToCore((TaskFunction_t)&core_loop, "core_loop", 4096, NULL, TASK_CORE_PRIO, &main_loop_task, + esp32hal->CORE_FUNCTION_CORE()); + + DEBUG_PRINTF("setup() complete\n"); +} + +// Loop empty, all functionality runs in tasks +void loop() {} + +void mqtt_loop(void*) { + esp_task_wdt_add(NULL); // Register this task with WDT + + while (true) { + START_TIME_MEASUREMENT(mqtt); + mqtt_loop(); + END_TIME_MEASUREMENT_MAX(mqtt, datalayer.system.status.mqtt_task_10s_max_us); + esp_task_wdt_reset(); // Reset watchdog + delay(1); + } +} From fb62b2cdb15c1a3b999c9da2070d8aa9ba8995e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 18:13:24 +0300 Subject: [PATCH 020/150] Progress --- Software/Software.cpp | 6 +++++- Software/USER_SETTINGS.cpp | 18 ++++++++---------- Software/USER_SETTINGS.h | 12 ------------ Software/src/devboard/mqtt/mqtt.cpp | 7 ++++++- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 70fd5609..dde1c9f3 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -52,8 +52,12 @@ TaskHandle_t mqtt_loop_task; Logging logging; -static std::list transmitters; +std::string mqtt_user; //TODO, move? +std::string mqtt_password; //TODO, move? +std::string http_username; //TODO, move? +std::string http_password; //TODO, move? +static std::list transmitters; void register_transmitter(Transmitter* transmitter) { transmitters.push_back(transmitter); DEBUG_PRINTF("transmitter registered, total: %d\n", transmitters.size()); diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 48cf2c9b..d79a90ae 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -20,23 +20,21 @@ volatile CAN_Configuration can_config = { .shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your shunt connected to? }; -std::string ssid; -std::string password; -std::string passwordAP; - -const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection - -std::string http_username; -std::string http_password; // Set your Static IP address. Only used incase WIFICONFIG is set in USER_SETTINGS.h IPAddress local_IP(192, 168, 10, 150); IPAddress gateway(192, 168, 10, 1); IPAddress subnet(255, 255, 255, 0); +std::string ssid; +std::string password; +std::string passwordAP; + +const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection + + // MQTT -std::string mqtt_user; -std::string mqtt_password; + const char* mqtt_topic_name = "BE"; // Custom MQTT topic name. Previously, the name was automatically set to "battery-emulator_esp32-XXXXXX" diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 6b199614..30e2a80a 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -4,14 +4,6 @@ #include #include "src/devboard/utils/types.h" -/* This file is being transitioned towards COMMON_IMAGE. Use v8.16 if you are taking this software into use! */ - -/* Select hardware used for Battery-Emulator */ -//#define HW_LILYGO -//#define HW_STARK -//#define HW_3LB -//#define HW_DEVKIT - /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement @@ -22,10 +14,6 @@ /* Connectivity options */ //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings -#define MQTT_QOS 0 // MQTT Quality of Service (0, 1, or 2) -#define MQTT_PUBLISH_CELL_VOLTAGES // Enable this line to publish cell voltages to MQTT -#define MQTT_TIMEOUT 2000 // MQTT timeout in milliseconds - /* Do not change any code below this line */ /* Only change battery specific settings above and in "USER_SETTINGS.cpp" */ typedef struct { diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index a031f1a5..525df501 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -24,11 +24,16 @@ int mqtt_port = mqtt_port_default; std::string mqtt_server = mqtt_server_default; bool mqtt_manual_topic_object_name = - true; //TODO, should this be configurable from webserver? Or legacy option removed? + true; //TODO: should this be configurable from webserver? Or legacy option removed? // If this is not true, the previous default naming format 'battery-emulator_esp32-XXXXXX' (based on hardware ID) will be used. // This naming convention was in place until version 7.5.0. Users should check the version from which they are updating, as this change // may break compatibility with previous versions of MQTT naming +#define MQTT_PUBLISH_CELL_VOLTAGES // Enable this line to publish cell voltages to MQTT +#define MQTT_QOS 0 // MQTT Quality of Service (0, 1, or 2) +#define MQTT_TIMEOUT 2000 // MQTT timeout in milliseconds + //TODO: Should all these defines be a configurable option? + esp_mqtt_client_config_t mqtt_cfg; esp_mqtt_client_handle_t client; char mqtt_msg[MQTT_MSG_BUFFER_SIZE]; From a0b0fbd5d6b977d0ab41f8b8f99a814466bde632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 18:27:37 +0300 Subject: [PATCH 021/150] Restore CAN-FD library to v2.1.4 --- .../pierremolinaro-ACAN2517FD/ACAN2517FD.cpp | 250 +++++++++--------- .../pierremolinaro-ACAN2517FD/ACAN2517FD.h | 168 ++++++------ .../ACAN2517FDFilters.h | 58 ++-- .../ACAN2517FDSettings.cpp | 239 ++++++++++------- .../ACAN2517FDSettings.h | 182 ++++++------- .../ACAN2517FD_ACANFDBuffer.h | 122 --------- .../pierremolinaro-ACAN2517FD/ACANFDBuffer.h | 119 +++++++++ ...ateFactor.h => ACANFD_DataBitRateFactor.h} | 10 +- ...AN2517FD_CANFDMessage.h => CANFDMessage.h} | 46 ++-- .../{ACAN2517FD_CANMessage.h => CANMessage.h} | 12 +- .../lib/pierremolinaro-ACAN2517FD/README.md | 0 .../library.properties | 9 - 12 files changed, 624 insertions(+), 591 deletions(-) delete mode 100644 Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_ACANFDBuffer.h create mode 100644 Software/src/lib/pierremolinaro-ACAN2517FD/ACANFDBuffer.h rename Software/src/lib/pierremolinaro-ACAN2517FD/{ACAN2517FD_DataBitRateFactor.h => ACANFD_DataBitRateFactor.h} (73%) rename Software/src/lib/pierremolinaro-ACAN2517FD/{ACAN2517FD_CANFDMessage.h => CANFDMessage.h} (65%) rename Software/src/lib/pierremolinaro-ACAN2517FD/{ACAN2517FD_CANMessage.h => CANMessage.h} (84%) mode change 100755 => 100644 Software/src/lib/pierremolinaro-ACAN2517FD/README.md delete mode 100644 Software/src/lib/pierremolinaro-ACAN2517FD/library.properties diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.cpp b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.cpp index 2f190f98..ec2526c2 100644 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.cpp +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.cpp @@ -1,20 +1,20 @@ -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // A CAN driver for MCP2517FD, CANFD mode // by Pierre Molinaro // https://github.com/pierremolinaro/acan2517FD // -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #include "ACAN2517FD.h" -#include "../../system_settings.h" //Contains task priority //Modded by Battery-Emulator +#include "../../system_settings.h" //Contains task priority -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- static const uint8_t TXBWS = 0 ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // Note about ESP32 -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // // It appears that Arduino ESP32 interrupts are managed in a completely different way from "usual" Arduino: // - SPI.usingInterrupt is not implemented; @@ -43,7 +43,7 @@ static const uint8_t TXBWS = 0 ; // #endif // mSPI.endTransaction () ; // -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #ifdef ARDUINO_ARCH_ESP32 static void myESP32Task (void * pData) { @@ -55,9 +55,9 @@ static const uint8_t TXBWS = 0 ; } #endif -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // ACAN2517FD register addresses -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- static const uint16_t CON_REGISTER = 0x000 ; static const uint16_t NBTCFG_REGISTER = 0x004 ; @@ -68,85 +68,85 @@ static const uint16_t TREC_REGISTER = 0x034 ; static const uint16_t BDIAG0_REGISTER = 0x038 ; static const uint16_t BDIAG1_REGISTER = 0x03C ; -//------------------------------------------------------------------------------ +//······················································································································ // TXQ REGISTERS -//------------------------------------------------------------------------------ +//······················································································································ static const uint16_t TXQCON_REGISTER = 0x050 ; static const uint16_t TXQSTA_REGISTER = 0x054 ; static const uint16_t TXQUA_REGISTER = 0x058 ; -//------------------------------------------------------------------------------ +//······················································································································ // INTERRUPT REGISTERS -//------------------------------------------------------------------------------ +//······················································································································ static const uint16_t INT_REGISTER = 0x01C ; -//------------------------------------------------------------------------------ +//······················································································································ // FIFO REGISTERS -//------------------------------------------------------------------------------ +//······················································································································ static uint16_t FIFOCON_REGISTER (const uint16_t inFIFOIndex) { // 1 ... 31 return 0x05C + 12 * (inFIFOIndex - 1) ; } -//------------------------------------------------------------------------------ +//······················································································································ static uint16_t FIFOSTA_REGISTER (const uint16_t inFIFOIndex) { // 1 ... 31 return 0x060 + 12 * (inFIFOIndex - 1) ; } -//------------------------------------------------------------------------------ +//······················································································································ static uint16_t FIFOUA_REGISTER (const uint16_t inFIFOIndex) { // 1 ... 31 return 0x064 + 12 * (inFIFOIndex - 1) ; } -//------------------------------------------------------------------------------ +//······················································································································ // FILTER REGISTERS -//------------------------------------------------------------------------------ +//······················································································································ static uint16_t FLTCON_REGISTER (const uint16_t inFilterIndex) { // 0 ... 31 (DS20005688B, page 58) return 0x1D0 + inFilterIndex ; } -//------------------------------------------------------------------------------ +//······················································································································ static uint16_t FLTOBJ_REGISTER (const uint16_t inFilterIndex) { // 0 ... 31 (DS20005688B, page 60) return 0x1F0 + 8 * inFilterIndex ; } -//------------------------------------------------------------------------------ +//······················································································································ static uint16_t MASK_REGISTER (const uint16_t inFilterIndex) { // 0 ... 31 (DS20005688B, page 61) return 0x1F4 + 8 * inFilterIndex ; } -//------------------------------------------------------------------------------ +//······················································································································ // OSCILLATOR REGISTER -//------------------------------------------------------------------------------ +//······················································································································ static const uint16_t OSC_REGISTER = 0xE00 ; -//------------------------------------------------------------------------------ +//······················································································································ // INPUT / OUPUT CONTROL REGISTER -//------------------------------------------------------------------------------ +//······················································································································ static const uint16_t IOCON_REGISTER_00_07 = 0xE04 ; static const uint16_t IOCON_REGISTER_08_15 = 0xE05 ; static const uint16_t IOCON_REGISTER_16_23 = 0xE06 ; static const uint16_t IOCON_REGISTER_24_31 = 0xE07 ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // RECEIVE FIFO INDEX -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- static const uint8_t RECEIVE_FIFO_INDEX = 1 ; static const uint8_t TRANSMIT_FIFO_INDEX = 2 ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // BYTE BUFFER UTILITY FUNCTIONS -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- static void enterU32InBufferAtIndex (const uint32_t inValue, uint8_t ioBuffer [], const uint8_t inIndex) { ioBuffer [inIndex + 0] = (uint8_t) inValue ; @@ -155,7 +155,7 @@ static void enterU32InBufferAtIndex (const uint32_t inValue, uint8_t ioBuffer [] ioBuffer [inIndex + 3] = (uint8_t) (inValue >> 24) ; } -//------------------------------------------------------------------------------ +//······················································································································ static uint32_t u32FromBufferAtIndex (uint8_t ioBuffer [], const uint8_t inIndex) { uint32_t result = (uint32_t) ioBuffer [inIndex + 0] ; @@ -165,7 +165,7 @@ static uint32_t u32FromBufferAtIndex (uint8_t ioBuffer [], const uint8_t inIndex return result ; } -//------------------------------------------------------------------------------ +//······················································································································ static uint16_t u16FromBufferAtIndex (uint8_t ioBuffer [], const uint8_t inIndex) { uint16_t result = (uint16_t) ioBuffer [inIndex + 0] ; @@ -173,7 +173,8 @@ static uint16_t u16FromBufferAtIndex (uint8_t ioBuffer [], const uint8_t inIndex return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- + static inline void turnOffInterrupts () { #ifndef DISABLEMCP2517FDCOMPAT #ifdef ARDUINO_ARCH_ESP32 @@ -208,6 +209,7 @@ mINT (inINT), mUsesTXQ (false), mHardwareTxFIFOFull (false), mRxInterruptEnabled (true), +mHasDataBitRate (false), mTransmitFIFOPayload (0), mTXQBufferPayload (0), mReceiveFIFOPayload (0), @@ -221,7 +223,7 @@ mDriverTransmitBuffer () { } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, void (* inInterruptServiceRoutine) (void)) { @@ -232,7 +234,7 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, return begin (inSettings, inInterruptServiceRoutine, filters) ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, void (* inInterruptServiceRoutine) (void), @@ -501,14 +503,17 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, // bits 11-8: TSEG2 - 1 // bits 7-4: unused // bits 3-0: SJW - 1 - data = inSettings.mBitRatePrescaler - 1 ; - data <<= 8 ; - data |= inSettings.mDataPhaseSegment1 - 1 ; - data <<= 8 ; - data |= inSettings.mDataPhaseSegment2 - 1 ; - data <<= 8 ; - data |= inSettings.mDataSJW - 1 ; - writeRegister32 (DBTCFG_REGISTER, data) ; + mHasDataBitRate = inSettings.mDataBitRateFactor != ::DataBitRateFactor::x1 ; + if (mHasDataBitRate) { + data = inSettings.mBitRatePrescaler - 1 ; + data <<= 8 ; + data |= inSettings.mDataPhaseSegment1 - 1 ; + data <<= 8 ; + data |= inSettings.mDataPhaseSegment2 - 1 ; + data <<= 8 ; + data |= inSettings.mDataSJW - 1 ; + writeRegister32 (DBTCFG_REGISTER, data) ; + } //----------------------------------- Request mode (CON_REGISTER + 3, DS20005688B, page 24) // bits 7-4: Transmit Bandwith Sharing Bits ---> 0 // bit 3: Abort All Pending Transmissions bit --> 0 @@ -526,14 +531,14 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, } } #ifdef ARDUINO_ARCH_ESP32 - xTaskCreate (myESP32Task, "ACAN2517Handler", 1024, this, TASK_ACAN2517FD_PRIORITY, &mESP32TaskHandle) ; //Modded by Battery-Emulator + xTaskCreate (myESP32Task, "ACAN2517Handler", 1024, this, TASK_ACAN2517FD_PRIORITY, &mESP32TaskHandle) ; #endif if (mINT != 255) { // 255 means interrupt is not used #ifdef ARDUINO_ARCH_ESP32 attachInterrupt (itPin, inInterruptServiceRoutine, FALLING) ; #else - mSPI.usingInterrupt (itPin) ; // usingInterrupt is not implemented in Arduino ESP32 attachInterrupt (itPin, inInterruptServiceRoutine, LOW) ; // Thank to Flole998 + mSPI.usingInterrupt (itPin) ; // usingInterrupt is not implemented in Arduino ESP32 #endif } // If you begin() multiple times without constructor, @@ -545,13 +550,13 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, return errorCode ; } -//------------------------------------------------------------------------------ +//······················································································································ // end method (resets the MCP2517FD, deallocate buffers, and detach interrupt pin) -//------------------------------------------------------------------------------ +//······················································································································ bool ACAN2517FD::end (void) { mSPI.beginTransaction (mSPISettings) ; - turnOffInterrupts () ; + turnOffInterrupts () ; //--- Detach interrupt pin if (mINT != 255) { // 255 means interrupt is not used const int8_t itPin = digitalPinToInterrupt (mINT) ; @@ -592,19 +597,15 @@ bool ACAN2517FD::end (void) { return ok ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // SEND FRAME -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FD::tryToSend (const CANFDMessage & inMessage) { bool ok = inMessage.isValid () ; if (ok) { mSPI.beginTransaction (mSPISettings) ; - #ifdef ARDUINO_ARCH_ESP32 - taskDISABLE_INTERRUPTS () ; - #else - noInterrupts () ; - #endif + turnOffInterrupts () ; if (inMessage.idx == 0) { ok = inMessage.len <= mTransmitFIFOPayload ; if (ok) { @@ -616,13 +617,13 @@ bool ACAN2517FD::tryToSend (const CANFDMessage & inMessage) { ok = sendViaTXQ (inMessage) ; } } - turnOnInterrupts () ; + turnOnInterrupts(); mSPI.endTransaction () ; } return ok ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FD::enterInTransmitBuffer (const CANFDMessage & inMessage) { bool result ; @@ -644,7 +645,7 @@ bool ACAN2517FD::enterInTransmitBuffer (const CANFDMessage & inMessage) { return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- static uint32_t lengthCodeForLength (const uint8_t inLength) { uint32_t result = inLength & 0x0F ; @@ -660,7 +661,7 @@ static uint32_t lengthCodeForLength (const uint8_t inLength) { return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::appendInControllerTxFIFO (const CANFDMessage & inMessage) { const uint16_t ramAddr = uint16_t (0x400 + readRegister32Assume_SPI_transaction (FIFOUA_REGISTER (TRANSMIT_FIFO_INDEX))) ; @@ -685,7 +686,9 @@ void ACAN2517FD::appendInControllerTxFIFO (const CANFDMessage & inMessage) { break ; case CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH : flags |= 1 << 7 ; // Set FDF bit - flags |= 1 << 6 ; // Set BRS bit + if (mHasDataBitRate) { + flags |= 1 << 6 ; // Set BRS bit + } break ; } //--- Word count @@ -711,7 +714,7 @@ void ACAN2517FD::appendInControllerTxFIFO (const CANFDMessage & inMessage) { writeRegister8Assume_SPI_transaction (FIFOCON_REGISTER (TRANSMIT_FIFO_INDEX) + 1, data8); } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FD::sendViaTXQ (const CANFDMessage & inMessage) { bool ok = mUsesTXQ ; @@ -748,7 +751,9 @@ bool ACAN2517FD::sendViaTXQ (const CANFDMessage & inMessage) { break ; case CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH : flags |= 1 << 7 ; // Set FDF bit - flags |= 1 << 6 ; // Set BRS bit + if (mHasDataBitRate) { + flags |= 1 << 6 ; // Set BRS bit + } break ; } //--- Word count @@ -777,48 +782,41 @@ bool ACAN2517FD::sendViaTXQ (const CANFDMessage & inMessage) { return ok ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // RECEIVE FRAME -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FD::available (void) { mSPI.beginTransaction (mSPISettings) ; - turnOffInterrupts () ; + turnOffInterrupts () ; const bool hasReceivedMessage = mDriverReceiveBuffer.count () > 0 ; - turnOnInterrupts () ; + turnOnInterrupts(); mSPI.endTransaction () ; return hasReceivedMessage ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FD::receive (CANFDMessage & outMessage) { + mSPI.beginTransaction (mSPISettings) ; + turnOffInterrupts () ; const bool hasReceivedMessage = mDriverReceiveBuffer.remove (outMessage) ; //--- If receive interrupt is disabled, enable it (added in release 2.17) if (mINT == 255) { // No interrupt pin mRxInterruptEnabled = true ; isr_poll_core () ; // Perform polling }else if (!mRxInterruptEnabled) { - - mSPI.beginTransaction (mSPISettings) ; - #ifdef ARDUINO_ARCH_ESP32 - taskDISABLE_INTERRUPTS () ; - #else - noInterrupts () ; - #endif - mRxInterruptEnabled = true ; uint8_t data8 = readRegister8Assume_SPI_transaction (INT_REGISTER + 2) ; data8 |= (1 << 1) ; // Receive FIFO Interrupt Enable writeRegister8Assume_SPI_transaction (INT_REGISTER + 2, data8) ; - - turnOnInterrupts () ; - mSPI.endTransaction () ; } + turnOnInterrupts(); + mSPI.endTransaction () ; return hasReceivedMessage ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FD::dispatchReceivedMessage (const tFilterMatchCallBack inFilterMatchCallBack) { CANFDMessage receivedMessage ; @@ -836,9 +834,9 @@ bool ACAN2517FD::dispatchReceivedMessage (const tFilterMatchCallBack inFilterMat return hasReceived ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // POLLING (ESP32) -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #ifdef ARDUINO_ARCH_ESP32 void ACAN2517FD::poll (void) { @@ -848,22 +846,22 @@ bool ACAN2517FD::dispatchReceivedMessage (const tFilterMatchCallBack inFilterMat } #endif -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // POLLING (other than ESP32) -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #ifndef ARDUINO_ARCH_ESP32 void ACAN2517FD::poll (void) { - noInterrupts () ; + turnOffInterrupts () ; isr_poll_core () ; - interrupts () ; + turnOnInterrupts () ; } #endif -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // INTERRUPT SERVICE ROUTINE (ESP32) // https://stackoverflow.com/questions/51750377/how-to-disable-interrupt-watchdog-in-esp32-or-increase-isr-time-limit -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #ifdef ARDUINO_ARCH_ESP32 void ACAN2517FD::isr (void) { @@ -873,9 +871,9 @@ bool ACAN2517FD::dispatchReceivedMessage (const tFilterMatchCallBack inFilterMat } #endif -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // INTERRUPT SERVICE ROUTINE (other than ESP32) -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #ifndef ARDUINO_ARCH_ESP32 void ACAN2517FD::isr (void) { @@ -883,9 +881,9 @@ bool ACAN2517FD::dispatchReceivedMessage (const tFilterMatchCallBack inFilterMat } #endif -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // INTERRUPT SERVICE ROUTINES (common) -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::isr_poll_core (void) { mSPI.beginTransaction (mSPISettings) ; @@ -935,7 +933,7 @@ void ACAN2517FD::isr_poll_core (void) { mSPI.endTransaction () ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::transmitInterrupt (void) { // Generated if hardware transmit FIFO is not full CANFDMessage message ; @@ -950,7 +948,7 @@ void ACAN2517FD::transmitInterrupt (void) { // Generated if hardware transmit FI } } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::receiveInterrupt (void) { const uint16_t ramAddress = uint16_t (0x400 + readRegister32Assume_SPI_transaction (FIFOUA_REGISTER (RECEIVE_FIFO_INDEX))) ; @@ -1009,9 +1007,9 @@ void ACAN2517FD::receiveInterrupt (void) { } } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // MCP2517FD REGISTER ACCESS, SECOND LEVEL FUNCTIONS (HANDLE CS, ASSUME WITHIN SPI TRANSACTION) -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::writeRegister32Assume_SPI_transaction (const uint16_t inRegisterAddress, const uint32_t inValue) { @@ -1029,7 +1027,7 @@ void ACAN2517FD::writeRegister32Assume_SPI_transaction (const uint16_t inRegiste deassertCS () ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::writeRegister8Assume_SPI_transaction (const uint16_t inRegisterAddress, const uint8_t inValue) { @@ -1044,7 +1042,7 @@ void ACAN2517FD::writeRegister8Assume_SPI_transaction (const uint16_t inRegister deassertCS () ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FD::readRegister32Assume_SPI_transaction (const uint16_t inRegisterAddress) { //--- Read word register via 6-byte buffer (speed enhancement, thanks to thomasfla) @@ -1063,7 +1061,7 @@ uint32_t ACAN2517FD::readRegister32Assume_SPI_transaction (const uint16_t inRegi return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint16_t ACAN2517FD::readRegister16Assume_SPI_transaction (const uint16_t inRegisterAddress) { //--- Read half-word register via 4-byte buffer (speed enhancement, thanks to thomasfla) @@ -1082,7 +1080,7 @@ uint16_t ACAN2517FD::readRegister16Assume_SPI_transaction (const uint16_t inRegi return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint8_t ACAN2517FD::readRegister8Assume_SPI_transaction (const uint16_t inRegisterAddress) { //--- Read byte register via 3-byte buffer (speed enhancement, thanks to thomasfla) @@ -1096,71 +1094,71 @@ uint8_t ACAN2517FD::readRegister8Assume_SPI_transaction (const uint16_t inRegist return buffer [2] ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // MCP2517FD REGISTER ACCESS, THIRD LEVEL FUNCTIONS (HANDLE CS AND SPI TRANSACTION) -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::writeRegister8 (const uint16_t inRegisterAddress, const uint8_t inValue) { mSPI.beginTransaction (mSPISettings) ; turnOffInterrupts () ; writeRegister8Assume_SPI_transaction (inRegisterAddress, inValue) ; - turnOnInterrupts () ; + turnOnInterrupts () ; mSPI.endTransaction () ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint8_t ACAN2517FD::readRegister8 (const uint16_t inRegisterAddress) { mSPI.beginTransaction (mSPISettings) ; turnOffInterrupts () ; const uint8_t result = readRegister8Assume_SPI_transaction (inRegisterAddress) ; -turnOnInterrupts () ; + turnOnInterrupts () ; mSPI.endTransaction () ; return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint16_t ACAN2517FD::readRegister16 (const uint16_t inRegisterAddress) { mSPI.beginTransaction (mSPISettings) ; turnOffInterrupts () ; const uint16_t result = readRegister16Assume_SPI_transaction (inRegisterAddress) ; -turnOnInterrupts () ; + turnOnInterrupts () ; mSPI.endTransaction () ; return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::writeRegister32 (const uint16_t inRegisterAddress, const uint32_t inValue) { mSPI.beginTransaction (mSPISettings) ; turnOffInterrupts () ; writeRegister32Assume_SPI_transaction (inRegisterAddress, inValue) ; -turnOnInterrupts () ; + turnOnInterrupts () ; mSPI.endTransaction () ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FD::readRegister32 (const uint16_t inRegisterAddress) { mSPI.beginTransaction (mSPISettings) ; turnOffInterrupts () ; const uint32_t result = readRegister32Assume_SPI_transaction (inRegisterAddress) ; -turnOnInterrupts () ; + turnOnInterrupts () ; mSPI.endTransaction () ; return result ; } -//------------------------------------------------------------------------------ +//······················································································································ // Current MCP2517FD Operation Mode -//------------------------------------------------------------------------------ +//······················································································································ ACAN2517FDSettings::OperationMode ACAN2517FD::currentOperationMode (void) { const uint8_t mode = readRegister8 (CON_REGISTER + 2) >> 5 ; return ACAN2517FDSettings::OperationMode (mode) ; } -//------------------------------------------------------------------------------ +//······················································································································ bool ACAN2517FD::recoverFromRestrictedOperationMode (void) { bool recoveryDone = false ; @@ -1184,9 +1182,9 @@ bool ACAN2517FD::recoverFromRestrictedOperationMode (void) { return recoveryDone ; } -//------------------------------------------------------------------------------ +//······················································································································ // Set MCP2517FD Operation Mode -//------------------------------------------------------------------------------ +//······················································································································ void ACAN2517FD::setOperationMode (const ACAN2517FDSettings::OperationMode inOperationMode) { // bits 7-4: Transmit Bandwith Sharing Bits ---> 0 @@ -1194,7 +1192,7 @@ void ACAN2517FD::setOperationMode (const ACAN2517FDSettings::OperationMode inOpe writeRegister8 (CON_REGISTER + 3, uint8_t (inOperationMode)); } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::reset2517FD (void) { mSPI.beginTransaction (mSPISettings) ; // Check RESET is performed with 800 kHz clock @@ -1202,14 +1200,14 @@ void ACAN2517FD::reset2517FD (void) { assertCS () ; mSPI.transfer16 (0x00) ; // Reset instruction: 0x0000 deassertCS () ; -turnOnInterrupts () ; + turnOnInterrupts () ; mSPI.endTransaction () ; } -//------------------------------------------------------------------------------ +//······················································································································ // Sleep Mode to Configuration Mode // (returns true if MCP2517FD was in sleep mode) -//------------------------------------------------------------------------------ +//······················································································································ // The device exits Sleep mode due to a dominant edge on RXCAN or by enabling the oscillator (clearing OSC.OSCDIS). // The module will transition automatically to Configuration mode. @@ -1228,21 +1226,21 @@ bool ACAN2517FD::performSleepModeToConfigurationMode (void) { return inSleepMode ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FD::errorCounters (void) { return readRegister32 (TREC_REGISTER) ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FD::diagInfos (const int inIndex) { // thanks to Flole998 and turmary return readRegister32 (inIndex ? BDIAG1_REGISTER: BDIAG0_REGISTER) ; } -//------------------------------------------------------------------------------ +//······················································································································ // GPIO -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::gpioSetMode (const uint8_t inPin, const uint8_t inMode) { if (inPin <= 1) { @@ -1262,7 +1260,7 @@ void ACAN2517FD::gpioSetMode (const uint8_t inPin, const uint8_t inMode) { } } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::gpioWrite (const uint8_t inPin, const uint8_t inLevel) { if (inPin <= 1) { @@ -1276,14 +1274,14 @@ void ACAN2517FD::gpioWrite (const uint8_t inPin, const uint8_t inLevel) { } } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FD::gpioRead (const uint8_t inPin) { const uint8_t value = readRegister8 (IOCON_REGISTER_16_23) ; return (value >> inPin) & 1 ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- void ACAN2517FD::configureGPIO0AsXSTBY (void) { uint8_t value = readRegister8 (IOCON_REGISTER_00_07) ; @@ -1291,4 +1289,4 @@ void ACAN2517FD::configureGPIO0AsXSTBY (void) { writeRegister8 (IOCON_REGISTER_00_07, value) ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h index ec77b11c..d9f85db7 100644 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h @@ -1,16 +1,17 @@ -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // A CAN driver for MCP2517FD, CANFD mode // by Pierre Molinaro // https://github.com/pierremolinaro/acan2517FD -//------------------------------------------------------------------------------ +// +//---------------------------------------------------------------------------------------------------------------------- #pragma once -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #include "ACAN2517FDSettings.h" -#include "ACAN2517FD_ACANFDBuffer.h" -#include "ACAN2517FD_CANMessage.h" +#include "ACANFDBuffer.h" +#include "CANMessage.h" #include "ACAN2517FDFilters.h" #include @@ -24,23 +25,23 @@ // #define DISABLEMCP2517FDCOMPAT -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // ACAN2517FD class -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- class ACAN2517FD { - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CONSTRUCTOR - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// CONSTRUCTOR +//······················································································································ public: ACAN2517FD (const uint8_t inCS, // CS input of MCP2517FD SPIClass & inSPI, // Hardware SPI object const uint8_t inINT) ; // INT output of MCP2517FD - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // begin method (returns 0 if no error) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// begin method (returns 0 if no error) +//······················································································································ public: uint32_t begin (const ACAN2517FDSettings & inSettings, void (* inInterruptServiceRoutine) (void)) ; @@ -72,22 +73,22 @@ class ACAN2517FD { public: static const uint32_t kISRNotNullAndNoIntPin = uint32_t (1) << 19 ; public: static const uint32_t kInvalidTDCO = uint32_t (1) << 20 ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // end method (resets the MCP2517FD, deallocate buffers, and detach interrupt pin) - // Return true if end method succeeds, and false otherwise - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// end method (resets the MCP2517FD, deallocate buffers, and detach interrupt pin) +// Return true if end method succeeds, and false otherwise +//······················································································································ public: bool end (void) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send a message - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Send a message +//······················································································································ public: bool tryToSend (const CANFDMessage & inMessage) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Receive a message - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Receive a message +//······················································································································ public: bool receive (CANFDMessage & outMessage) ; public: bool available (void) ; @@ -97,44 +98,44 @@ class ACAN2517FD { //--- Call back function array private: ACANFDCallBackRoutine * mCallBackFunctionArray = NULL ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get error counters - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Get error counters +//······················································································································ public: uint32_t errorCounters (void) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get diagnostic information (thanks to Flole998 and turmary) - // inIndex == 0 returns BDIAG0_REGISTER - // inIndex != 0 returns BDIAG1_REGISTER - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Get diagnostic information (thanks to Flole998 and turmary) +// inIndex == 0 returns BDIAG0_REGISTER +// inIndex != 0 returns BDIAG1_REGISTER +//······················································································································ public: uint32_t diagInfos (const int inIndex = 1) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Operation Mode - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Operation Mode +//······················································································································ public: ACAN2517FDSettings::OperationMode currentOperationMode (void) ; public: void setOperationMode (const ACAN2517FDSettings::OperationMode inMode) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Recovery from Restricted Operation Mode - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Recovery from Restricted Operation Mode +//······················································································································ public: bool recoverFromRestrictedOperationMode (void) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Sleep Mode to Configuration Mode - // (returns true if MCP2517FD was in sleep mode) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Sleep Mode to Configuration Mode +// (returns true if MCP2517FD was in sleep mode) +//······················································································································ public: bool performSleepModeToConfigurationMode (void) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Private properties - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Private properties +//······················································································································ #ifdef ARDUINO_ARCH_ESP32 private: TaskHandle_t mESP32TaskHandle = nullptr ; @@ -146,51 +147,40 @@ class ACAN2517FD { private: bool mUsesTXQ ; private: bool mHardwareTxFIFOFull ; private: bool mRxInterruptEnabled ; // Added in 2.1.7 + private: bool mHasDataBitRate ; private: uint8_t mTransmitFIFOPayload ; // in byte count private: uint8_t mTXQBufferPayload ; // in byte count private: uint8_t mReceiveFIFOPayload ; // in byte count private: uint8_t mTXBWS_RequestedMode ; private: uint8_t mHardwareReceiveBufferOverflowCount ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Receive buffer - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Receive buffer +//······················································································································ private: ACANFDBuffer mDriverReceiveBuffer ; - public: uint32_t driverReceiveBufferPeakCount (void) const { - return mDriverReceiveBuffer.peakCount () ; - } + public: uint32_t driverReceiveBufferPeakCount (void) const { return mDriverReceiveBuffer.peakCount () ; } - public: uint8_t hardwareReceiveBufferOverflowCount (void) const { - return mHardwareReceiveBufferOverflowCount ; - } + public: uint8_t hardwareReceiveBufferOverflowCount (void) const { return mHardwareReceiveBufferOverflowCount ; } - public: void resetHardwareReceiveBufferOverflowCount (void) { - mHardwareReceiveBufferOverflowCount = 0 ; - } + public: void resetHardwareReceiveBufferOverflowCount (void) { mHardwareReceiveBufferOverflowCount = 0 ; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Transmit buffer - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Transmit buffer +//······················································································································ private: ACANFDBuffer mDriverTransmitBuffer ; - public: uint32_t driverTransmitBufferSize (void) const { - return mDriverTransmitBuffer.size () ; - } + public: uint32_t driverTransmitBufferSize (void) const { return mDriverTransmitBuffer.size () ; } - public: uint32_t driverTransmitBufferCount (void) const { - return mDriverTransmitBuffer.count () ; - } + public: uint32_t driverTransmitBufferCount (void) const { return mDriverTransmitBuffer.count () ; } - public: uint32_t driverTransmitBufferPeakCount (void) const { - return mDriverTransmitBuffer.peakCount () ; - } + public: uint32_t driverTransmitBufferPeakCount (void) const { return mDriverTransmitBuffer.peakCount () ; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Private methods - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Private methods +//······················································································································ private: void writeRegister32Assume_SPI_transaction (const uint16_t inRegisterAddress, const uint32_t inValue) ; private: void writeRegister8Assume_SPI_transaction (const uint16_t inRegisterAddress, const uint8_t inValue) ; @@ -212,15 +202,15 @@ class ACAN2517FD { private: bool enterInTransmitBuffer (const CANFDMessage & inMessage) ; private: void appendInControllerTxFIFO (const CANFDMessage & inMessage) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Polling - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Polling +//······················································································································ public: void poll (void) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Interrupt service routine - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Interrupt service routine +//······················································································································ public: void isr (void) ; public: void isr_poll_core (void) ; @@ -230,9 +220,9 @@ class ACAN2517FD { public: SemaphoreHandle_t mISRSemaphore ; #endif - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Optimized CS handling (thanks to Flole998) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//---------------------------------------------------------------------------------------------------------------------- +// Optimized CS handling (thanks to Flole998) +//······················································································································ #if defined(__AVR__) private: volatile uint8_t *cs_pin_reg; @@ -303,8 +293,10 @@ class ACAN2517FD { *(cs_pin_reg+8+2) = cs_pin_mask; } #elif defined(ARDUINO_ARCH_ESP8266) + // private: volatile uint32_t *cs_pin_reg; private: uint32_t cs_pin_mask; private: inline void initCS () { + // cs_pin_reg = (volatile uint32_t*)GPO; cs_pin_mask = 1 << mCS; pinMode(mCS, OUTPUT); } @@ -341,9 +333,9 @@ class ACAN2517FD { } #endif - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // GPIO - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// GPIO +//······················································································································ public: void gpioSetMode (const uint8_t inPin, const uint8_t inMode) ; @@ -353,16 +345,16 @@ class ACAN2517FD { public: void configureGPIO0AsXSTBY (void) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // No copy - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// No copy +//······················································································································ private: ACAN2517FD (const ACAN2517FD &) = delete ; private: ACAN2517FD & operator = (const ACAN2517FD &) = delete ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ } ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDFilters.h b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDFilters.h index 68fb71fe..69895acb 100644 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDFilters.h +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDFilters.h @@ -1,27 +1,27 @@ -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // An utility class for: // - ACAN2517FD CAN driver for MCP2517FD (CANFD mode) // by Pierre Molinaro // https://github.com/pierremolinaro/acan2517FD // -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #ifndef ACAN2517FD_FILTERS_CLASS_DEFINED #define ACAN2517FD_FILTERS_CLASS_DEFINED -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- -#include "ACAN2517FD_CANFDMessage.h" +#include "CANFDMessage.h" -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // ACAN2517FDFilters class -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- class ACAN2517FDFilters { -//------------------------------------------------------------------------------ +//······················································································································ // EMBEDDED CLASS -//------------------------------------------------------------------------------ +//······················································································································ private: class Filter { public: Filter * mNextFilter ; @@ -43,9 +43,9 @@ class ACAN2517FDFilters { private: Filter & operator = (const Filter &) ; } ; -//------------------------------------------------------------------------------ +//······················································································································ // ENUMERATED TYPE -//------------------------------------------------------------------------------ +//······················································································································ public: typedef enum { kFiltersOk, @@ -58,15 +58,15 @@ class ACAN2517FDFilters { kInconsistencyBetweenMaskAndAcceptance } FilterStatus ; -//------------------------------------------------------------------------------ +//······················································································································ // CONSTRUCTOR -//------------------------------------------------------------------------------ +//······················································································································ public: ACAN2517FDFilters (void) {} -//------------------------------------------------------------------------------ +//······················································································································ // DESTRUCTOR -//------------------------------------------------------------------------------ +//······················································································································ public: ~ ACAN2517FDFilters (void) { while (mFirstFilter != NULL) { @@ -76,9 +76,9 @@ class ACAN2517FDFilters { } } -//------------------------------------------------------------------------------ +//······················································································································ // RECEIVE FILTERS -//------------------------------------------------------------------------------ +//······················································································································ public: void appendPassAllFilter (const ACANFDCallBackRoutine inCallBackRoutine) { // Accept any frame Filter * f = new Filter (0, 0, inCallBackRoutine) ; @@ -91,7 +91,7 @@ class ACAN2517FDFilters { mFilterCount += 1 ; } -//------------------------------------------------------------------------------ +//······················································································································ public: void appendFormatFilter (const tFrameFormat inFormat, // Accept any identifier const ACANFDCallBackRoutine inCallBackRoutine) { @@ -107,7 +107,7 @@ class ACAN2517FDFilters { mFilterCount += 1 ; } -//------------------------------------------------------------------------------ +//······················································································································ public: void appendFrameFilter (const tFrameFormat inFormat, const uint32_t inIdentifier, @@ -141,7 +141,7 @@ class ACAN2517FDFilters { mFilterCount += 1 ; } -//------------------------------------------------------------------------------ +//······················································································································ public: void appendFilter (const tFrameFormat inFormat, const uint32_t inMask, @@ -196,9 +196,9 @@ class ACAN2517FDFilters { mFilterCount += 1 ; } -//------------------------------------------------------------------------------ +//······················································································································ // ACCESSORS -//------------------------------------------------------------------------------ +//······················································································································ public: FilterStatus filterStatus (void) const { return mFilterStatus ; } @@ -206,9 +206,9 @@ class ACAN2517FDFilters { public: uint8_t filterCount (void) const { return mFilterCount ; } -//------------------------------------------------------------------------------ +//······················································································································ // PRIVATE PROPERTIES -//------------------------------------------------------------------------------ +//······················································································································ private: uint8_t mFilterCount = 0 ; private: Filter * mFirstFilter = NULL ; @@ -216,23 +216,23 @@ class ACAN2517FDFilters { private: FilterStatus mFilterStatus = kFiltersOk ; private: uint8_t mFilterErrorIndex = 0 ; -//------------------------------------------------------------------------------ +//······················································································································ // NO COPY -//------------------------------------------------------------------------------ +//······················································································································ private: ACAN2517FDFilters (const ACAN2517FDFilters &) = delete ; private: ACAN2517FDFilters & operator = (const ACAN2517FDFilters &) = delete ; -//------------------------------------------------------------------------------ +//······················································································································ // Friend -//------------------------------------------------------------------------------ +//······················································································································ friend class ACAN2517FD ; -//------------------------------------------------------------------------------ +//······················································································································ } ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #endif diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDSettings.cpp b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDSettings.cpp index 09184d30..0a97683a 100644 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDSettings.cpp +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDSettings.cpp @@ -1,19 +1,19 @@ -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // A CAN driver for MCP2517FD (CANFD mode) // by Pierre Molinaro // https://github.com/pierremolinaro/acan2517FD // -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #include "ACAN2517FDSettings.h" -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #pragma GCC diagnostic error "-Wswitch-enum" -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // sysClock -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::sysClock (const Oscillator inOscillator) { uint32_t sysClock = 40UL * 1000 * 1000 ; @@ -39,9 +39,9 @@ uint32_t ACAN2517FDSettings::sysClock (const Oscillator inOscillator) { return sysClock ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // CONSTRUCTOR -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- ACAN2517FDSettings::ACAN2517FDSettings (const Oscillator inOscillator, const uint32_t inDesiredArbitrationBitRate, @@ -51,93 +51,148 @@ mOscillator (inOscillator), mSysClock (sysClock (inOscillator)), mDesiredArbitrationBitRate (inDesiredArbitrationBitRate), mDataBitRateFactor (inDataBitRateFactor) { -// First compute data bit rate - const uint32_t maxDataTQCount = MAX_DATA_PHASE_SEGMENT_1 + MAX_DATA_PHASE_SEGMENT_2 ; // Setting for slowest bit rate - const uint32_t desiredDataBitRate = inDesiredArbitrationBitRate * uint8_t (inDataBitRateFactor) ; - uint32_t smallestError = UINT32_MAX ; - uint32_t bestBRP = MAX_BRP ; // Setting for lowest bit rate - uint32_t bestDataTQCount = maxDataTQCount ; // Setting for lowest bit rate - uint32_t dataTQCount = 4 ; - uint32_t brp = mSysClock / desiredDataBitRate / dataTQCount ; -//--- Loop for finding best BRP and best TQCount - while ((dataTQCount <= maxDataTQCount) && (brp > 0)) { - //--- Compute error using brp - if (brp <= MAX_BRP) { - const uint32_t error = mSysClock - desiredDataBitRate * dataTQCount * brp ; // error is always >= 0 - if (error <= smallestError) { - smallestError = error ; - bestBRP = brp ; - bestDataTQCount = dataTQCount ; + if (inDataBitRateFactor == DataBitRateFactor::x1) { // Single bit rate + const uint32_t maxTQCount = MAX_ARBITRATION_PHASE_SEGMENT_1 + MAX_ARBITRATION_PHASE_SEGMENT_2 + 1 ; // Setting for slowest bit rate + uint32_t BRP = MAX_BRP ; + uint32_t smallestError = UINT32_MAX ; + uint32_t bestBRP = 1 ; // Setting for highest bit rate + uint32_t bestTQCount = 4 ; // Setting for highest bit rate + uint32_t TQCount = mSysClock / inDesiredArbitrationBitRate / BRP ; + //--- Loop for finding best BRP and best TQCount + while ((TQCount <= (MAX_ARBITRATION_PHASE_SEGMENT_1 + MAX_ARBITRATION_PHASE_SEGMENT_2 + 1)) && (BRP > 0)) { + //--- Compute error using TQCount + if ((TQCount >= 4) && (TQCount <= maxTQCount)) { + const uint32_t error = mSysClock - inDesiredArbitrationBitRate * TQCount * BRP ; // error is always >= 0 + if (error <= smallestError) { + smallestError = error ; + bestBRP = BRP ; + bestTQCount = TQCount ; + } } - } - //--- Compute error using brp+1 - if (brp < MAX_BRP) { - const uint32_t error = desiredDataBitRate * dataTQCount * (brp + 1) - mSysClock ; // error is always >= 0 - if (error <= smallestError) { - smallestError = error ; - bestBRP = brp + 1 ; - bestDataTQCount = dataTQCount ; + //--- Compute error using TQCount+1 + if ((TQCount >= 3) && (TQCount < maxTQCount)) { + const uint32_t error = inDesiredArbitrationBitRate * (TQCount + 1) * BRP - mSysClock ; // error is always >= 0 + if (error <= smallestError) { + smallestError = error ; + bestBRP = BRP ; + bestTQCount = TQCount + 1 ; + } } + //--- Continue with next value of BRP + BRP -- ; + TQCount = (BRP == 0) ? (maxTQCount + 1) : (mSysClock / inDesiredArbitrationBitRate / BRP) ; } - //--- Continue with next value of BRP - dataTQCount += 1 ; - brp = mSysClock / desiredDataBitRate / dataTQCount ; + //--- Compute PS2 (1 <= PS2 <= 128) + uint32_t PS2 = bestTQCount / 5 ; // For sampling point at 80% + if (PS2 == 0) { + PS2 = 1 ; + }else if (PS2 > MAX_ARBITRATION_PHASE_SEGMENT_2) { + PS2 = MAX_ARBITRATION_PHASE_SEGMENT_2 ; + } + //--- Compute PS1 (1 <= PS1 <= 256) + uint32_t PS1 = bestTQCount - PS2 - 1 /* Sync Seg */ ; + if (PS1 > MAX_ARBITRATION_PHASE_SEGMENT_1) { + PS2 += PS1 - MAX_ARBITRATION_PHASE_SEGMENT_1 ; + PS1 = MAX_ARBITRATION_PHASE_SEGMENT_1 ; + } + //--- + mBitRatePrescaler = (uint16_t) bestBRP ; + mArbitrationPhaseSegment1 = (uint16_t) PS1 ; + mArbitrationPhaseSegment2 = (uint8_t) PS2 ; + mArbitrationSJW = mArbitrationPhaseSegment2 ; // Always 1 <= SJW <= 128, and SJW <= mArbitrationPhaseSegment2 + //--- Final check of the nominal configuration + const uint32_t W = bestTQCount * mDesiredArbitrationBitRate * bestBRP ; + const uint64_t diff = (mSysClock > W) ? (mSysClock - W) : (W - mSysClock) ; + const uint64_t ppm = (uint64_t) (1000UL * 1000UL) ; // UL suffix is required for Arduino Uno + mArbitrationBitRateClosedToDesiredRate = (diff * ppm) <= (((uint64_t) W) * inTolerancePPM) ; + }else{ // Dual bit rate, first compute data bit rate + const uint32_t maxDataTQCount = MAX_DATA_PHASE_SEGMENT_1 + MAX_DATA_PHASE_SEGMENT_2 ; // Setting for slowest bit rate + const uint32_t desiredDataBitRate = inDesiredArbitrationBitRate * uint8_t (inDataBitRateFactor) ; + uint32_t smallestError = UINT32_MAX ; + uint32_t bestBRP = MAX_BRP ; // Setting for lowest bit rate + uint32_t bestDataTQCount = maxDataTQCount ; // Setting for lowest bit rate + uint32_t dataTQCount = 4 ; + uint32_t brp = mSysClock / desiredDataBitRate / dataTQCount ; + //--- Loop for finding best BRP and best TQCount + while ((dataTQCount <= maxDataTQCount) && (brp > 0)) { + //--- Compute error using brp + if (brp <= MAX_BRP) { + const uint32_t error = mSysClock - desiredDataBitRate * dataTQCount * brp ; // error is always >= 0 + if (error <= smallestError) { + smallestError = error ; + bestBRP = brp ; + bestDataTQCount = dataTQCount ; + } + } + //--- Compute error using brp+1 + if (brp < MAX_BRP) { + const uint32_t error = desiredDataBitRate * dataTQCount * (brp + 1) - mSysClock ; // error is always >= 0 + if (error <= smallestError) { + smallestError = error ; + bestBRP = brp + 1 ; + bestDataTQCount = dataTQCount ; + } + } + //--- Continue with next value of BRP + dataTQCount += 1 ; + brp = mSysClock / desiredDataBitRate / dataTQCount ; + } + //--- Compute data PS2 (1 <= PS2 <= 16) + uint32_t dataPS2 = bestDataTQCount / 5 ; // For sampling point at 80% + if (dataPS2 == 0) { + dataPS2 = 1 ; + } + //--- Compute data PS1 (1 <= PS1 <= 32) + uint32_t dataPS1 = bestDataTQCount - dataPS2 - 1 /* Sync Seg */ ; + if (dataPS1 > MAX_DATA_PHASE_SEGMENT_1) { + dataPS2 += dataPS1 - MAX_DATA_PHASE_SEGMENT_1 ; + dataPS1 = MAX_DATA_PHASE_SEGMENT_1 ; + } + //--- + if ((mDesiredArbitrationBitRate * uint32_t (inDataBitRateFactor)) <= (1000UL * 1000)) { + mTDCO = 0 ; + }else{ + const int TDCO = bestBRP * dataPS1 ; // According to DS20005678D, §3.4.8 Page 20 + mTDCO = (TDCO > 63) ? 63 : (int8_t) TDCO ; + } + mDataPhaseSegment1 = (uint8_t) dataPS1 ; + mDataPhaseSegment2 = (uint8_t) dataPS2 ; + mDataSJW = mDataPhaseSegment2 ; + const uint32_t arbitrationTQCount = bestDataTQCount * uint8_t (mDataBitRateFactor) ; + //--- Compute arbiration PS2 (1 <= PS2 <= 128) + uint32_t arbitrationPS2 = arbitrationTQCount / 5 ; // For sampling point at 80% + if (arbitrationPS2 == 0) { + arbitrationPS2 = 1 ; + } + //--- Compute PS1 (1 <= PS1 <= 256) + uint32_t arbitrationPS1 = arbitrationTQCount - arbitrationPS2 - 1 /* Sync Seg */ ; + if (arbitrationPS1 > MAX_ARBITRATION_PHASE_SEGMENT_1) { + arbitrationPS2 += arbitrationPS1 - MAX_ARBITRATION_PHASE_SEGMENT_1 ; + arbitrationPS1 = MAX_ARBITRATION_PHASE_SEGMENT_1 ; + } + //--- + mBitRatePrescaler = (uint16_t) bestBRP ; + mArbitrationPhaseSegment1 = (uint16_t) arbitrationPS1 ; + mArbitrationPhaseSegment2 = (uint8_t) arbitrationPS2 ; + mArbitrationSJW = mArbitrationPhaseSegment2 ; // Always 1 <= SJW <= 128, and SJW <= mArbitrationPhaseSegment2 + //--- Final check of the nominal configuration + const uint32_t W = arbitrationTQCount * mDesiredArbitrationBitRate * bestBRP ; + const uint64_t diff = (mSysClock > W) ? (mSysClock - W) : (W - mSysClock) ; + const uint64_t ppm = (uint64_t) (1000UL * 1000UL) ; // UL suffix is required for Arduino Uno + mArbitrationBitRateClosedToDesiredRate = (diff * ppm) <= (((uint64_t) W) * inTolerancePPM) ; } -//--- Compute data PS2 (1 <= PS2 <= 16) - uint32_t dataPS2 = bestDataTQCount / 5 ; // For sampling point at 80% - if (dataPS2 == 0) { - dataPS2 = 1 ; - } -//--- Compute data PS1 (1 <= PS1 <= 32) - uint32_t dataPS1 = bestDataTQCount - dataPS2 - 1 /* Sync Seg */ ; - if (dataPS1 > MAX_DATA_PHASE_SEGMENT_1) { - dataPS2 += dataPS1 - MAX_DATA_PHASE_SEGMENT_1 ; - dataPS1 = MAX_DATA_PHASE_SEGMENT_1 ; - } -//--- - if ((mDesiredArbitrationBitRate * uint32_t (inDataBitRateFactor)) <= (1000UL * 1000)) { - mTDCO = 0 ; - }else{ - const int TDCO = bestBRP * dataPS1 ; // According to DS20005678D, §3.4.8 Page 20 - mTDCO = (TDCO > 63) ? 63 : (int8_t) TDCO ; - } - mDataPhaseSegment1 = (uint8_t) dataPS1 ; - mDataPhaseSegment2 = (uint8_t) dataPS2 ; - mDataSJW = mDataPhaseSegment2 ; - const uint32_t arbitrationTQCount = bestDataTQCount * uint8_t (mDataBitRateFactor) ; -//--- Compute arbitration PS2 (1 <= PS2 <= 128) - uint32_t arbitrationPS2 = arbitrationTQCount / 5 ; // For sampling point at 80% - if (arbitrationPS2 == 0) { - arbitrationPS2 = 1 ; - } -//--- Compute PS1 (1 <= PS1 <= 256) - uint32_t arbitrationPS1 = arbitrationTQCount - arbitrationPS2 - 1 /* Sync Seg */ ; - if (arbitrationPS1 > MAX_ARBITRATION_PHASE_SEGMENT_1) { - arbitrationPS2 += arbitrationPS1 - MAX_ARBITRATION_PHASE_SEGMENT_1 ; - arbitrationPS1 = MAX_ARBITRATION_PHASE_SEGMENT_1 ; - } -//--- - mBitRatePrescaler = (uint16_t) bestBRP ; - mArbitrationPhaseSegment1 = (uint16_t) arbitrationPS1 ; - mArbitrationPhaseSegment2 = (uint8_t) arbitrationPS2 ; - mArbitrationSJW = mArbitrationPhaseSegment2 ; // Always 1 <= SJW <= 128, and SJW <= mArbitrationPhaseSegment2 -//--- Final check of the nominal configuration - const uint32_t W = arbitrationTQCount * mDesiredArbitrationBitRate * bestBRP ; - const uint64_t diff = (mSysClock > W) ? (mSysClock - W) : (W - mSysClock) ; - const uint64_t ppm = (uint64_t) (1000UL * 1000UL) ; // UL suffix is required for Arduino Uno - mArbitrationBitRateClosedToDesiredRate = (diff * ppm) <= (((uint64_t) W) * inTolerancePPM) ; } ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // ACCESSORS -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::actualArbitrationBitRate (void) const { const uint32_t arbitrationTQCount = 1 /* Sync Seg */ + mArbitrationPhaseSegment1 + mArbitrationPhaseSegment2 ; return mSysClock / mBitRatePrescaler / arbitrationTQCount ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::actualDataBitRate (void) const { if (mDataBitRateFactor == DataBitRateFactor::x1) { @@ -148,14 +203,14 @@ uint32_t ACAN2517FDSettings::actualDataBitRate (void) const { } } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FDSettings::exactArbitrationBitRate (void) const { const uint32_t TQCount = 1 /* Sync Seg */ + mArbitrationPhaseSegment1 + mArbitrationPhaseSegment2 ; return mSysClock == (mBitRatePrescaler * mDesiredArbitrationBitRate * TQCount) ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FDSettings::exactDataBitRate (void) const { if (mDataBitRateFactor == DataBitRateFactor::x1) { @@ -166,7 +221,7 @@ bool ACAN2517FDSettings::exactDataBitRate (void) const { } } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FDSettings::dataBitRateIsAMultipleOfArbitrationBitRate (void) const { bool result = mDataBitRateFactor == DataBitRateFactor::x1 ; @@ -178,7 +233,7 @@ bool ACAN2517FDSettings::dataBitRateIsAMultipleOfArbitrationBitRate (void) const return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::ppmFromDesiredArbitrationBitRate (void) const { const uint32_t TQCount = 1 /* Sync Seg */ + mArbitrationPhaseSegment1 + mArbitrationPhaseSegment2 ; @@ -188,7 +243,7 @@ uint32_t ACAN2517FDSettings::ppmFromDesiredArbitrationBitRate (void) const { return (uint32_t) ((diff * ppm) / W) ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::arbitrationSamplePointFromBitStart (void) const { const uint32_t nominalTQCount = 1 /* Sync Seg */ + mArbitrationPhaseSegment1 + mArbitrationPhaseSegment2 ; @@ -197,7 +252,7 @@ uint32_t ACAN2517FDSettings::arbitrationSamplePointFromBitStart (void) const { return (samplePoint * partPerCent) / nominalTQCount ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::dataSamplePointFromBitStart (void) const { const uint32_t nominalTQCount = 1 /* Sync Seg */ + mDataPhaseSegment1 + mDataPhaseSegment2 ; @@ -206,7 +261,7 @@ uint32_t ACAN2517FDSettings::dataSamplePointFromBitStart (void) const { return (samplePoint * partPerCent) / nominalTQCount ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::CANBitSettingConsistency (void) const { uint32_t errorCode = 0 ; // Means no error @@ -274,9 +329,9 @@ uint32_t ACAN2517FDSettings::CANBitSettingConsistency (void) const { return errorCode ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // RAM USAGE -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::ramUsage (void) const { uint32_t result = 0 ; @@ -290,11 +345,11 @@ uint32_t ACAN2517FDSettings::ramUsage (void) const { return result ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- uint32_t ACAN2517FDSettings::objectSizeForPayload (const PayloadSize inPayload) { static const uint8_t kPayload [8] = {16, 20, 24, 28, 32, 40, 56, 72} ; return kPayload [inPayload] ; } -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDSettings.h b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDSettings.h index 38eb0381..ec86560c 100644 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDSettings.h +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FDSettings.h @@ -1,25 +1,25 @@ -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // A CAN driver for MCP2517FD (CANFD mode) // by Pierre Molinaro // https://github.com/pierremolinaro/acan2517FD // -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #pragma once -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- -#include "ACAN2517FD_DataBitRateFactor.h" +#include "ACANFD_DataBitRateFactor.h" -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // ACAN2517FDSettings class -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- class ACAN2517FDSettings { - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ENUMERATED TYPES - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// ENUMERATED TYPES +//······················································································································ public: typedef enum : uint8_t { OSC_4MHz, @@ -64,9 +64,9 @@ class ACAN2517FDSettings { PAYLOAD_64 = 7 } PayloadSize ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Deprecated enumeration (now use DataBitRateFactor declared in ACANFD_DataBitRateFactor.h) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Deprecated enumeration (now use DataBitRateFactor declared in ACANFD_DataBitRateFactor.h) +//······················································································································ public : typedef enum : uint8_t { DATA_BITRATE_x1 = 1, @@ -81,18 +81,18 @@ class ACAN2517FDSettings { DATA_BITRATE_x10 = 10 } DataBitRateFactor_Deprecated ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CONSTRUCTOR - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// CONSTRUCTOR +//······················································································································ public: ACAN2517FDSettings (const Oscillator inOscillator, const uint32_t inDesiredArbitrationBitRate, const DataBitRateFactor inDataBitRateFactor, const uint32_t inTolerancePPM = 1000) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // DEPRECATED CONSTRUCTOR (for compatibility with version < 2.1.0) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// DEPRECATED CONSTRUCTOR (for compatibility with version < 2.1.0) +//······················································································································ public: ACAN2517FDSettings (const Oscillator inOscillator, const uint32_t inDesiredArbitrationBitRate, @@ -101,9 +101,9 @@ class ACAN2517FDSettings { ACAN2517FDSettings (inOscillator, inDesiredArbitrationBitRate, DataBitRateFactor (inDataBitRateFactor), inTolerancePPM) { } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CAN BIT TIMING - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// CAN BIT TIMING +//······················································································································ private: Oscillator mOscillator ; private: uint32_t mSysClock ; // In Hz @@ -123,44 +123,44 @@ class ACAN2517FDSettings { //--- Transmitter Delay Compensation Offset public: int8_t mTDCO = 0 ; // -64 ... +63 - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // MCP2517FD TXCAN pin is Open Drain ? - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// MCP2517FD TXCAN pin is Open Drain ? +//······················································································································ public: bool mTXCANIsOpenDrain = false ; // false --> Push/Pull Output, true --> Open Drain Output - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // MCP2517FD INT pin is Open Drain ? - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// MCP2517FD INT pin is Open Drain ? +//······················································································································ public: bool mINTIsOpenDrain = false ; // false --> Push/Pull Output, true --> Open Drain Output - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ISO CRC Enable - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// ISO CRC Enable +//······················································································································ // false --> Do NOT include Stuff Bit Count in CRC Field and use CRC Initialization Vector with all zeros // true --> Include Stuff Bit Count in CRC Field and use Non-Zero CRC Initialization Vector according to ISO 11898-1:2015 public: bool mISOCRCEnabled = true ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // CLKO pin function (default value is MCP2517FD power on setting) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// CLKO pin function (default value is MCP2517FD power on setting) +//······················································································································ public: CLKOpin mCLKOPin = CLKO_DIVIDED_BY_10 ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Requested mode - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Requested mode +//······················································································································ public: OperationMode mRequestedMode = NormalFD ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // TRANSMIT FIFO - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// TRANSMIT FIFO +//······················································································································ //--- Driver transmit buffer size - public: uint16_t mDriverTransmitFIFOSize = 16 ; // >= 0 + public: uint16_t mDriverTransmitFIFOSize = 22 ; // >= 0 //--- Controller transmit FIFO size public: uint8_t mControllerTransmitFIFOSize = 1 ; // 1 ... 32 @@ -174,9 +174,9 @@ class ACAN2517FDSettings { //--- Controller transmit FIFO retransmission attempts public: RetransmissionAttempts mControllerTransmitFIFORetransmissionAttempts = UnlimitedNumber ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // TXQ BUFFER - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// TXQ BUFFER +//······················································································································ //--- TXQ buffer size (0 --> TXQ disabled) public: uint8_t mControllerTXQSize = 0 ; // 0 ... 32 @@ -191,9 +191,9 @@ class ACAN2517FDSettings { public: RetransmissionAttempts mControllerTXQBufferRetransmissionAttempts = UnlimitedNumber ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // RECEIVE FIFO - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// RECEIVE FIFO +//······················································································································ //--- Driver receive buffer size public: uint16_t mDriverReceiveFIFOSize = 32 ; // > 0 @@ -204,15 +204,15 @@ class ACAN2517FDSettings { //--- Controller receive FIFO size public: uint8_t mControllerReceiveFIFOSize = 27 ; // 1 ... 32 - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // SYSCLOCK frequency computation - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// SYSCLOCK frequency computation +//······················································································································ public: static uint32_t sysClock (const Oscillator inOscillator) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Accessors - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Accessors +//······················································································································ public: Oscillator oscillator (void) const { return mOscillator ; } public: uint32_t sysClock (void) const { return mSysClock ; } @@ -222,61 +222,61 @@ class ACAN2517FDSettings { public: bool exactDataBitRate (void) const ; public: bool dataBitRateIsAMultipleOfArbitrationBitRate (void) const ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // RAM USAGE - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// RAM USAGE +//······················································································································ public: uint32_t ramUsage (void) const ; public: static uint32_t objectSizeForPayload (const PayloadSize inPayload) ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Distance between actual bit rate and requested bit rate (in ppm, part-per-million) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Distance between actual bit rate and requested bit rate (in ppm, part-per-million) +//······················································································································ public: uint32_t ppmFromDesiredArbitrationBitRate (void) const ; public: uint32_t ppmFromDesiredDataBitRate (void) const ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Distance of sample point from bit start (in ppc, part-per-cent, denoted by %) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Distance of sample point from bit start (in ppc, part-per-cent, denoted by %) +//······················································································································ public: uint32_t arbitrationSamplePointFromBitStart (void) const ; public: uint32_t dataSamplePointFromBitStart (void) const ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Bit settings are consistent ? (returns 0 if ok) - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Bit settings are consistent ? (returns 0 if ok) +//······················································································································ public: uint32_t CANBitSettingConsistency (void) const ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Constants returned by CANBitSettingConsistency - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Constants returned by CANBitSettingConsistency +//······················································································································ - public: static const uint32_t kBitRatePrescalerIsZero = uint32_t (1) << 0 ; - public: static const uint32_t kBitRatePrescalerIsGreaterThan256 = uint32_t (1) << 1 ; - public: static const uint32_t kArbitrationPhaseSegment1IsLowerThan2 = uint32_t (1) << 2 ; - public: static const uint32_t kArbitrationPhaseSegment1IsGreaterThan256 = uint32_t (1) << 3 ; - public: static const uint32_t kArbitrationPhaseSegment2IsZero = uint32_t (1) << 4 ; - public: static const uint32_t kArbitrationPhaseSegment2IsGreaterThan128 = uint32_t (1) << 5 ; - public: static const uint32_t kArbitrationSJWIsZero = uint32_t (1) << 6 ; - public: static const uint32_t kArbitrationSJWIsGreaterThan128 = uint32_t (1) << 7 ; - public: static const uint32_t kArbitrationSJWIsGreaterThanPhaseSegment1 = uint32_t (1) << 8 ; - public: static const uint32_t kArbitrationSJWIsGreaterThanPhaseSegment2 = uint32_t (1) << 9 ; - public: static const uint32_t kArbitrationTQCountNotDivisibleByDataBitRateFactor = uint32_t (1) << 10 ; - public: static const uint32_t kDataPhaseSegment1IsLowerThan2 = uint32_t (1) << 11 ; - public: static const uint32_t kDataPhaseSegment1IsGreaterThan32 = uint32_t (1) << 12 ; - public: static const uint32_t kDataPhaseSegment2IsZero = uint32_t (1) << 13 ; - public: static const uint32_t kDataPhaseSegment2IsGreaterThan16 = uint32_t (1) << 14 ; - public: static const uint32_t kDataSJWIsZero = uint32_t (1) << 15 ; - public: static const uint32_t kDataSJWIsGreaterThan16 = uint32_t (1) << 16 ; - public: static const uint32_t kDataSJWIsGreaterThanPhaseSegment1 = uint32_t (1) << 17 ; - public: static const uint32_t kDataSJWIsGreaterThanPhaseSegment2 = uint32_t (1) << 18 ; + public: static const uint32_t kBitRatePrescalerIsZero = ((uint32_t) 1) << 0 ; + public: static const uint32_t kBitRatePrescalerIsGreaterThan256 = ((uint32_t) 1) << 1 ; + public: static const uint32_t kArbitrationPhaseSegment1IsLowerThan2 = ((uint32_t) 1) << 2 ; + public: static const uint32_t kArbitrationPhaseSegment1IsGreaterThan256 = ((uint32_t) 1) << 3 ; + public: static const uint32_t kArbitrationPhaseSegment2IsZero = ((uint32_t) 1) << 4 ; + public: static const uint32_t kArbitrationPhaseSegment2IsGreaterThan128 = ((uint32_t) 1) << 5 ; + public: static const uint32_t kArbitrationSJWIsZero = ((uint32_t) 1) << 6 ; + public: static const uint32_t kArbitrationSJWIsGreaterThan128 = ((uint32_t) 1) << 7 ; + public: static const uint32_t kArbitrationSJWIsGreaterThanPhaseSegment1 = ((uint32_t) 1) << 8 ; + public: static const uint32_t kArbitrationSJWIsGreaterThanPhaseSegment2 = ((uint32_t) 1) << 9 ; + public: static const uint32_t kArbitrationTQCountNotDivisibleByDataBitRateFactor = ((uint32_t) 1) << 10 ; + public: static const uint32_t kDataPhaseSegment1IsLowerThan2 = ((uint32_t) 1) << 11 ; + public: static const uint32_t kDataPhaseSegment1IsGreaterThan32 = ((uint32_t) 1) << 12 ; + public: static const uint32_t kDataPhaseSegment2IsZero = ((uint32_t) 1) << 13 ; + public: static const uint32_t kDataPhaseSegment2IsGreaterThan16 = ((uint32_t) 1) << 14 ; + public: static const uint32_t kDataSJWIsZero = ((uint32_t) 1) << 15 ; + public: static const uint32_t kDataSJWIsGreaterThan16 = ((uint32_t) 1) << 16 ; + public: static const uint32_t kDataSJWIsGreaterThanPhaseSegment1 = ((uint32_t) 1) << 17 ; + public: static const uint32_t kDataSJWIsGreaterThanPhaseSegment2 = ((uint32_t) 1) << 18 ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Max values - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ +// Max values +//······················································································································ public: static const uint16_t MAX_BRP = 256 ; @@ -288,9 +288,9 @@ class ACAN2517FDSettings { public: static const uint8_t MAX_DATA_PHASE_SEGMENT_2 = 16 ; public: static const uint8_t MAX_DATA_SJW = 16 ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//······················································································································ } ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_ACANFDBuffer.h b/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_ACANFDBuffer.h deleted file mode 100644 index e474f9f1..00000000 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_ACANFDBuffer.h +++ /dev/null @@ -1,122 +0,0 @@ -//------------------------------------------------------------------------------ -// A CAN driver for MCP2517FD CAN Controller in CANFD mode -// by Pierre Molinaro -// https://github.com/pierremolinaro/acan2517FD -// -//------------------------------------------------------------------------------ - -#ifndef ACANFD_BUFFER_CLASS_DEFINED -#define ACANFD_BUFFER_CLASS_DEFINED - -//------------------------------------------------------------------------------ - -#include "ACAN2517FD_CANFDMessage.h" - -//------------------------------------------------------------------------------ - -class ACANFDBuffer { - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Default constructor - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public: ACANFDBuffer (void) : - mBuffer (NULL), - mSize (0), - mReadIndex (0), - mCount (0), - mPeakCount (0) { - } - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Destructor - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public: ~ ACANFDBuffer (void) { - delete [] mBuffer ; - } - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Private properties - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - private: CANFDMessage * mBuffer ; - private: uint32_t mSize ; - private: uint32_t mReadIndex ; - private: uint32_t mCount ; - private: uint32_t mPeakCount ; // > mSize if overflow did occur - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Accessors - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public: inline uint32_t size (void) const { return mSize ; } - public: inline uint32_t count (void) const { return mCount ; } - public: inline bool isFull (void) const { return mCount == mSize ; } // Added in release 2.17 (thanks to Flole998) - public: inline uint32_t peakCount (void) const { return mPeakCount ; } - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // initWithSize - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public: void initWithSize (const uint32_t inSize) { - delete [] mBuffer ; mBuffer = new CANFDMessage [inSize] ; - mSize = inSize ; - mReadIndex = 0 ; - mCount = 0 ; - mPeakCount = 0 ; - } - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // append - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public: bool append (const CANFDMessage & inMessage) { - const bool ok = mCount < mSize ; - if (ok) { - uint32_t writeIndex = mReadIndex + mCount ; - if (writeIndex >= mSize) { - writeIndex -= mSize ; - } - mBuffer [writeIndex] = inMessage ; - mCount += 1 ; - if (mPeakCount < mCount) { - mPeakCount = mCount ; - } - }else{ - mPeakCount = mSize + 1 ; - } - return ok ; - } - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Remove - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public: bool remove (CANFDMessage & outMessage) { - const bool ok = mCount > 0 ; - if (ok) { - outMessage = mBuffer [mReadIndex] ; - mCount -= 1 ; - mReadIndex += 1 ; - if (mReadIndex == mSize) { - mReadIndex = 0 ; - } - } - return ok ; - } - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // No copy - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - private: ACANFDBuffer (const ACANFDBuffer &) = delete ; - private: ACANFDBuffer & operator = (const ACANFDBuffer &) = delete ; - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -} ; - -//------------------------------------------------------------------------------ - -#endif diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACANFDBuffer.h b/Software/src/lib/pierremolinaro-ACAN2517FD/ACANFDBuffer.h new file mode 100644 index 00000000..75de5ef8 --- /dev/null +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/ACANFDBuffer.h @@ -0,0 +1,119 @@ +//---------------------------------------------------------------------------------------------------------------------- +// A CAN driver for MCP2517FD CAN Controller in CANFD mode +// by Pierre Molinaro +// https://github.com/pierremolinaro/acan2517FD +// +//---------------------------------------------------------------------------------------------------------------------- + +#ifndef ACANFD_BUFFER_CLASS_DEFINED +#define ACANFD_BUFFER_CLASS_DEFINED + +//---------------------------------------------------------------------------------------------------------------------- + +#include "CANFDMessage.h" + +//---------------------------------------------------------------------------------------------------------------------- + +class ACANFDBuffer { + +//······················································································································ +// Default constructor +//······················································································································ + + public: ACANFDBuffer (void) : + mBuffer (NULL), + mSize (0), + mReadIndex (0), + mCount (0), + mPeakCount (0) { + } + +//······················································································································ +// Destructor +//······················································································································ + + public: ~ ACANFDBuffer (void) { + delete [] mBuffer ; + } + +//······················································································································ +// Private properties +//······················································································································ + + private: CANFDMessage * mBuffer ; + private: uint32_t mSize ; + private: uint32_t mReadIndex ; + private: uint32_t mCount ; + private: uint32_t mPeakCount ; // > mSize if overflow did occur + +//······················································································································ +// Accessors +//······················································································································ + + public: inline uint32_t size (void) const { return mSize ; } + public: inline uint32_t count (void) const { return mCount ; } + public: inline bool isFull (void) const { return mCount == mSize ; } // Added in release 2.17 (thanks to Flole998) + public: inline uint32_t peakCount (void) const { return mPeakCount ; } + +//······················································································································ +// initWithSize +//······················································································································ + + public: void initWithSize (const uint32_t inSize) { + delete [] mBuffer ; mBuffer = new CANFDMessage [inSize] ; + mSize = inSize ; + mReadIndex = 0 ; + mCount = 0 ; + mPeakCount = 0 ; + } + +//······················································································································ +// append +//······················································································································ + + public: bool append (const CANFDMessage & inMessage) { + const bool ok = mCount < mSize ; + if (ok) { + uint32_t writeIndex = mReadIndex + mCount ; + if (writeIndex >= mSize) { + writeIndex -= mSize ; + } + mBuffer [writeIndex] = inMessage ; + mCount += 1 ; + if (mPeakCount < mCount) { + mPeakCount = mCount ; + } + }else{ + mPeakCount = mSize + 1 ; + } + return ok ; + } + +//······················································································································ +// Remove +//······················································································································ + + public: bool remove (CANFDMessage & outMessage) { + const bool ok = mCount > 0 ; + if (ok) { + outMessage = mBuffer [mReadIndex] ; + mCount -= 1 ; + mReadIndex += 1 ; + if (mReadIndex == mSize) { + mReadIndex = 0 ; + } + } + return ok ; + } + +//······················································································································ +// No copy +//······················································································································ + + private: ACANFDBuffer (const ACANFDBuffer &) = delete ; + private: ACANFDBuffer & operator = (const ACANFDBuffer &) = delete ; +} ; + +//---------------------------------------------------------------------------------------------------------------------- + +#endif diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_DataBitRateFactor.h b/Software/src/lib/pierremolinaro-ACAN2517FD/ACANFD_DataBitRateFactor.h similarity index 73% rename from Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_DataBitRateFactor.h rename to Software/src/lib/pierremolinaro-ACAN2517FD/ACANFD_DataBitRateFactor.h index b3868638..7177cae4 100644 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_DataBitRateFactor.h +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/ACANFD_DataBitRateFactor.h @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // A CANFD driver // by Pierre Molinaro @@ -6,16 +6,16 @@ // https://github.com/pierremolinaro/ACAN_T4 // https://github.com/pierremolinaro/ACAN2517FD // -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #ifndef ACANFD_DATA_BIT_RATE_FACTOR_DEFINED #define ACANFD_DATA_BIT_RATE_FACTOR_DEFINED -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #include -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- enum class DataBitRateFactor : uint8_t { x1 = 1, @@ -30,6 +30,6 @@ enum class DataBitRateFactor : uint8_t { x10 = 10 } ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #endif diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_CANFDMessage.h b/Software/src/lib/pierremolinaro-ACAN2517FD/CANFDMessage.h similarity index 65% rename from Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_CANFDMessage.h rename to Software/src/lib/pierremolinaro-ACAN2517FD/CANFDMessage.h index 64f3838b..10cf7d3b 100644 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_CANFDMessage.h +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/CANFDMessage.h @@ -1,21 +1,21 @@ -//------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- // Generic CANFD Message // by Pierre Molinaro // // https://github.com/pierremolinaro/acan2517FD // -//------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- #ifndef GENERIC_CANFD_MESSAGE_DEFINED #define GENERIC_CANFD_MESSAGE_DEFINED -//------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- -#include "ACAN2517FD_CANMessage.h" +#include "CANMessage.h" -//------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- // CANFDMessage class -//------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- // Note that "len" field contains the actual length, not its encoding in CANFD frames // Valid values are: 0, 1, ..., 8, 12, 16, 20, 24, 32, 48, 64. // Having other values is an error that prevents frame to be sent by tryToSend @@ -23,9 +23,9 @@ class CANFDMessage { - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Constructors - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//············································································· +// Constructors +//············································································· public : CANFDMessage (void) : id (0), // Frame identifier @@ -36,7 +36,7 @@ class CANFDMessage { data () { } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//············································································· public : CANFDMessage (const CANMessage & inMessage) : id (inMessage.id), // Frame identifier @@ -48,9 +48,9 @@ class CANFDMessage { data64 [0] = inMessage.data64 ; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Enumerated Type - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//············································································· +// Enumerated Type +//············································································· public: typedef enum : uint8_t { CAN_REMOTE, @@ -59,9 +59,9 @@ class CANFDMessage { CANFD_WITH_BIT_RATE_SWITCH } Type ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Properties - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//············································································· +// Properties +//············································································· public : uint32_t id ; // Frame identifier public : bool ext ; // false -> base frame, true -> extended frame @@ -80,9 +80,9 @@ class CANFDMessage { uint8_t data [64] ; } ; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Methods - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//············································································· +// Methods +//············································································· public: void pad (void) { uint8_t paddedLength = len ; @@ -107,7 +107,7 @@ class CANFDMessage { } } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//············································································· public: bool isValid (void) const { if ((type == CAN_REMOTE) || (type == CAN_DATA)) { // Remote frame @@ -121,14 +121,14 @@ class CANFDMessage { } } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//············································································· } ; -//------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- typedef void (*ACANFDCallBackRoutine) (const CANFDMessage & inMessage) ; -//------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- #endif diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_CANMessage.h b/Software/src/lib/pierremolinaro-ACAN2517FD/CANMessage.h similarity index 84% rename from Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_CANMessage.h rename to Software/src/lib/pierremolinaro-ACAN2517FD/CANMessage.h index 9e175a3a..6c687d7e 100644 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD_CANMessage.h +++ b/Software/src/lib/pierremolinaro-ACAN2517FD/CANMessage.h @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- // Generic CAN Message // by Pierre Molinaro // @@ -8,16 +8,16 @@ // https://github.com/pierremolinaro/acan2517 // https://github.com/pierremolinaro/acan2517FD // -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #ifndef GENERIC_CAN_MESSAGE_DEFINED #define GENERIC_CAN_MESSAGE_DEFINED -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #include -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- class CANMessage { public : uint32_t id = 0 ; // Frame identifier @@ -38,12 +38,12 @@ class CANMessage { } ; } ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- typedef enum {kStandard, kExtended} tFrameFormat ; typedef enum {kData, kRemote} tFrameKind ; typedef void (*ACANCallBackRoutine) (const CANMessage & inMessage) ; -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------------------------------------------------------- #endif diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/README.md b/Software/src/lib/pierremolinaro-ACAN2517FD/README.md old mode 100755 new mode 100644 diff --git a/Software/src/lib/pierremolinaro-ACAN2517FD/library.properties b/Software/src/lib/pierremolinaro-ACAN2517FD/library.properties deleted file mode 100644 index b249255d..00000000 --- a/Software/src/lib/pierremolinaro-ACAN2517FD/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=ACAN2517FD -version=2.1.16 -author=Pierre Molinaro -maintainer=Pierre Molinaro -sentence=Driver for MCP2517FD and MCP2518FD CAN Controller (CAN FD mode) -paragraph=This library is an Arduino CAN network driver for the MCP2517FD, the MCP2518FD and the MCP251863 CAN Controller, in CAN FD mode. Compatible with ACAN, ACAN2515, ACAN2517 libraries, with ACAN_T4 library from version 2.1.0. Default configuration sends and receives any frame – no default filter to provide. Reception filters (up to 32) can be easily defined. Compatible with ESP32 from version 1.1.0. -category=Communication -url=https://github.com/pierremolinaro/acan2517FD -architectures=* From 224c33ec1d6ed3233adef0c06df6acbc8272b5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 19:42:26 +0300 Subject: [PATCH 022/150] Make more settings configurable --- Software/USER_SETTINGS.h | 4 -- Software/src/communication/nvm/comm_nvm.cpp | 8 +++- .../precharge_control/precharge_control.cpp | 36 ++++++---------- .../precharge_control/precharge_control.h | 5 +++ Software/src/devboard/mqtt/mqtt.cpp | 25 ++++++----- Software/src/devboard/mqtt/mqtt.h | 7 +-- .../src/devboard/webserver/settings_html.cpp | 43 ++++++++++++++++++- Software/src/devboard/webserver/webserver.cpp | 12 ++++-- 8 files changed, 92 insertions(+), 48 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 30e2a80a..e2873c17 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -7,10 +7,6 @@ /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement -/* Automatic Precharge settings (Optional) If you have a battery that expects an external voltage applied before opening contactors (within the battery), configure this section */ -//#define PRECHARGE_CONTROL //Enable this line to control a modified HIA4V1 via PWM on the HIA4V1_PIN (see Wiki and HAL for pin definition) -//#define INVERTER_DISCONNECT_CONTACTOR_IS_NORMALLY_OPEN //Enable this line if you use a normally open contactor instead of normally closed - /* Connectivity options */ //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 8869fc15..2cb7a89e 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -8,6 +8,7 @@ #include "../../devboard/wifi/wifi.h" #include "../../inverter/INVERTERS.h" #include "../contactorcontrol/comm_contactorcontrol.h" +#include "../precharge_control/precharge_control.h" // Parameters Preferences settings; // Store user settings @@ -142,6 +143,10 @@ void init_stored_settings() { remote_bms_reset = settings.getBool("REMBMSRESET", false); use_canfd_as_can = settings.getBool("CANFDASCAN", false); + precharge_control_enabled = settings.getBool("EXTPRECHARGE", false); + precharge_inverter_normally_open_contactor = settings.getBool("NOINVDISC", false); + precharge_max_precharge_time_before_fault = settings.getUInt("MAXPRETIME", 15000); + datalayer.system.info.performance_measurement_active = settings.getBool("PERFPROFILE", false); datalayer.system.info.CAN_usb_logging_active = settings.getBool("CANLOGUSB", false); datalayer.system.info.usb_logging_active = settings.getBool("USBENABLED", false); @@ -154,8 +159,9 @@ void init_stored_settings() { wifiap_enabled = settings.getBool("WIFIAPENABLED", true); passwordAP = settings.getString("APPASSWORD", "123456789").c_str(); mqtt_enabled = settings.getBool("MQTTENABLED", false); + mqtt_timeout_ms = settings.getUInt("MQTTTIMEOUT", 2000); ha_autodiscovery_enabled = settings.getBool("HADISC", false); - + mqtt_transmit_all_cellvoltages = settings.getBool("MQTTCELLV", false); custom_hostname = settings.getString("HOSTNAME").c_str(); mqtt_server = settings.getString("MQTTSERVER").c_str(); diff --git a/Software/src/communication/precharge_control/precharge_control.cpp b/Software/src/communication/precharge_control/precharge_control.cpp index be7a01ce..31acf342 100644 --- a/Software/src/communication/precharge_control/precharge_control.cpp +++ b/Software/src/communication/precharge_control/precharge_control.cpp @@ -4,29 +4,21 @@ #include "../../datalayer/datalayer_extended.h" #include "../../devboard/hal/hal.h" -#ifdef PRECHARGE_CONTROL -const bool precharge_control_enabled_default = true; -#else -const bool precharge_control_enabled_default = false; -#endif +// Parameters adjustable by user in Settings page +bool precharge_control_enabled = false; +bool precharge_inverter_normally_open_contactor = false; +uint16_t precharge_max_precharge_time_before_fault = 15000; -bool precharge_control_enabled = precharge_control_enabled_default; - -// Parameters -#define MAX_PRECHARGE_TIME_MS 15000 // Maximum time precharge may be enabled +// Hardcoded parameters #define Precharge_default_PWM_Freq 11000 #define Precharge_min_PWM_Freq 5000 #define Precharge_max_PWM_Freq 34000 #define Precharge_PWM_Res 8 #define PWM_Freq 20000 // 20 kHz frequency, beyond audible range #define PWM_Precharge_Channel 0 -#ifndef INVERTER_DISCONNECT_CONTACTOR_IS_NORMALLY_OPEN -#define ON 0 //Normally closed contactors use inverted logic -#define OFF 1 //Normally closed contactors use inverted logic -#else -#define ON 1 -#define OFF 0 -#endif +#define CONTACTOR_ON (precharge_inverter_normally_open_contactor ? 1 : 0) +#define CONTACTOR_OFF (precharge_inverter_normally_open_contactor ? 0 : 1) + static unsigned long prechargeStartTime = 0; static uint32_t freq = Precharge_default_PWM_Freq; static uint16_t delta_freq = 1; @@ -66,7 +58,7 @@ void handle_precharge_control(unsigned long currentMillis) { if (datalayer.system.status.precharge_status == AUTO_PRECHARGE_FAILURE) { pinMode(hia4v1_pin, OUTPUT); digitalWrite(hia4v1_pin, LOW); - digitalWrite(inverter_disconnect_contactor_pin, ON); + digitalWrite(inverter_disconnect_contactor_pin, CONTACTOR_ON); return; // Exit immediately - no further processing allowed. Reboot required to recover } @@ -86,7 +78,7 @@ void handle_precharge_control(unsigned long currentMillis) { prechargeStartTime = currentMillis; datalayer.system.status.precharge_status = AUTO_PRECHARGE_PRECHARGING; logging.printf("Precharge: Starting sequence\n"); - digitalWrite(inverter_disconnect_contactor_pin, OFF); + digitalWrite(inverter_disconnect_contactor_pin, CONTACTOR_OFF); break; case AUTO_PRECHARGE_PRECHARGING: @@ -120,14 +112,14 @@ void handle_precharge_control(unsigned long currentMillis) { datalayer.battery.status.bms_status != ACTIVE || datalayer.system.settings.equipment_stop_active) { pinMode(hia4v1_pin, OUTPUT); digitalWrite(hia4v1_pin, LOW); - digitalWrite(inverter_disconnect_contactor_pin, ON); + digitalWrite(inverter_disconnect_contactor_pin, CONTACTOR_ON); datalayer.system.status.precharge_status = AUTO_PRECHARGE_IDLE; logging.printf("Precharge: Disabling Precharge bms not standby/active or equipment stop\n"); - } else if (currentMillis - prechargeStartTime >= MAX_PRECHARGE_TIME_MS || + } else if (currentMillis - prechargeStartTime >= precharge_max_precharge_time_before_fault || datalayer.battery.status.real_bms_status == BMS_FAULT) { pinMode(hia4v1_pin, OUTPUT); digitalWrite(hia4v1_pin, LOW); - digitalWrite(inverter_disconnect_contactor_pin, ON); + digitalWrite(inverter_disconnect_contactor_pin, CONTACTOR_ON); datalayer.system.status.precharge_status = AUTO_PRECHARGE_FAILURE; logging.printf("Precharge: CRITICAL FAILURE (timeout/BMS fault) -> REQUIRES REBOOT\n"); set_event(EVENT_AUTOMATIC_PRECHARGE_FAILURE, 0); @@ -137,7 +129,7 @@ void handle_precharge_control(unsigned long currentMillis) { } else if (datalayer.system.status.battery_allows_contactor_closing) { pinMode(hia4v1_pin, OUTPUT); digitalWrite(hia4v1_pin, LOW); - digitalWrite(inverter_disconnect_contactor_pin, ON); + digitalWrite(inverter_disconnect_contactor_pin, CONTACTOR_ON); datalayer.system.status.precharge_status = AUTO_PRECHARGE_COMPLETED; logging.printf("Precharge: Disabled (contacts closed) -> COMPLETED\n"); } diff --git a/Software/src/communication/precharge_control/precharge_control.h b/Software/src/communication/precharge_control/precharge_control.h index 0262ebd7..f02e082e 100644 --- a/Software/src/communication/precharge_control/precharge_control.h +++ b/Software/src/communication/precharge_control/precharge_control.h @@ -3,6 +3,11 @@ #include "../../devboard/utils/events.h" +// TODO: Ensure valid values at run-time +// User can update all these values via Settings page +extern bool precharge_control_enabled; +extern bool precharge_inverter_normally_open_contactor; +extern uint16_t precharge_max_precharge_time_before_fault; /** * @brief Contactor initialization * diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index 525df501..c5a5ee2f 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -16,6 +16,8 @@ bool mqtt_enabled = false; bool ha_autodiscovery_enabled = false; +bool mqtt_transmit_all_cellvoltages = false; +uint16_t mqtt_timeout_ms = 2000; const int mqtt_port_default = 0; const char* mqtt_server_default = ""; @@ -29,10 +31,7 @@ bool mqtt_manual_topic_object_name = // This naming convention was in place until version 7.5.0. Users should check the version from which they are updating, as this change // may break compatibility with previous versions of MQTT naming -#define MQTT_PUBLISH_CELL_VOLTAGES // Enable this line to publish cell voltages to MQTT -#define MQTT_QOS 0 // MQTT Quality of Service (0, 1, or 2) -#define MQTT_TIMEOUT 2000 // MQTT timeout in milliseconds - //TODO: Should all these defines be a configurable option? +#define MQTT_QOS 0 // MQTT Quality of Service (0, 1, or 2) //TODO: Should this be configurable? esp_mqtt_client_config_t mqtt_cfg; esp_mqtt_client_handle_t client; @@ -67,17 +66,17 @@ static void publish_values(void) { return; } -#ifdef MQTT_PUBLISH_CELL_VOLTAGES - if (publish_cell_voltages() == false) { - return; + if (mqtt_transmit_all_cellvoltages) { + if (publish_cell_voltages() == false) { + return; + } } -#endif -#ifdef MQTT_PUBLISH_CELL_VOLTAGES - if (publish_cell_balancing() == false) { - return; + if (mqtt_transmit_all_cellvoltages) { + if (publish_cell_balancing() == false) { + return; + } } -#endif } static bool ha_common_info_published = false; @@ -655,7 +654,7 @@ bool init_mqtt(void) { mqtt_cfg.session.last_will.retain = true; mqtt_cfg.session.last_will.msg = "offline"; mqtt_cfg.session.last_will.msg_len = strlen(mqtt_cfg.session.last_will.msg); - mqtt_cfg.network.timeout_ms = MQTT_TIMEOUT; + mqtt_cfg.network.timeout_ms = mqtt_timeout_ms; client = esp_mqtt_client_init(&mqtt_cfg); if (client == nullptr) { diff --git a/Software/src/devboard/mqtt/mqtt.h b/Software/src/devboard/mqtt/mqtt.h index 46261d5b..4189ca91 100644 --- a/Software/src/devboard/mqtt/mqtt.h +++ b/Software/src/devboard/mqtt/mqtt.h @@ -42,6 +42,10 @@ extern const char* version_number; // The current software version, used for mqtt +extern bool mqtt_enabled; +extern bool mqtt_transmit_all_cellvoltages; +extern uint16_t mqtt_timeout_ms; +extern bool ha_autodiscovery_enabled; extern std::string mqtt_server; extern std::string mqtt_user; extern std::string mqtt_password; @@ -57,7 +61,4 @@ bool init_mqtt(void); void mqtt_loop(void); bool mqtt_publish(const char* topic, const char* mqtt_msg, bool retain); -extern bool mqtt_enabled; -extern bool ha_autodiscovery_enabled; - #endif diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 0517962b..74825e3d 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -270,6 +270,18 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return settings.getBool("REMBMSRESET") ? "checked" : ""; } + if (var == "EXTPRECHARGE") { + return settings.getBool("EXTPRECHARGE") ? "checked" : ""; + } + + if (var == "MAXPRETIME") { + return String(settings.getUInt("MAXPRETIME", 15000)); + } + + if (var == "NOINVDISC") { + return settings.getBool("NOINVDISC") ? "checked" : ""; + } + if (var == "CANFDASCAN") { return settings.getBool("CANFDASCAN") ? "checked" : ""; } @@ -330,6 +342,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return settings.getString("MQTTTOPIC"); } + if (var == "MQTTTIMEOUT") { + return String(settings.getUInt("MQTTTIMEOUT", 2000)); + } + if (var == "MQTTOBJIDPREFIX") { return settings.getString("MQTTOBJIDPREFIX"); } @@ -338,6 +354,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return settings.getString("MQTTDEVICENAME"); } + if (var == "MQTTCELLV") { + return settings.getBool("MQTTCELLV") ? "checked" : ""; + } + if (var == "HADEVICEID") { return settings.getString("HADEVICEID"); } @@ -807,6 +827,11 @@ const char* getCANInterfaceName(CAN_Interface interface) { display: contents; } + form .if-extprecharge { display: none; } + form[data-extprecharge="true"] .if-extprecharge { + display: contents; + } + form .if-sofar { display: none; } form[data-inverter="17"] .if-sofar { display: contents; @@ -1008,6 +1033,19 @@ const char* getCANInterfaceName(CAN_Interface interface) { + + + +
+ + + + + +
+ +
+ @@ -1047,7 +1085,8 @@ const char* getCANInterfaceName(CAN_Interface interface) { - + + @@ -1057,7 +1096,7 @@ const char* getCANInterfaceName(CAN_Interface interface) { - +

diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index fe71aa61..f1abe00c 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -396,9 +396,10 @@ void init_webserver() { }; const char* boolSettingNames[] = { - "DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED", "REMBMSRESET", - "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", "CANLOGSD", "WIFIAPENABLED", "MQTTENABLED", - "HADISC", "MQTTTOPICS", "INVICNT", "GTWRHD", "DIGITALHVIL", "PERFPROFILE", "INTERLOCKREQ", + "DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED", + "REMBMSRESET", "EXTPRECHARGE", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", + "CANLOGSD", "WIFIAPENABLED", "MQTTENABLED", "NOINVDISC", "HADISC", "MQTTTOPICS", + "MQTTCELLV", "INVICNT", "GTWRHD", "DIGITALHVIL", "PERFPROFILE", "INTERLOCKREQ", }; // Handles the form POST from UI to save settings of the common image @@ -459,6 +460,9 @@ void init_webserver() { } else if (p->name() == "SHUNTCOMM") { auto type = static_cast(atoi(p->value().c_str())); settings.saveUInt("SHUNTCOMM", (int)type); + } else if (p->name() == "MAXPRETIME") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("MAXPRETIME", type); } else if (p->name() == "HOSTNAME") { settings.saveString("HOSTNAME", p->value().c_str()); } else if (p->name() == "MQTTSERVER") { @@ -472,6 +476,8 @@ void init_webserver() { settings.saveString("MQTTPASSWORD", p->value().c_str()); } else if (p->name() == "MQTTTOPIC") { settings.saveString("MQTTTOPIC", p->value().c_str()); + } else if (p->name() == "MQTTTIMEOUT") { + settings.saveString("MQTTTIMEOUT", p->value().c_str()); } else if (p->name() == "MQTTOBJIDPREFIX") { settings.saveString("MQTTOBJIDPREFIX", p->value().c_str()); } else if (p->name() == "MQTTDEVICENAME") { From 58af5b658bb0e06d470562db3de69e1617dd8a86 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:42:38 +0000 Subject: [PATCH 023/150] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- Software/Software.cpp | 8 ++++---- Software/USER_SETTINGS.cpp | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index dde1c9f3..73cdea2c 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -52,10 +52,10 @@ TaskHandle_t mqtt_loop_task; Logging logging; -std::string mqtt_user; //TODO, move? -std::string mqtt_password; //TODO, move? -std::string http_username; //TODO, move? -std::string http_password; //TODO, move? +std::string mqtt_user; //TODO, move? +std::string mqtt_password; //TODO, move? +std::string http_username; //TODO, move? +std::string http_password; //TODO, move? static std::list transmitters; void register_transmitter(Transmitter* transmitter) { diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index d79a90ae..8e7b46f4 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -20,7 +20,6 @@ volatile CAN_Configuration can_config = { .shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your shunt connected to? }; - // Set your Static IP address. Only used incase WIFICONFIG is set in USER_SETTINGS.h IPAddress local_IP(192, 168, 10, 150); IPAddress gateway(192, 168, 10, 1); @@ -32,10 +31,8 @@ std::string passwordAP; const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection - // MQTT - const char* mqtt_topic_name = "BE"; // Custom MQTT topic name. Previously, the name was automatically set to "battery-emulator_esp32-XXXXXX" const char* mqtt_object_id_prefix = From 21eda56c9e4ae8c7c9c4ea262a985ba701e2111f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 20:12:42 +0300 Subject: [PATCH 024/150] Make Wifi channel configurable --- Software/USER_SETTINGS.cpp | 5 ----- Software/USER_SETTINGS.h | 1 - Software/src/communication/nvm/comm_nvm.cpp | 1 + Software/src/devboard/webserver/settings_html.cpp | 13 +++++++++---- Software/src/devboard/webserver/webserver.cpp | 3 +++ Software/src/devboard/wifi/wifi.cpp | 5 ++++- Software/src/devboard/wifi/wifi.h | 2 +- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index d79a90ae..ccfa3e83 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -20,7 +20,6 @@ volatile CAN_Configuration can_config = { .shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your shunt connected to? }; - // Set your Static IP address. Only used incase WIFICONFIG is set in USER_SETTINGS.h IPAddress local_IP(192, 168, 10, 150); IPAddress gateway(192, 168, 10, 1); @@ -30,12 +29,8 @@ std::string ssid; std::string password; std::string passwordAP; -const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection - - // MQTT - const char* mqtt_topic_name = "BE"; // Custom MQTT topic name. Previously, the name was automatically set to "battery-emulator_esp32-XXXXXX" const char* mqtt_object_id_prefix = diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index e2873c17..9f89c7bb 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -21,7 +21,6 @@ typedef struct { } CAN_Configuration; extern volatile CAN_Configuration can_config; extern volatile uint8_t AccessPointEnabled; -extern const uint8_t wifi_channel; extern volatile float CHARGER_SET_HV; extern volatile float CHARGER_MAX_HV; extern volatile float CHARGER_MIN_HV; diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 2cb7a89e..2351728b 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -157,6 +157,7 @@ void init_stored_settings() { // WIFI AP is enabled by default unless disabled in the settings wifiap_enabled = settings.getBool("WIFIAPENABLED", true); + wifi_channel = settings.getUInt("WIFICHANNEL", 2000); passwordAP = settings.getString("APPASSWORD", "123456789").c_str(); mqtt_enabled = settings.getBool("MQTTENABLED", false); mqtt_timeout_ms = settings.getUInt("MQTTTIMEOUT", 2000); diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 74825e3d..521805c5 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -290,6 +290,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return settings.getBool("WIFIAPENABLED", wifiap_enabled) ? "checked" : ""; } + if (var == "WIFICHANNEL") { + return String(settings.getUInt("WIFICHANNEL", 0)); + } + if (var == "PERFPROFILE") { return settings.getBool("PERFPROFILE") ? "checked" : ""; } @@ -867,7 +871,7 @@ const char* getCANInterfaceName(CAN_Interface interface) {

SSID: %SSID%

Password: ########

- +
@@ -1042,16 +1046,17 @@ const char* getCANInterfaceName(CAN_Interface interface) { -
-
- + + + + diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index f1abe00c..8e3c3df4 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -463,6 +463,9 @@ void init_webserver() { } else if (p->name() == "MAXPRETIME") { auto type = atoi(p->value().c_str()); settings.saveUInt("MAXPRETIME", type); + } else if (p->name() == "WIFICHANNEL") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("WIFICHANNEL", type); } else if (p->name() == "HOSTNAME") { settings.saveString("HOSTNAME", p->value().c_str()); } else if (p->name() == "MQTTSERVER") { diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 869d863f..50ac3d2e 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -7,6 +7,7 @@ bool wifi_enabled = true; bool wifiap_enabled = true; bool mdns_enabled = true; //If true, allows battery monitor te be found by .local address +uint16_t wifi_channel = 0; std::string custom_hostname; //If not set, the default naming format 'esp32-XXXXXX' will be used std::string ssidAP; @@ -150,7 +151,9 @@ void connectToWiFi() { if (WiFi.status() != WL_CONNECTED) { lastReconnectAttempt = millis(); // Reset the reconnect attempt timer logging.println("Connecting to Wi-Fi..."); - + if (wifi_channel > 14) { + wifi_channel = 0; + } //prevent users going out of bounds DEBUG_PRINTF("Connecting to Wi-Fi SSID: %s, password: %s, Channel: %d\n", ssid.c_str(), password.c_str(), wifi_channel); WiFi.begin(ssid.c_str(), password.c_str(), wifi_channel); diff --git a/Software/src/devboard/wifi/wifi.h b/Software/src/devboard/wifi/wifi.h index 6e0b7b50..bf0ecb01 100644 --- a/Software/src/devboard/wifi/wifi.h +++ b/Software/src/devboard/wifi/wifi.h @@ -6,7 +6,7 @@ extern std::string ssid; extern std::string password; -extern const uint8_t wifi_channel; +extern uint16_t wifi_channel; extern std::string ssidAP; extern std::string passwordAP; extern std::string custom_hostname; From f03324585b596b08a497d5a0cf12f8cec3ba3836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 20:42:48 +0300 Subject: [PATCH 025/150] Move more USER_SETTINGS out --- Software/USER_SETTINGS.cpp | 31 ------------------- Software/USER_SETTINGS.h | 27 ---------------- Software/src/communication/can/comm_can.cpp | 6 ++++ Software/src/communication/can/comm_can.h | 9 ++++++ .../comm_equipmentstopbutton.cpp | 1 + Software/src/communication/nvm/comm_nvm.cpp | 1 + Software/src/devboard/mqtt/mqtt.cpp | 8 +++++ .../src/devboard/webserver/settings_html.cpp | 1 + Software/src/devboard/webserver/webserver.cpp | 1 + Software/src/devboard/wifi/wifi.cpp | 3 ++ 10 files changed, 30 insertions(+), 58 deletions(-) diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 3581e093..46031b96 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -2,42 +2,11 @@ #include #include "src/devboard/hal/hal.h" -/* This file contains all the battery settings and limits */ -/* They can be defined here, or later on in the WebUI */ -/* Most important is to select which CAN interface each component is connected to */ -/* -CAN_NATIVE = Native CAN port on the LilyGo & Stark hardware -CANFD_NATIVE = Native CANFD port on the Stark CMR hardware -CAN_ADDON_MCP2515 = Add-on CAN MCP2515 connected to GPIO pins -CANFD_ADDON_MCP2518 = Add-on CAN-FD MCP2518 connected to GPIO pins -*/ - -volatile CAN_Configuration can_config = { - .battery = CAN_NATIVE, // Which CAN is your battery connected to? - .inverter = CAN_NATIVE, // Which CAN is your inverter connected to? (No need to configure incase you use RS485) - .battery_double = CAN_ADDON_MCP2515, // (OPTIONAL) Which CAN is your second battery connected to? - .charger = CAN_NATIVE, // (OPTIONAL) Which CAN is your charger connected to? - .shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your shunt connected to? -}; - // Set your Static IP address. Only used incase WIFICONFIG is set in USER_SETTINGS.h IPAddress local_IP(192, 168, 10, 150); IPAddress gateway(192, 168, 10, 1); IPAddress subnet(255, 255, 255, 0); -std::string ssid; -std::string password; -std::string passwordAP; - -const char* mqtt_topic_name = - "BE"; // Custom MQTT topic name. Previously, the name was automatically set to "battery-emulator_esp32-XXXXXX" -const char* mqtt_object_id_prefix = - "be_"; // Custom prefix for MQTT object ID. Previously, the prefix was automatically set to "esp32-XXXXXX_" -const char* mqtt_device_name = - "Battery Emulator"; // Custom device name in Home Assistant. Previously, the name was automatically set to "BatteryEmulator_esp32-XXXXXX" -const char* ha_device_id = - "battery-emulator"; // Custom device ID in Home Assistant. Previously, the ID was always "battery-emulator" - /* Charger settings (Optional, when using generator charging) */ volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 9f89c7bb..db208f06 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -10,17 +10,6 @@ /* Connectivity options */ //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings -/* Do not change any code below this line */ -/* Only change battery specific settings above and in "USER_SETTINGS.cpp" */ -typedef struct { - CAN_Interface battery; - CAN_Interface inverter; - CAN_Interface battery_double; - CAN_Interface charger; - CAN_Interface shunt; -} CAN_Configuration; -extern volatile CAN_Configuration can_config; -extern volatile uint8_t AccessPointEnabled; extern volatile float CHARGER_SET_HV; extern volatile float CHARGER_MAX_HV; extern volatile float CHARGER_MIN_HV; @@ -28,26 +17,10 @@ extern volatile float CHARGER_MAX_POWER; extern volatile float CHARGER_MAX_A; extern volatile float CHARGER_END_A; -#include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h" - -// Equipment stop button behavior. Use NC button for safety reasons. -//LATCHING_SWITCH - Normally closed (NC), latching switch. When pressed it activates e-stop -//MOMENTARY_SWITCH - Short press to activate e-stop, long 15s press to deactivate. E-stop is persistent between reboots - -#ifdef EQUIPMENT_STOP_BUTTON -const STOP_BUTTON_BEHAVIOR stop_button_default_behavior = STOP_BUTTON_BEHAVIOR::MOMENTARY_SWITCH; -#else -const STOP_BUTTON_BEHAVIOR stop_button_default_behavior = STOP_BUTTON_BEHAVIOR::NOT_CONNECTED; -#endif - #ifdef WIFICONFIG extern IPAddress local_IP; extern IPAddress gateway; extern IPAddress subnet; #endif -#if defined(MEB_BATTERY) -#define PRECHARGE_CONTROL -#endif - #endif // __USER_SETTINGS_H__ diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index eadb75d8..4dc2e47d 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -12,6 +12,12 @@ #include "src/devboard/sdcard/sdcard.h" #include "src/devboard/utils/logging.h" +volatile CAN_Configuration can_config = {.battery = CAN_NATIVE, + .inverter = CAN_NATIVE, + .battery_double = CAN_ADDON_MCP2515, + .charger = CAN_NATIVE, + .shunt = CAN_NATIVE}; + struct CanReceiverRegistration { CanReceiver* receiver; CAN_Speed speed; diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h index 91e58017..b4624928 100644 --- a/Software/src/communication/can/comm_can.h +++ b/Software/src/communication/can/comm_can.h @@ -15,6 +15,15 @@ void transmit_can_frame_to_interface(const CAN_frame* tx_frame, int interface); class CanReceiver; +typedef struct { + CAN_Interface battery; + CAN_Interface inverter; + CAN_Interface battery_double; + CAN_Interface charger; + CAN_Interface shunt; +} CAN_Configuration; +extern volatile CAN_Configuration can_config; + enum class CAN_Speed { CAN_SPEED_100KBPS = 100, CAN_SPEED_125KBPS = 125, diff --git a/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp index de03820e..ca056b93 100644 --- a/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp +++ b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp @@ -4,6 +4,7 @@ #include "../../devboard/utils/debounce_button.h" #include "USER_SETTINGS.h" +const STOP_BUTTON_BEHAVIOR stop_button_default_behavior = STOP_BUTTON_BEHAVIOR::NOT_CONNECTED; STOP_BUTTON_BEHAVIOR equipment_stop_behavior = stop_button_default_behavior; // Parameters diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 2351728b..3ba5b478 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -8,6 +8,7 @@ #include "../../devboard/wifi/wifi.h" #include "../../inverter/INVERTERS.h" #include "../contactorcontrol/comm_contactorcontrol.h" +#include "../equipmentstopbutton/comm_equipmentstopbutton.h" #include "../precharge_control/precharge_control.h" // Parameters diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index c5a5ee2f..cf505a34 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -30,6 +30,14 @@ bool mqtt_manual_topic_object_name = // If this is not true, the previous default naming format 'battery-emulator_esp32-XXXXXX' (based on hardware ID) will be used. // This naming convention was in place until version 7.5.0. Users should check the version from which they are updating, as this change // may break compatibility with previous versions of MQTT naming +const char* mqtt_topic_name = + "BE"; // Custom MQTT topic name. Previously, the name was automatically set to "battery-emulator_esp32-XXXXXX" +const char* mqtt_object_id_prefix = + "be_"; // Custom prefix for MQTT object ID. Previously, the prefix was automatically set to "esp32-XXXXXX_" +const char* mqtt_device_name = + "Battery Emulator"; // Custom device name in Home Assistant. Previously, the name was automatically set to "BatteryEmulator_esp32-XXXXXX" +const char* ha_device_id = + "battery-emulator"; // Custom device ID in Home Assistant. Previously, the ID was always "battery-emulator" #define MQTT_QOS 0 // MQTT Quality of Service (0, 1, or 2) //TODO: Should this be configurable? diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 521805c5..b2892d89 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -1,6 +1,7 @@ #include "settings_html.h" #include #include "../../../src/communication/contactorcontrol/comm_contactorcontrol.h" +#include "../../../src/communication/equipmentstopbutton/comm_equipmentstopbutton.h" #include "../../charger/CHARGERS.h" #include "../../communication/can/comm_can.h" #include "../../communication/nvm/comm_nvm.h" diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 8e3c3df4..2b5f0b9d 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -7,6 +7,7 @@ #include "../../charger/CHARGERS.h" #include "../../communication/can/comm_can.h" #include "../../communication/contactorcontrol/comm_contactorcontrol.h" +#include "../../communication/equipmentstopbutton/comm_equipmentstopbutton.h" #include "../../communication/nvm/comm_nvm.h" #include "../../datalayer/datalayer.h" #include "../../datalayer/datalayer_extended.h" diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 50ac3d2e..1cf51b83 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -10,7 +10,10 @@ bool mdns_enabled = true; //If true, allows battery monitor te be found by .loc uint16_t wifi_channel = 0; std::string custom_hostname; //If not set, the default naming format 'esp32-XXXXXX' will be used +std::string ssid; +std::string password; std::string ssidAP; +std::string passwordAP; // Configuration Parameters static const uint16_t WIFI_CHECK_INTERVAL = 2000; // 1 seconds normal check interval when last connected From bb21b5d8e17ae06f2d06a735b3f9fa82d3b48d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 20:51:53 +0300 Subject: [PATCH 026/150] Remove unused ifdefs --- Software/Software.cpp | 9 +++++---- Software/src/inverter/AFORE-CAN.h | 4 ---- Software/src/inverter/BYD-CAN.h | 4 ---- Software/src/inverter/BYD-MODBUS.h | 4 ---- Software/src/inverter/FERROAMP-CAN.h | 4 ---- Software/src/inverter/FOXESS-CAN.h | 4 ---- Software/src/inverter/GROWATT-HV-CAN.h | 4 ---- Software/src/inverter/GROWATT-LV-CAN.h | 4 ---- Software/src/inverter/GROWATT-WIT-CAN.h | 4 ---- Software/src/inverter/KOSTAL-RS485.h | 5 ----- Software/src/inverter/PYLON-CAN.h | 4 ---- Software/src/inverter/PYLON-LV-CAN.h | 4 ---- Software/src/inverter/SCHNEIDER-CAN.h | 4 ---- Software/src/inverter/SMA-BYD-H-CAN.h | 4 ---- Software/src/inverter/SMA-BYD-HVS-CAN.h | 4 ---- Software/src/inverter/SMA-LV-CAN.h | 4 ---- Software/src/inverter/SMA-TRIPOWER-CAN.h | 4 ---- Software/src/inverter/SOFAR-CAN.h | 4 ---- Software/src/inverter/SOL-ARK-LV-CAN.h | 4 ---- Software/src/inverter/SOLAX-CAN.h | 4 ---- Software/src/inverter/SOLXPOW-CAN.h | 4 ---- Software/src/inverter/SUNGROW-CAN.h | 4 ---- 22 files changed, 5 insertions(+), 89 deletions(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 73cdea2c..0702406e 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -30,7 +30,7 @@ #include "src/inverter/INVERTERS.h" #if !defined(HW_LILYGO) && !defined(HW_LILYGO2CAN) && !defined(HW_STARK) && !defined(HW_3LB) && !defined(HW_DEVKIT) -#error You must select a target hardware in the USER_SETTINGS.h file! +#error You must select a target hardware! #endif // The current software version, shown on webserver @@ -396,9 +396,10 @@ void core_loop(void*) { } led_exe(); handle_contactors(); // Take care of startup precharge/contactor closing -#ifdef PRECHARGE_CONTROL - handle_precharge_control(currentMillis); -#endif // PRECHARGE_CONTROL + if (precharge_control_enabled) { + handle_precharge_control(currentMillis); //Drive the hia4v1 via PWM + } + if (datalayer.system.info.performance_measurement_active) { END_TIME_MEASUREMENT_MAX(10ms, datalayer.system.status.time_10ms_us); } diff --git a/Software/src/inverter/AFORE-CAN.h b/Software/src/inverter/AFORE-CAN.h index f98a582a..96e59ec6 100644 --- a/Software/src/inverter/AFORE-CAN.h +++ b/Software/src/inverter/AFORE-CAN.h @@ -1,10 +1,6 @@ #ifndef AFORE_CAN_H #define AFORE_CAN_H -#ifdef AFORE_CAN -#define SELECTED_INVERTER_CLASS AforeCanInverter -#endif - #include "CanInverterProtocol.h" class AforeCanInverter : public CanInverterProtocol { diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index b61d0a5c..07fd1189 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -1,10 +1,6 @@ #ifndef BYD_CAN_H #define BYD_CAN_H -#ifdef BYD_CAN -#define SELECTED_INVERTER_CLASS BydCanInverter -#endif - #include "../../USER_SETTINGS.h" #include "../datalayer/datalayer.h" #include "CanInverterProtocol.h" diff --git a/Software/src/inverter/BYD-MODBUS.h b/Software/src/inverter/BYD-MODBUS.h index a51010c5..83da47db 100644 --- a/Software/src/inverter/BYD-MODBUS.h +++ b/Software/src/inverter/BYD-MODBUS.h @@ -1,10 +1,6 @@ #ifndef BYD_MODBUS_H #define BYD_MODBUS_H -#ifdef BYD_MODBUS -#define SELECTED_INVERTER_CLASS BydModbusInverter -#endif - #include "../devboard/utils/types.h" #include "ModbusInverterProtocol.h" diff --git a/Software/src/inverter/FERROAMP-CAN.h b/Software/src/inverter/FERROAMP-CAN.h index 00ec78bd..aa4f064f 100644 --- a/Software/src/inverter/FERROAMP-CAN.h +++ b/Software/src/inverter/FERROAMP-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef FERROAMP_CAN -#define SELECTED_INVERTER_CLASS FerroampCanInverter -#endif - class FerroampCanInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/FOXESS-CAN.h b/Software/src/inverter/FOXESS-CAN.h index 2bb82df4..cd756807 100644 --- a/Software/src/inverter/FOXESS-CAN.h +++ b/Software/src/inverter/FOXESS-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef FOXESS_CAN -#define SELECTED_INVERTER_CLASS FoxessCanInverter -#endif - class FoxessCanInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/GROWATT-HV-CAN.h b/Software/src/inverter/GROWATT-HV-CAN.h index cf9d1b9a..44b86745 100644 --- a/Software/src/inverter/GROWATT-HV-CAN.h +++ b/Software/src/inverter/GROWATT-HV-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef GROWATT_HV_CAN -#define SELECTED_INVERTER_CLASS GrowattHvInverter -#endif - class GrowattHvInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/GROWATT-LV-CAN.h b/Software/src/inverter/GROWATT-LV-CAN.h index ae6c71b2..a55a1ef9 100644 --- a/Software/src/inverter/GROWATT-LV-CAN.h +++ b/Software/src/inverter/GROWATT-LV-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef GROWATT_LV_CAN -#define SELECTED_INVERTER_CLASS GrowattLvInverter -#endif - class GrowattLvInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/GROWATT-WIT-CAN.h b/Software/src/inverter/GROWATT-WIT-CAN.h index d94f6c18..fceef3d5 100644 --- a/Software/src/inverter/GROWATT-WIT-CAN.h +++ b/Software/src/inverter/GROWATT-WIT-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef GROWATT_WIT_CAN -#define SELECTED_INVERTER_CLASS GrowattWitInverter -#endif - class GrowattWitInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/KOSTAL-RS485.h b/Software/src/inverter/KOSTAL-RS485.h index 0768461f..d67b7438 100644 --- a/Software/src/inverter/KOSTAL-RS485.h +++ b/Software/src/inverter/KOSTAL-RS485.h @@ -3,11 +3,6 @@ #include #include "Rs485InverterProtocol.h" -#ifdef BYD_KOSTAL_RS485 -#define RS485_INVERTER_SELECTED -#define SELECTED_INVERTER_CLASS KostalInverterProtocol -#endif - class KostalInverterProtocol : public Rs485InverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/PYLON-CAN.h b/Software/src/inverter/PYLON-CAN.h index 33a8b1b6..7f03fa82 100644 --- a/Software/src/inverter/PYLON-CAN.h +++ b/Software/src/inverter/PYLON-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef PYLON_CAN -#define SELECTED_INVERTER_CLASS PylonInverter -#endif - class PylonInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/PYLON-LV-CAN.h b/Software/src/inverter/PYLON-LV-CAN.h index 24800621..af2e7342 100644 --- a/Software/src/inverter/PYLON-LV-CAN.h +++ b/Software/src/inverter/PYLON-LV-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef PYLON_LV_CAN -#define SELECTED_INVERTER_CLASS PylonLvInverter -#endif - class PylonLvInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SCHNEIDER-CAN.h b/Software/src/inverter/SCHNEIDER-CAN.h index e895e939..dbaa2441 100644 --- a/Software/src/inverter/SCHNEIDER-CAN.h +++ b/Software/src/inverter/SCHNEIDER-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef SCHNEIDER_CAN -#define SELECTED_INVERTER_CLASS SchneiderInverter -#endif - class SchneiderInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SMA-BYD-H-CAN.h b/Software/src/inverter/SMA-BYD-H-CAN.h index 9d9eda6b..88a5b845 100644 --- a/Software/src/inverter/SMA-BYD-H-CAN.h +++ b/Software/src/inverter/SMA-BYD-H-CAN.h @@ -4,10 +4,6 @@ #include "../devboard/hal/hal.h" #include "SmaInverterBase.h" -#ifdef SMA_BYD_H_CAN -#define SELECTED_INVERTER_CLASS SmaBydHInverter -#endif - class SmaBydHInverter : public SmaInverterBase { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SMA-BYD-HVS-CAN.h b/Software/src/inverter/SMA-BYD-HVS-CAN.h index c3d78b07..2f9dac67 100644 --- a/Software/src/inverter/SMA-BYD-HVS-CAN.h +++ b/Software/src/inverter/SMA-BYD-HVS-CAN.h @@ -4,10 +4,6 @@ #include "../devboard/hal/hal.h" #include "SmaInverterBase.h" -#ifdef SMA_BYD_HVS_CAN -#define SELECTED_INVERTER_CLASS SmaBydHvsInverter -#endif - class SmaBydHvsInverter : public SmaInverterBase { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SMA-LV-CAN.h b/Software/src/inverter/SMA-LV-CAN.h index 4ceef71b..e414f305 100644 --- a/Software/src/inverter/SMA-LV-CAN.h +++ b/Software/src/inverter/SMA-LV-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef SMA_LV_CAN -#define SELECTED_INVERTER_CLASS SmaLvInverter -#endif - class SmaLvInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index ace38bf9..7a18ea2a 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -4,10 +4,6 @@ #include "../devboard/hal/hal.h" #include "SmaInverterBase.h" -#ifdef SMA_TRIPOWER_CAN -#define SELECTED_INVERTER_CLASS SmaTripowerInverter -#endif - class SmaTripowerInverter : public SmaInverterBase { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SOFAR-CAN.h b/Software/src/inverter/SOFAR-CAN.h index 9a6a8642..59959688 100644 --- a/Software/src/inverter/SOFAR-CAN.h +++ b/Software/src/inverter/SOFAR-CAN.h @@ -2,10 +2,6 @@ #define SOFAR_CAN_H #include "CanInverterProtocol.h" -#ifdef SOFAR_CAN -#define SELECTED_INVERTER_CLASS SofarInverter -#endif - class SofarInverter : public CanInverterProtocol { public: bool setup() override; diff --git a/Software/src/inverter/SOL-ARK-LV-CAN.h b/Software/src/inverter/SOL-ARK-LV-CAN.h index 98b2cf9f..7e28f944 100644 --- a/Software/src/inverter/SOL-ARK-LV-CAN.h +++ b/Software/src/inverter/SOL-ARK-LV-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef SOL_ARK_LV_CAN -#define SELECTED_INVERTER_CLASS SolArkLvInverter -#endif - class SolArkLvInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SOLAX-CAN.h b/Software/src/inverter/SOLAX-CAN.h index 6a67e8bf..2599133c 100644 --- a/Software/src/inverter/SOLAX-CAN.h +++ b/Software/src/inverter/SOLAX-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef SOLAX_CAN -#define SELECTED_INVERTER_CLASS SolaxInverter -#endif - class SolaxInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SOLXPOW-CAN.h b/Software/src/inverter/SOLXPOW-CAN.h index f45970ee..8010c944 100644 --- a/Software/src/inverter/SOLXPOW-CAN.h +++ b/Software/src/inverter/SOLXPOW-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef SOLXPOW_CAN -#define SELECTED_INVERTER_CLASS SolxpowInverter -#endif - class SolxpowInverter : public CanInverterProtocol { public: const char* name() override { return Name; } diff --git a/Software/src/inverter/SUNGROW-CAN.h b/Software/src/inverter/SUNGROW-CAN.h index a28a2372..d4f5a7c9 100644 --- a/Software/src/inverter/SUNGROW-CAN.h +++ b/Software/src/inverter/SUNGROW-CAN.h @@ -3,10 +3,6 @@ #include "CanInverterProtocol.h" -#ifdef SUNGROW_CAN -#define SELECTED_INVERTER_CLASS SungrowInverter -#endif - class SungrowInverter : public CanInverterProtocol { public: const char* name() override { return Name; } From da560e162948400e452ba9266455aa6666316a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 21:06:18 +0300 Subject: [PATCH 027/150] Remove more USER_SETTINGS --- Software/Software.cpp | 1 + Software/USER_SETTINGS.cpp | 8 -------- Software/USER_SETTINGS.h | 7 ------- Software/src/battery/BATTERIES.h | 1 - Software/src/battery/CanBattery.h | 1 - Software/src/battery/MG-HS-PHEV-BATTERY.cpp | 2 -- Software/src/battery/Shunt.h | 1 - Software/src/charger/CHARGERS.cpp | 9 +++++++++ Software/src/charger/CHARGERS.h | 9 ++++++++- Software/src/charger/CHEVY-VOLT-CHARGER.cpp | 1 + Software/src/charger/NISSAN-LEAF-CHARGER.cpp | 1 + Software/src/communication/can/comm_can.cpp | 1 - .../contactorcontrol/comm_contactorcontrol.cpp | 2 +- .../equipmentstopbutton/comm_equipmentstopbutton.cpp | 1 - Software/src/datalayer/datalayer.h | 1 - Software/src/datalayer/datalayer_extended.h | 1 - 16 files changed, 21 insertions(+), 26 deletions(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 0702406e..da59ecbb 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -24,6 +24,7 @@ #include "src/devboard/utils/logging.h" #include "src/devboard/utils/time_meas.h" #include "src/devboard/utils/timer.h" +#include "src/devboard/utils/types.h" #include "src/devboard/utils/value_mapping.h" #include "src/devboard/webserver/webserver.h" #include "src/devboard/wifi/wifi.h" diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 46031b96..78cb6eee 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -6,11 +6,3 @@ IPAddress local_IP(192, 168, 10, 150); IPAddress gateway(192, 168, 10, 1); IPAddress subnet(255, 255, 255, 0); - -/* Charger settings (Optional, when using generator charging) */ -volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack -volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger -volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of charger -volatile float CHARGER_MAX_POWER = 3300; // Max power capable of charger, as a ceiling for validating config -volatile float CHARGER_MAX_A = 11.5; // Max current output (amps) of charger -volatile float CHARGER_END_A = 1.0; // Current at which charging is considered complete diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index db208f06..e8dd2c09 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -10,13 +10,6 @@ /* Connectivity options */ //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings -extern volatile float CHARGER_SET_HV; -extern volatile float CHARGER_MAX_HV; -extern volatile float CHARGER_MIN_HV; -extern volatile float CHARGER_MAX_POWER; -extern volatile float CHARGER_MAX_A; -extern volatile float CHARGER_END_A; - #ifdef WIFICONFIG extern IPAddress local_IP; extern IPAddress gateway; diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 22741186..cd4a8d56 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -1,6 +1,5 @@ #ifndef BATTERIES_H #define BATTERIES_H -#include "../../USER_SETTINGS.h" #include "Shunt.h" class Battery; diff --git a/Software/src/battery/CanBattery.h b/Software/src/battery/CanBattery.h index 53d720d7..cf08a7ae 100644 --- a/Software/src/battery/CanBattery.h +++ b/Software/src/battery/CanBattery.h @@ -3,7 +3,6 @@ #include "Battery.h" -#include "../../USER_SETTINGS.h" #include "../../src/communication/Transmitter.h" #include "../../src/communication/can/CanReceiver.h" #include "../../src/communication/can/comm_can.h" diff --git a/Software/src/battery/MG-HS-PHEV-BATTERY.cpp b/Software/src/battery/MG-HS-PHEV-BATTERY.cpp index daf7485f..4eede5ca 100644 --- a/Software/src/battery/MG-HS-PHEV-BATTERY.cpp +++ b/Software/src/battery/MG-HS-PHEV-BATTERY.cpp @@ -15,8 +15,6 @@ changing. OPTIONAL SETTINGS -Put these in your USER_SETTINGS.h: - // This will scale the SoC so the batteries top out at 4.2V/cell instead of 4.1V/cell. The car only seems to use up to 4.1V/cell in service. #define MG_HS_PHEV_USE_FULL_CAPACITY true diff --git a/Software/src/battery/Shunt.h b/Software/src/battery/Shunt.h index 7128e1e8..330988dd 100644 --- a/Software/src/battery/Shunt.h +++ b/Software/src/battery/Shunt.h @@ -1,7 +1,6 @@ #ifndef _SHUNT_H #define _SHUNT_H -#include "../../USER_SETTINGS.h" #include "../../src/communication/Transmitter.h" #include "../../src/communication/can/CanReceiver.h" #include "../../src/communication/can/comm_can.h" diff --git a/Software/src/charger/CHARGERS.cpp b/Software/src/charger/CHARGERS.cpp index 22e7d8c5..6e384fdb 100644 --- a/Software/src/charger/CHARGERS.cpp +++ b/Software/src/charger/CHARGERS.cpp @@ -6,6 +6,15 @@ CanCharger* charger = nullptr; ChargerType user_selected_charger_type = ChargerType::None; +/* Charger settings (Optional, when using generator charging) */ +//TODO: These should be user configurable via webserver +volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack +volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger +volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of charger +volatile float CHARGER_MAX_POWER = 3300; // Max power capable of charger, as a ceiling for validating config +volatile float CHARGER_MAX_A = 11.5; // Max current output (amps) of charger +volatile float CHARGER_END_A = 1.0; // Current at which charging is considered complete + std::vector supported_charger_types() { std::vector types; diff --git a/Software/src/charger/CHARGERS.h b/Software/src/charger/CHARGERS.h index 5581d578..89d46bff 100644 --- a/Software/src/charger/CHARGERS.h +++ b/Software/src/charger/CHARGERS.h @@ -1,6 +1,5 @@ #ifndef CHARGERS_H #define CHARGERS_H -#include "../../USER_SETTINGS.h" #include "CHEVY-VOLT-CHARGER.h" #include "NISSAN-LEAF-CHARGER.h" @@ -12,4 +11,12 @@ void setup_charger(); // The selected charger or null if no charger in use. extern CanCharger* charger; +//TODO: These should be user configurable via webserver +extern volatile float CHARGER_SET_HV; +extern volatile float CHARGER_MAX_HV; +extern volatile float CHARGER_MIN_HV; +extern volatile float CHARGER_MAX_POWER; +extern volatile float CHARGER_MAX_A; +extern volatile float CHARGER_END_A; + #endif diff --git a/Software/src/charger/CHEVY-VOLT-CHARGER.cpp b/Software/src/charger/CHEVY-VOLT-CHARGER.cpp index f981e869..c7317e80 100644 --- a/Software/src/charger/CHEVY-VOLT-CHARGER.cpp +++ b/Software/src/charger/CHEVY-VOLT-CHARGER.cpp @@ -3,6 +3,7 @@ #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" #include "../devboard/utils/logging.h" +#include "CHARGERS.h" /* This implements Chevy Volt / Ampera charger support (2011-2015 model years). * diff --git a/Software/src/charger/NISSAN-LEAF-CHARGER.cpp b/Software/src/charger/NISSAN-LEAF-CHARGER.cpp index fa502c07..92f7a780 100644 --- a/Software/src/charger/NISSAN-LEAF-CHARGER.cpp +++ b/Software/src/charger/NISSAN-LEAF-CHARGER.cpp @@ -1,6 +1,7 @@ #include "NISSAN-LEAF-CHARGER.h" #include "../communication/can/comm_can.h" #include "../datalayer/datalayer.h" +#include "CHARGERS.h" /* This implements Nissan LEAF PDM charger support. 2013-2024 Gen2/3 PDMs are supported * diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index 4dc2e47d..04b67572 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -5,7 +5,6 @@ #include "../../lib/pierremolinaro-acan-esp32/ACAN_ESP32.h" #include "../../lib/pierremolinaro-acan2515/ACAN2515.h" #include "CanReceiver.h" -#include "USER_SETTINGS.h" #include "comm_can.h" #include "src/datalayer/datalayer.h" #include "src/devboard/safety/safety.h" diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index a88ff9d0..cc3269e3 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -257,7 +257,7 @@ REMOTE_BMS_RESET - Allows the user to remotely powercycle the BMS by sending a c This makes the BMS recalculate all SOC% and avoid memory leaks During that time we also set the emulator state to paused in order to not try and send CAN messages towards the battery -Feature is only used if user has enabled PERIODIC_BMS_RESET in the USER_SETTINGS */ +Feature is only used if user has enabled PERIODIC_BMS_RESET */ void handle_BMSpower() { if (periodic_bms_reset || remote_bms_reset) { diff --git a/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp index ca056b93..ca0b88c1 100644 --- a/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp +++ b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp @@ -2,7 +2,6 @@ #include "../../devboard/hal/hal.h" #include "../../devboard/safety/safety.h" #include "../../devboard/utils/debounce_button.h" -#include "USER_SETTINGS.h" const STOP_BUTTON_BEHAVIOR stop_button_default_behavior = STOP_BUTTON_BEHAVIOR::NOT_CONNECTED; STOP_BUTTON_BEHAVIOR equipment_stop_behavior = stop_button_default_behavior; diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index fddc057c..e9ffc8af 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -1,7 +1,6 @@ #ifndef _DATALAYER_H_ #define _DATALAYER_H_ -#include "../../USER_SETTINGS.h" #include "../devboard/utils/types.h" #include "../system_settings.h" diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 091316da..b982e10f 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -2,7 +2,6 @@ #define _DATALAYER_EXTENDED_H_ #include -#include "../../USER_SETTINGS.h" struct DATALAYER_INFO_BOLTAMPERA { /** uint16_t */ From 53d40cbe51815b6adfa7947bec1bd7e652c442a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 21:18:15 +0300 Subject: [PATCH 028/150] Remove USER_SETTINGS for good --- .github/ISSUE_TEMPLATE.md | 16 +++++++--------- .github/ISSUE_TEMPLATE/bug_report.md | 10 +++++----- CONTRIBUTING.md | 2 +- Software/Software.cpp | 1 - Software/USER_SETTINGS.cpp | 8 -------- Software/USER_SETTINGS.h | 19 ------------------- Software/src/devboard/hal/hal.cpp | 2 -- Software/src/devboard/mqtt/mqtt.cpp | 1 - Software/src/devboard/utils/events.cpp | 1 - Software/src/devboard/utils/logging.cpp | 1 - Software/src/devboard/utils/logging.h | 2 +- Software/src/devboard/utils/time_meas.h | 1 - .../src/devboard/webserver/settings_html.h | 1 - Software/src/devboard/wifi/wifi.cpp | 7 ++++++- Software/src/inverter/BYD-CAN.h | 1 - Software/src/inverter/CanInverterProtocol.h | 4 +--- Software/src/inverter/INVERTERS.h | 2 -- test/CMakeLists.txt | 1 - 18 files changed, 21 insertions(+), 59 deletions(-) delete mode 100644 Software/USER_SETTINGS.cpp delete mode 100644 Software/USER_SETTINGS.h diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 71921d60..98f59888 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -16,13 +16,11 @@ ### Settings - + -- Software version: `` -- Battery used: `` -- Inverter communication protocol: `` -- Hardware used for Battery-Emulator: `HW_LILYGO, HW_STARK, Custom` -- CONTACTOR_CONTROL: `yes/no` -- CAN_ADDON: `yes/no` -- WEBSERVER: `yes/no` -- MQTT: `yes/no` +- Software version: X.Y.Z +- Battery used: [Nissan LEAF] +- Inverter communication protocol: [BYD Modbus] +- Hardware used for Battery-Emulator: [LilyGo T-CAN/Stark CMR/LilyGo T-2CAN] +- GPIO controlled contactors: [yes/no] +- MQTT: [yes/no] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 2d7bc4b9..a9b633a6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -20,10 +20,10 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Version and settings (please complete the following information):** -- Please attach your USER_SETTINGS files for easier debugging +- Please attach screenshot of configuration for easier debugging - Software version: X.Y.Z -- Battery used: [NISSAN_LEAF] -- Inverter communication protocol: [BYD_MODBUS] -- Hardware used for Battery-Emulator: [HW_LILYGO/HW_STARK/HW_DEVKIT] -- CONTACTOR_CONTROL: [yes/no] +- Battery used: [Nissan LEAF] +- Inverter communication protocol: [BYD Modbus] +- Hardware used for Battery-Emulator: [LilyGo T-CAN/Stark CMR/LilyGo T-2CAN] +- GPIO controlled contactors: [yes/no] - MQTT: [yes/no] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8136fb2e..b303cd06 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ You're in luck. There's various sources to contribute: - [Discord server](https://www.patreon.com/dala) ## Notes on embedded system -The Battery-Emulator is a real-time control system, which performs lots of time critical operations. Some operations, like contactor control, need to complete within 10 milliseconds periodically. The resources of the ESP32 microcontroller is limited, so keeping track of CPU and memory usage is essential. Keep this in mind when coding for the system! Performance profiling the system can be done by enabling the FUNCTION_TIME_MEASUREMENT option in the USER_SETTINGS.h file +The Battery-Emulator is a real-time control system, which performs lots of time critical operations. Some operations, like contactor control, need to complete within 10 milliseconds periodically. The resources of the ESP32 microcontroller is limited, so keeping track of CPU and memory usage is essential. Keep this in mind when coding for the system! Performance profiling the system can be done by enabling the "Enable performance profiling:" option in the webserver ## Code formatting The project enforces a specific code formatting in the workflows. To get your code formatted properly, it is easiest to use a pre-commit hook before pushing the code to a pull request. diff --git a/Software/Software.cpp b/Software/Software.cpp index da59ecbb..8ad87b7e 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -1,6 +1,5 @@ #include #include "HardwareSerial.h" -#include "USER_SETTINGS.h" #include "esp_system.h" #include "esp_task_wdt.h" #include "esp_timer.h" diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp deleted file mode 100644 index 78cb6eee..00000000 --- a/Software/USER_SETTINGS.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "USER_SETTINGS.h" -#include -#include "src/devboard/hal/hal.h" - -// Set your Static IP address. Only used incase WIFICONFIG is set in USER_SETTINGS.h -IPAddress local_IP(192, 168, 10, 150); -IPAddress gateway(192, 168, 10, 1); -IPAddress subnet(255, 255, 255, 0); diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h deleted file mode 100644 index e8dd2c09..00000000 --- a/Software/USER_SETTINGS.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __USER_SETTINGS_H__ -#define __USER_SETTINGS_H__ -#include -#include -#include "src/devboard/utils/types.h" - -/* Shunt/Contactor settings (Optional) */ -//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement - -/* Connectivity options */ -//#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings - -#ifdef WIFICONFIG -extern IPAddress local_IP; -extern IPAddress gateway; -extern IPAddress subnet; -#endif - -#endif // __USER_SETTINGS_H__ diff --git a/Software/src/devboard/hal/hal.cpp b/Software/src/devboard/hal/hal.cpp index ab10943f..e8b0a958 100644 --- a/Software/src/devboard/hal/hal.cpp +++ b/Software/src/devboard/hal/hal.cpp @@ -1,7 +1,5 @@ #include "hal.h" -#include "../../../USER_SETTINGS.h" - #include Esp32Hal* esp32hal = nullptr; diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index cf505a34..c6ed1640 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -4,7 +4,6 @@ #include #include #include -#include "../../../USER_SETTINGS.h" #include "../../battery/BATTERIES.h" #include "../../communication/contactorcontrol/comm_contactorcontrol.h" #include "../../datalayer/datalayer.h" diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 19e877b3..d6875aab 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -1,6 +1,5 @@ #include "events.h" #include -#include "../../../USER_SETTINGS.h" #include "../../datalayer/datalayer.h" #include "../../devboard/hal/hal.h" #include "../../devboard/utils/logging.h" diff --git a/Software/src/devboard/utils/logging.cpp b/Software/src/devboard/utils/logging.cpp index e20607fe..2b4b1d30 100644 --- a/Software/src/devboard/utils/logging.cpp +++ b/Software/src/devboard/utils/logging.cpp @@ -1,5 +1,4 @@ #include "logging.h" -#include "../../../USER_SETTINGS.h" #include "../../datalayer/datalayer.h" #include "../sdcard/sdcard.h" diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h index 69a1f170..21422385 100644 --- a/Software/src/devboard/utils/logging.h +++ b/Software/src/devboard/utils/logging.h @@ -2,8 +2,8 @@ #define __LOGGING_H__ #include -#include "../../../USER_SETTINGS.h" #include "../../datalayer/datalayer.h" +#include "Print.h" #include "types.h" #ifndef UNIT_TEST diff --git a/Software/src/devboard/utils/time_meas.h b/Software/src/devboard/utils/time_meas.h index df2c8b0c..aeac69da 100644 --- a/Software/src/devboard/utils/time_meas.h +++ b/Software/src/devboard/utils/time_meas.h @@ -1,7 +1,6 @@ #ifndef TIME_MEAS_H_ #define TIME_MEAS_H_ -#include "USER_SETTINGS.h" #include "esp_timer.h" /** Start time measurement in microseconds diff --git a/Software/src/devboard/webserver/settings_html.h b/Software/src/devboard/webserver/settings_html.h index 17043a37..227f2607 100644 --- a/Software/src/devboard/webserver/settings_html.h +++ b/Software/src/devboard/webserver/settings_html.h @@ -7,7 +7,6 @@ extern std::string ssid; extern std::string password; -#include "../../../USER_SETTINGS.h" // Needed for WiFi ssid and password #include "../../communication/nvm/comm_nvm.h" /** diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 1cf51b83..b9ba7750 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -2,7 +2,6 @@ #include #include "../utils/events.h" #include "../utils/logging.h" -#include "USER_SETTINGS.h" bool wifi_enabled = true; bool wifiap_enabled = true; @@ -15,6 +14,12 @@ std::string password; std::string ssidAP; std::string passwordAP; +// Set your Static IP address. Only used incase Static address option is set +//TODO: Make configurable via webserver +IPAddress local_IP(192, 168, 10, 150); +IPAddress gateway(192, 168, 10, 1); +IPAddress subnet(255, 255, 255, 0); + // Configuration Parameters static const uint16_t WIFI_CHECK_INTERVAL = 2000; // 1 seconds normal check interval when last connected static const uint16_t STEP_WIFI_CHECK_INTERVAL = 2000; // 3 seconds wait step increase in checks for normal reconnects diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index 07fd1189..4eb63918 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -1,7 +1,6 @@ #ifndef BYD_CAN_H #define BYD_CAN_H -#include "../../USER_SETTINGS.h" #include "../datalayer/datalayer.h" #include "CanInverterProtocol.h" diff --git a/Software/src/inverter/CanInverterProtocol.h b/Software/src/inverter/CanInverterProtocol.h index 3c9585d5..777a4548 100644 --- a/Software/src/inverter/CanInverterProtocol.h +++ b/Software/src/inverter/CanInverterProtocol.h @@ -1,14 +1,12 @@ #ifndef CANINVERTER_PROTOCOL_H #define CANINVERTER_PROTOCOL_H -#include "../../USER_SETTINGS.h" -#include "InverterProtocol.h" - #include "../communication/Transmitter.h" #include "../communication/can/CanReceiver.h" #include "../communication/can/comm_can.h" #include "../devboard/safety/safety.h" #include "../devboard/utils/types.h" +#include "InverterProtocol.h" class CanInverterProtocol : public InverterProtocol, Transmitter, CanReceiver { public: diff --git a/Software/src/inverter/INVERTERS.h b/Software/src/inverter/INVERTERS.h index 08d411ef..231eb804 100644 --- a/Software/src/inverter/INVERTERS.h +++ b/Software/src/inverter/INVERTERS.h @@ -4,8 +4,6 @@ #include "InverterProtocol.h" extern InverterProtocol* inverter; -#include "../../USER_SETTINGS.h" - #include "AFORE-CAN.h" #include "BYD-CAN.h" #include "BYD-MODBUS.h" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8d16116c..398cb69a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -82,7 +82,6 @@ add_executable(tests ../Software/src/lib/eModbus-eModbus/ModbusTypeDefs.cpp ../Software/src/lib/eModbus-eModbus/RTUutils.cpp # ../Software/src/lib/eModbus-eModbus/scripts/mbServerFCs.cpp - ../Software/USER_SETTINGS.cpp ../Software/src/battery/BATTERIES.cpp ../Software/src/battery/Battery.cpp ../Software/src/battery/BMW-I3-BATTERY.cpp From 081d96e055233b0e0648b4d830b0cd00f0c253b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 21:56:30 +0300 Subject: [PATCH 029/150] Fix unit tests after removal of USER_SETTINGS --- test/emul/Arduino.cpp | 11 +++++++++++ test/emul/Arduino.h | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/test/emul/Arduino.cpp b/test/emul/Arduino.cpp index aa0997e0..f14846c3 100644 --- a/test/emul/Arduino.cpp +++ b/test/emul/Arduino.cpp @@ -1,5 +1,16 @@ #include "Arduino.h" +#include "../../Software/src/communication/can/comm_can.h" + +// Provide the definition that was previously in USER_SETTINGS.cpp +volatile CAN_Configuration can_config = { + .battery = CAN_Interface::CAN_NATIVE, + .inverter = CAN_Interface::CAN_NATIVE, + .battery_double = CAN_Interface::CAN_NATIVE, + .charger = CAN_Interface::CAN_NATIVE, + .shunt = CAN_Interface::CAN_NATIVE +}; + void delay(unsigned long ms) {} void delayMicroseconds(unsigned long us) {} int digitalRead(uint8_t pin) { diff --git a/test/emul/Arduino.h b/test/emul/Arduino.h index 149191af..af908100 100644 --- a/test/emul/Arduino.h +++ b/test/emul/Arduino.h @@ -38,7 +38,6 @@ inline long random(long min, long max) { return min; // Return the minimum value for predictability } -// Also add randomSeed for completeness inline void randomSeed(unsigned long seed) { (void)seed; } @@ -98,6 +97,21 @@ inline int analogRead(uint8_t pin) { return 0; // Return 0 for predictable tests } +// Mock WiFi types +typedef int WiFiEvent_t; +typedef int WiFiEventInfo_t; + +// Mock WiFi functions +inline void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) { + (void)event; + (void)info; +} + +inline void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info) { + (void)event; + (void)info; +} + unsigned long micros(); // Can be previously declared as a macro in stupid eModbus #undef millis From 630c67a482c75d21205912d581e84fff26df9478 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 18:57:25 +0000 Subject: [PATCH 030/150] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- test/emul/Arduino.cpp | 12 +++++------- test/emul/Arduino.h | 8 ++++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/test/emul/Arduino.cpp b/test/emul/Arduino.cpp index f14846c3..563dd466 100644 --- a/test/emul/Arduino.cpp +++ b/test/emul/Arduino.cpp @@ -3,13 +3,11 @@ #include "../../Software/src/communication/can/comm_can.h" // Provide the definition that was previously in USER_SETTINGS.cpp -volatile CAN_Configuration can_config = { - .battery = CAN_Interface::CAN_NATIVE, - .inverter = CAN_Interface::CAN_NATIVE, - .battery_double = CAN_Interface::CAN_NATIVE, - .charger = CAN_Interface::CAN_NATIVE, - .shunt = CAN_Interface::CAN_NATIVE -}; +volatile CAN_Configuration can_config = {.battery = CAN_Interface::CAN_NATIVE, + .inverter = CAN_Interface::CAN_NATIVE, + .battery_double = CAN_Interface::CAN_NATIVE, + .charger = CAN_Interface::CAN_NATIVE, + .shunt = CAN_Interface::CAN_NATIVE}; void delay(unsigned long ms) {} void delayMicroseconds(unsigned long us) {} diff --git a/test/emul/Arduino.h b/test/emul/Arduino.h index af908100..0bcf55b5 100644 --- a/test/emul/Arduino.h +++ b/test/emul/Arduino.h @@ -103,13 +103,13 @@ typedef int WiFiEventInfo_t; // Mock WiFi functions inline void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) { - (void)event; - (void)info; + (void)event; + (void)info; } inline void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info) { - (void)event; - (void)info; + (void)event; + (void)info; } unsigned long micros(); From 778d9b85853858e83e83b9f323c085b33d5316ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 22:00:00 +0300 Subject: [PATCH 031/150] Wifi unit test wrap --- Software/src/communication/can/comm_can.h | 1 + Software/src/devboard/wifi/wifi.h | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h index b4624928..5af47131 100644 --- a/Software/src/communication/can/comm_can.h +++ b/Software/src/communication/can/comm_can.h @@ -22,6 +22,7 @@ typedef struct { CAN_Interface charger; CAN_Interface shunt; } CAN_Configuration; + extern volatile CAN_Configuration can_config; enum class CAN_Speed { diff --git a/Software/src/devboard/wifi/wifi.h b/Software/src/devboard/wifi/wifi.h index bf0ecb01..0a24d283 100644 --- a/Software/src/devboard/wifi/wifi.h +++ b/Software/src/devboard/wifi/wifi.h @@ -15,9 +15,19 @@ void init_WiFi(); void wifi_monitor(); void connectToWiFi(); void FullReconnectToWiFi(); + +// In the real wifi.h +#ifndef UNIT_TEST void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info); void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info); void onWifiGotIP(WiFiEvent_t event, WiFiEventInfo_t info); +#else +// Mock declarations for unit tests +typedef int WiFiEvent_t; +typedef int WiFiEventInfo_t; +void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info); +void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info); +#endif void init_WiFi_AP(); From 90d333214371e0f320bd476f7615cc0118061f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 23:34:58 +0300 Subject: [PATCH 032/150] Add configurable static IP --- Software/src/communication/nvm/comm_nvm.cpp | 14 ++ .../src/devboard/webserver/settings_html.cpp | 188 +++++++++++++----- Software/src/devboard/webserver/webserver.cpp | 44 +++- Software/src/devboard/wifi/wifi.cpp | 32 ++- Software/src/devboard/wifi/wifi.h | 13 ++ 5 files changed, 228 insertions(+), 63 deletions(-) diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 3ba5b478..df9cae1b 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -166,6 +166,20 @@ void init_stored_settings() { mqtt_transmit_all_cellvoltages = settings.getBool("MQTTCELLV", false); custom_hostname = settings.getString("HOSTNAME").c_str(); + static_IP_enabled = settings.getBool("STATICIP", false); + static_local_IP1 = settings.getUInt("LOCALIP1", 192); + static_local_IP2 = settings.getUInt("LOCALIP2", 168); + static_local_IP3 = settings.getUInt("LOCALIP3", 10); + static_local_IP4 = settings.getUInt("LOCALIP4", 150); + static_gateway1 = settings.getUInt("GATEWAY1", 192); + static_gateway2 = settings.getUInt("GATEWAY2", 168); + static_gateway3 = settings.getUInt("GATEWAY3", 10); + static_gateway4 = settings.getUInt("GATEWAY4", 1); + static_subnet1 = settings.getUInt("SUBNET1", 255); + static_subnet2 = settings.getUInt("SUBNET2", 255); + static_subnet3 = settings.getUInt("SUBNET3", 255); + static_subnet4 = settings.getUInt("SUBNET4", 0); + mqtt_server = settings.getString("MQTTSERVER").c_str(); mqtt_port = settings.getUInt("MQTTPORT", 0); mqtt_user = settings.getString("MQTTUSER").c_str(); diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index b2892d89..63411805 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -291,10 +291,62 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return settings.getBool("WIFIAPENABLED", wifiap_enabled) ? "checked" : ""; } + if (var == "STATICIP") { + return settings.getBool("STATICIP") ? "checked" : ""; + } + if (var == "WIFICHANNEL") { return String(settings.getUInt("WIFICHANNEL", 0)); } + if (var == "LOCALIP1") { + return String(settings.getUInt("LOCALIP1", 0)); + } + + if (var == "LOCALIP2") { + return String(settings.getUInt("LOCALIP2", 0)); + } + + if (var == "LOCALIP3") { + return String(settings.getUInt("LOCALIP3", 0)); + } + + if (var == "LOCALIP4") { + return String(settings.getUInt("LOCALIP4", 0)); + } + + if (var == "GATEWAY1") { + return String(settings.getUInt("GATEWAY1", 0)); + } + + if (var == "GATEWAY2") { + return String(settings.getUInt("GATEWAY2", 0)); + } + + if (var == "GATEWAY3") { + return String(settings.getUInt("GATEWAY3", 0)); + } + + if (var == "GATEWAY4") { + return String(settings.getUInt("GATEWAY4", 0)); + } + + if (var == "SUBNET1") { + return String(settings.getUInt("SUBNET1", 0)); + } + + if (var == "SUBNET2") { + return String(settings.getUInt("SUBNET2", 0)); + } + + if (var == "SUBNET3") { + return String(settings.getUInt("SUBNET3", 0)); + } + + if (var == "SUBNET4") { + return String(settings.getUInt("SUBNET4", 0)); + } + if (var == "PERFPROFILE") { return settings.getBool("PERFPROFILE") ? "checked" : ""; } @@ -852,6 +904,11 @@ const char* getCANInterfaceName(CAN_Interface interface) { display: contents; } + form .if-staticip { display: none; } + form[data-staticip="true"] .if-staticip { + display: contents; + } + form .if-mqtt { display: none; } form[data-mqttenabled="true"] .if-mqtt { display: contents; @@ -869,40 +926,41 @@ const char* getCANInterfaceName(CAN_Interface interface) { R"rawliteral( -
+

SSID: %SSID%

Password: ########

+
-
-
+
- - + %BATTTYPE%
- - + +
- - - - - - - - + + + + + + + +
@@ -970,7 +1028,7 @@ const char* getCANInterfaceName(CAN_Interface interface) { - +
+ + + - +
@@ -1009,18 +1070,18 @@ const char* getCANInterfaceName(CAN_Interface interface) { %BATT2COMM% - +
- +
- +
@@ -1033,58 +1094,85 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- + - + - +
- +
- - - - - + + - + + + + +
+
+
Local IP:
+ . + . + . + +
+ +
+
Gateway:
+ . + . + . + +
+ +
+
Subnet:
+ . + . + . + +
+
+
+ - + - + - + - + - + - + - +
@@ -1092,9 +1180,9 @@ const char* getCANInterfaceName(CAN_Interface interface) { - + - +
@@ -1106,14 +1194,14 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- +
-

Settings saved. Reboot to take the settings into use.

+

Settings saved. Reboot to take the new settings into use.

diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 2b5f0b9d..4a173127 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -397,10 +397,10 @@ void init_webserver() { }; const char* boolSettingNames[] = { - "DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED", - "REMBMSRESET", "EXTPRECHARGE", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", - "CANLOGSD", "WIFIAPENABLED", "MQTTENABLED", "NOINVDISC", "HADISC", "MQTTTOPICS", - "MQTTCELLV", "INVICNT", "GTWRHD", "DIGITALHVIL", "PERFPROFILE", "INTERLOCKREQ", + "DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED", "STATICIP", + "REMBMSRESET", "EXTPRECHARGE", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", "CANLOGSD", + "WIFIAPENABLED", "MQTTENABLED", "NOINVDISC", "HADISC", "MQTTTOPICS", "MQTTCELLV", "INVICNT", + "GTWRHD", "DIGITALHVIL", "PERFPROFILE", "INTERLOCKREQ", }; // Handles the form POST from UI to save settings of the common image @@ -467,6 +467,42 @@ void init_webserver() { } else if (p->name() == "WIFICHANNEL") { auto type = atoi(p->value().c_str()); settings.saveUInt("WIFICHANNEL", type); + } else if (p->name() == "LOCALIP1") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("LOCALIP1", type); + } else if (p->name() == "LOCALIP2") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("LOCALIP2", type); + } else if (p->name() == "LOCALIP3") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("LOCALIP3", type); + } else if (p->name() == "LOCALIP4") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("LOCALIP4", type); + } else if (p->name() == "GATEWAY1") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("GATEWAY1", type); + } else if (p->name() == "GATEWAY2") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("GATEWAY2", type); + } else if (p->name() == "GATEWAY3") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("GATEWAY3", type); + } else if (p->name() == "GATEWAY4") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("GATEWAY4", type); + } else if (p->name() == "SUBNET1") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("SUBNET1", type); + } else if (p->name() == "SUBNET2") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("SUBNET2", type); + } else if (p->name() == "SUBNET3") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("SUBNET3", type); + } else if (p->name() == "SUBNET4") { + auto type = atoi(p->value().c_str()); + settings.saveUInt("SUBNET4", type); } else if (p->name() == "HOSTNAME") { settings.saveString("HOSTNAME", p->value().c_str()); } else if (p->name() == "MQTTSERVER") { diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index b9ba7750..ab9831ee 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -15,10 +15,19 @@ std::string ssidAP; std::string passwordAP; // Set your Static IP address. Only used incase Static address option is set -//TODO: Make configurable via webserver -IPAddress local_IP(192, 168, 10, 150); -IPAddress gateway(192, 168, 10, 1); -IPAddress subnet(255, 255, 255, 0); +bool static_IP_enabled = false; +uint16_t static_local_IP1 = 0; +uint16_t static_local_IP2 = 0; +uint16_t static_local_IP3 = 0; +uint16_t static_local_IP4 = 0; +uint16_t static_gateway1 = 0; +uint16_t static_gateway2 = 0; +uint16_t static_gateway3 = 0; +uint16_t static_gateway4 = 0; +uint16_t static_subnet1 = 0; +uint16_t static_subnet2 = 0; +uint16_t static_subnet3 = 0; +uint16_t static_subnet4 = 0; // Configuration Parameters static const uint16_t WIFI_CHECK_INTERVAL = 2000; // 1 seconds normal check interval when last connected @@ -62,11 +71,16 @@ void init_WiFi() { // Set WiFi to auto reconnect WiFi.setAutoReconnect(true); -#ifdef WIFICONFIG - // Set static IP - WiFi.config(local_IP, gateway, subnet); -#endif - + if (static_IP_enabled) { + // Set static IP + IPAddress local_IP((uint8_t)static_local_IP1, (uint8_t)static_local_IP2, (uint8_t)static_local_IP3, + (uint8_t)static_local_IP4); + IPAddress gateway((uint8_t)static_gateway1, (uint8_t)static_gateway2, (uint8_t)static_gateway3, + (uint8_t)static_gateway4); + IPAddress subnet((uint8_t)static_subnet1, (uint8_t)static_subnet2, (uint8_t)static_subnet3, + (uint8_t)static_subnet4); + WiFi.config(local_IP, gateway, subnet); + } DEBUG_PRINTF("init_Wifi set event handlers\n"); // Initialize Wi-Fi event handlers diff --git a/Software/src/devboard/wifi/wifi.h b/Software/src/devboard/wifi/wifi.h index 0a24d283..ed6a9a89 100644 --- a/Software/src/devboard/wifi/wifi.h +++ b/Software/src/devboard/wifi/wifi.h @@ -37,5 +37,18 @@ void init_mDNS(); extern bool wifi_enabled; extern bool wifiap_enabled; extern bool mdns_enabled; +extern bool static_IP_enabled; +extern uint16_t static_local_IP1; +extern uint16_t static_local_IP2; +extern uint16_t static_local_IP3; +extern uint16_t static_local_IP4; +extern uint16_t static_gateway1; +extern uint16_t static_gateway2; +extern uint16_t static_gateway3; +extern uint16_t static_gateway4; +extern uint16_t static_subnet1; +extern uint16_t static_subnet2; +extern uint16_t static_subnet3; +extern uint16_t static_subnet4; #endif From 21870349d40f7d981a8c4a9d44a60aa1d124cb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 23:40:32 +0300 Subject: [PATCH 033/150] Update Software.cpp --- Software/Software.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 8ad87b7e..81412e76 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.0.RC5experimental"; +const char* version_number = "9.0.RC5"; // Interval timers volatile unsigned long currentMillis = 0; From 0617bf4b8c95a3ef46546928816c161279c28b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 2 Sep 2025 23:59:44 +0300 Subject: [PATCH 034/150] Update release-assets.yml --- .github/workflows/release-assets.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml index fcbf4684..bb1c4dc9 100644 --- a/.github/workflows/release-assets.yml +++ b/.github/workflows/release-assets.yml @@ -47,10 +47,6 @@ jobs: - name: Install PlatformIO Core run: pip install --upgrade platformio - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - name: 🛠 Build ota image for Lilygo T-CAN run: | pio run -e lilygo_330 From 08b6c81e67c7ce2761d0940be7c0f55e403fed58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 3 Sep 2025 13:02:08 +0300 Subject: [PATCH 035/150] Increase CAN TX buffer --- Software/Software.cpp | 2 +- .../src/lib/pierremolinaro-acan-esp32/ACAN_ESP32_Settings.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 81412e76..9dca621e 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.0.RC5"; +const char* version_number = "9.0.RC6experimental"; // Interval timers volatile unsigned long currentMillis = 0; diff --git a/Software/src/lib/pierremolinaro-acan-esp32/ACAN_ESP32_Settings.h b/Software/src/lib/pierremolinaro-acan-esp32/ACAN_ESP32_Settings.h index 9f1d937e..9ad3136f 100644 --- a/Software/src/lib/pierremolinaro-acan-esp32/ACAN_ESP32_Settings.h +++ b/Software/src/lib/pierremolinaro-acan-esp32/ACAN_ESP32_Settings.h @@ -101,7 +101,7 @@ class ACAN_ESP32_Settings { // Transmit buffer sizes // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public: uint16_t mDriverTransmitBufferSize = 16 ; + public: uint16_t mDriverTransmitBufferSize = 32 ; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Compute actual bit rate From e38b6286c75f090362a2c0638aaa148ec6dd6c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 3 Sep 2025 23:25:30 +0300 Subject: [PATCH 036/150] Add initial support for 50/75kWh vans --- Software/src/battery/ECMP-BATTERY.cpp | 155 +++++++++++++++++++++----- Software/src/battery/ECMP-BATTERY.h | 5 +- 2 files changed, 130 insertions(+), 30 deletions(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 536f4b90..456eb7b0 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -12,44 +12,86 @@ This integration is still ongoing. Here is what still needs to be done in order /* Do not change code below unless you are sure what you are doing */ void EcmpBattery::update_values() { - datalayer.battery.status.real_soc = battery_soc * 10; + if (!MysteryVan) { //Normal eCMP platform + datalayer.battery.status.real_soc = battery_soc * 10; - datalayer.battery.status.soh_pptt; + datalayer.battery.status.soh_pptt; - datalayer.battery.status.voltage_dV = battery_voltage * 10; + datalayer.battery.status.voltage_dV = battery_voltage * 10; - datalayer.battery.status.current_dA = -(battery_current * 10); + datalayer.battery.status.current_dA = -(battery_current * 10); - 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.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 = battery_AllowedMaxChargeCurrent * battery_voltage; + datalayer.battery.status.max_charge_power_W = battery_AllowedMaxChargeCurrent * battery_voltage; - datalayer.battery.status.max_discharge_power_W = battery_AllowedMaxDischargeCurrent * battery_voltage; + datalayer.battery.status.max_discharge_power_W = battery_AllowedMaxDischargeCurrent * battery_voltage; - datalayer.battery.status.temperature_min_dC = battery_lowestTemperature * 10; + datalayer.battery.status.temperature_min_dC = battery_lowestTemperature * 10; - datalayer.battery.status.temperature_max_dC = battery_highestTemperature * 10; + datalayer.battery.status.temperature_max_dC = battery_highestTemperature * 10; - // Initialize min and max, lets find which cells are min and max! - uint16_t min_cell_mv_value = std::numeric_limits::max(); - uint16_t max_cell_mv_value = 0; - // Loop to find the min and max while ignoring zero values - for (uint8_t i = 0; i < datalayer.battery.info.number_of_cells; ++i) { - uint16_t voltage_mV = datalayer.battery.status.cell_voltages_mV[i]; - if (voltage_mV != 0) { // Skip unread values (0) - min_cell_mv_value = std::min(min_cell_mv_value, voltage_mV); - max_cell_mv_value = std::max(max_cell_mv_value, voltage_mV); + // Initialize min and max, lets find which cells are min and max! + uint16_t min_cell_mv_value = std::numeric_limits::max(); + uint16_t max_cell_mv_value = 0; + // Loop to find the min and max while ignoring zero values + for (uint8_t i = 0; i < datalayer.battery.info.number_of_cells; ++i) { + uint16_t voltage_mV = datalayer.battery.status.cell_voltages_mV[i]; + if (voltage_mV != 0) { // Skip unread values (0) + min_cell_mv_value = std::min(min_cell_mv_value, voltage_mV); + max_cell_mv_value = std::max(max_cell_mv_value, voltage_mV); + } + } + // If all array values are 0, reset min/max to 3700 + if (min_cell_mv_value == std::numeric_limits::max()) { + min_cell_mv_value = 3700; + max_cell_mv_value = 3700; + } + + datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value; + datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value; + } else { //Some variant of the 50/75kWh battery that is not using the eCMP CAN mappings. + // For these batteries we need to use the OBD2 PID polled values + datalayer.battery.status.real_soc = battery_soc * 10; //TTOD, calculate based on cap remaining? + + datalayer.battery.status.soh_pptt; + + if (pid_pack_voltage != NOT_SAMPLED_YET) { + datalayer.battery.status.voltage_dV = pid_pack_voltage; + } + + if (pid_current != NOT_SAMPLED_YET) { + datalayer.battery.status.current_dA = (int16_t)(pid_current / 100); + + datalayer.battery.status.active_power_W = + (uint16_t)((pid_current / 1000.0f) * (datalayer.battery.status.voltage_dV / 10.0f)); + } + + if (pid_max_charge_10s != NOT_SAMPLED_YET) { + datalayer.battery.status.max_charge_power_W = pid_max_charge_10s; + } + + if (pid_max_discharge_10s != NOT_SAMPLED_YET) { + datalayer.battery.status.max_discharge_power_W = pid_max_discharge_10s; + } + + if (pid_lowest_temperature != NOT_SAMPLED_YET) { + datalayer.battery.status.temperature_min_dC = pid_lowest_temperature * 10; + } + + if (pid_highest_temperature != NOT_SAMPLED_YET) { + datalayer.battery.status.temperature_max_dC = pid_highest_temperature * 10; + } + + if (pid_high_cell_voltage != NOT_SAMPLED_YET) { + datalayer.battery.status.cell_max_voltage_mV = pid_high_cell_voltage; + } + + if (pid_low_cell_voltage != NOT_SAMPLED_YET) { + datalayer.battery.status.cell_min_voltage_mV = pid_low_cell_voltage; } } - // If all array values are 0, reset min/max to 3700 - if (min_cell_mv_value == std::numeric_limits::max()) { - min_cell_mv_value = 3700; - max_cell_mv_value = 3700; - } - - datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value; - datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value; // Update extended datalayer (More Battery Info page) datalayer_extended.stellantisECMP.MainConnectorState = battery_MainConnectorState; @@ -145,9 +187,58 @@ void EcmpBattery::update_values() { } void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { - datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { + case 0x2D4: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + MysteryVan = true; + break; + case 0x3B4: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x2F4: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x3F4: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x554: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x373: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x4F4: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x414: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x353: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x474: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x574: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x583: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x314: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x254: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x2B4: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x4D4: //MysteryVan 50/75kWh platform + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; case 0x125: //Common + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_soc = (rx_frame.data.u8[0] << 2) | (rx_frame.data.u8[1] >> 6); // Byte1, bit 7 length 10 (0x3FE when abnormal) (0-1000 ppt) battery_MainConnectorState = ((rx_frame.data.u8[2] & 0x18) >> @@ -157,6 +248,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { battery_current = (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[5]) - 600; // TODO: Test break; case 0x127: //DFM specific + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_AllowedMaxChargeCurrent = (rx_frame.data.u8[0] << 2) | ((rx_frame.data.u8[1] & 0xC0) >> 6); //Byte 1, bit 7, length 10 (0-600A) [0x3FF if invalid] @@ -165,12 +257,15 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { (rx_frame.data.u8[3] >> 4); //Byte 2, bit 5, length 10 (0-600A) [0x3FF if invalid] break; case 0x129: //PSA specific + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; break; case 0x31B: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_InterlockOpen = ((rx_frame.data.u8[1] & 0x10) >> 4); //Best guess, seems to work? //TODO: frame7 contains checksum, we can use this to check for CAN message corruption break; case 0x358: //Common + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_highestTemperature = rx_frame.data.u8[6] - 40; battery_lowestTemperature = rx_frame.data.u8[7] - 40; break; @@ -185,11 +280,13 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { case 0x494: break; case 0x594: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_insulation_failure_diag = ((rx_frame.data.u8[6] & 0xE0) >> 5); //Unsure if this is right position //byte pos 6, bit pos 7, signal lenth 3 //0 = no failure, 1 = symmetric failure, 4 = invalid value , forbidden value 5-7 break; case 0x6D0: //Common + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_insulationResistanceKOhm = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; //Byte 2, bit 7, length 16 (0-60000 kOhm) break; @@ -198,6 +295,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { case 0x6D2: break; case 0x6D3: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; cellvoltages[0] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; cellvoltages[1] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cellvoltages[2] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; @@ -374,6 +472,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages, 108 * sizeof(uint16_t)); break; case 0x694: // Poll reply + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; // Handle user requested functionality first if ongoing if (datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring) { diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h index fe4aa58a..201f59d8 100644 --- a/Software/src/battery/ECMP-BATTERY.h +++ b/Software/src/battery/ECMP-BATTERY.h @@ -38,6 +38,7 @@ class EcmpBattery : public CanBattery { static const int COMPLETED_STATE = 0; bool battery_RelayOpenRequest = false; bool battery_InterlockOpen = false; + bool MysteryVan = false; uint8_t ContactorResetStatemachine = 0; uint8_t CollisionResetStatemachine = 0; uint8_t IsolationResetStatemachine = 0; @@ -80,8 +81,8 @@ class EcmpBattery : public CanBattery { uint8_t pid_coldest_module = NOT_SAMPLED_YET; uint8_t pid_lowest_temperature = NOT_SAMPLED_YET; uint8_t pid_average_temperature = NOT_SAMPLED_YET; - uint8_t pid_highest_temperature = NOT_SAMPLED_YET; - uint8_t pid_hottest_module = NOT_SAMPLED_YET; + int8_t pid_highest_temperature = NOT_SAMPLED_YET; + int8_t pid_hottest_module = NOT_SAMPLED_YET; uint16_t pid_avg_cell_voltage = NOT_SAMPLED_YET; int32_t pid_current = NOT_SAMPLED_YET; uint32_t pid_insulation_res_neg = NOT_SAMPLED_YET; From 805d5060627bb38ff7919bb3702dbe5073840b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 3 Sep 2025 23:39:50 +0300 Subject: [PATCH 037/150] Fix SOC and capacity for mystery van --- Software/src/battery/ECMP-BATTERY.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 456eb7b0..9adf2661 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -24,6 +24,9 @@ void EcmpBattery::update_values() { 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.remaining_capacity_Wh = static_cast( + (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); + datalayer.battery.status.max_charge_power_W = battery_AllowedMaxChargeCurrent * battery_voltage; datalayer.battery.status.max_discharge_power_W = battery_AllowedMaxDischargeCurrent * battery_voltage; @@ -53,7 +56,13 @@ void EcmpBattery::update_values() { datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value; } else { //Some variant of the 50/75kWh battery that is not using the eCMP CAN mappings. // For these batteries we need to use the OBD2 PID polled values - datalayer.battery.status.real_soc = battery_soc * 10; //TTOD, calculate based on cap remaining? + + if (pid_energy_capacity != NOT_SAMPLED_YET) { + datalayer.battery.status.remaining_capacity_Wh = pid_energy_capacity; + // calculate SOC based on datalayer.battery.info.total_capacity_Wh and remaining_capacity_Wh + datalayer.battery.status.real_soc = + ((datalayer.battery.status.remaining_capacity_Wh / datalayer.battery.info.total_capacity_Wh) * 10000); + } datalayer.battery.status.soh_pptt; From 3597a99a089b64f11d155ae7aa3bbcbf4009ffc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 3 Sep 2025 23:52:32 +0300 Subject: [PATCH 038/150] Fix float calculation for SOC --- Software/src/battery/ECMP-BATTERY.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 9adf2661..0e77e5d9 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -60,8 +60,9 @@ void EcmpBattery::update_values() { if (pid_energy_capacity != NOT_SAMPLED_YET) { datalayer.battery.status.remaining_capacity_Wh = pid_energy_capacity; // calculate SOC based on datalayer.battery.info.total_capacity_Wh and remaining_capacity_Wh - datalayer.battery.status.real_soc = - ((datalayer.battery.status.remaining_capacity_Wh / datalayer.battery.info.total_capacity_Wh) * 10000); + datalayer.battery.status.real_soc = (uint16_t)(((float)datalayer.battery.status.remaining_capacity_Wh / + datalayer.battery.info.total_capacity_Wh) * + 10000); } datalayer.battery.status.soh_pptt; From bd0923cab3b66dcfed81e3406bd1857c4e0dffee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 3 Sep 2025 23:55:35 +0300 Subject: [PATCH 039/150] Only update temp and cellv when both min/max are available --- Software/src/battery/ECMP-BATTERY.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 0e77e5d9..1fe61714 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -86,19 +86,13 @@ void EcmpBattery::update_values() { datalayer.battery.status.max_discharge_power_W = pid_max_discharge_10s; } - if (pid_lowest_temperature != NOT_SAMPLED_YET) { + if ((pid_highest_temperature != NOT_SAMPLED_YET) && (pid_lowest_temperature != NOT_SAMPLED_YET)) { + datalayer.battery.status.temperature_max_dC = pid_highest_temperature * 10; datalayer.battery.status.temperature_min_dC = pid_lowest_temperature * 10; } - if (pid_highest_temperature != NOT_SAMPLED_YET) { - datalayer.battery.status.temperature_max_dC = pid_highest_temperature * 10; - } - - if (pid_high_cell_voltage != NOT_SAMPLED_YET) { + if ((pid_high_cell_voltage != NOT_SAMPLED_YET) && (pid_low_cell_voltage != NOT_SAMPLED_YET)) { datalayer.battery.status.cell_max_voltage_mV = pid_high_cell_voltage; - } - - if (pid_low_cell_voltage != NOT_SAMPLED_YET) { datalayer.battery.status.cell_min_voltage_mV = pid_low_cell_voltage; } } From 5770df46e4fc6d94d2d5db96fe2628b7d2c1e350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 4 Sep 2025 09:28:07 +0300 Subject: [PATCH 040/150] Add offset to voltage value to make it more realistic --- Software/src/battery/ECMP-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 1fe61714..2e5547e7 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -68,7 +68,7 @@ void EcmpBattery::update_values() { datalayer.battery.status.soh_pptt; if (pid_pack_voltage != NOT_SAMPLED_YET) { - datalayer.battery.status.voltage_dV = pid_pack_voltage; + datalayer.battery.status.voltage_dV = pid_pack_voltage + 800; } if (pid_current != NOT_SAMPLED_YET) { From 8fe21fddb7090712462383325464b961fd4fe563 Mon Sep 17 00:00:00 2001 From: Matt Holmes Date: Thu, 4 Sep 2025 10:35:32 +0100 Subject: [PATCH 041/150] Fixing mqtt_loop setup regression bug --- Software/Software.cpp | 24 ++++++++++++------------ Software/src/devboard/mqtt/mqtt.cpp | 2 +- Software/src/devboard/mqtt/mqtt.h | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 9dca621e..c0ef4e99 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -474,6 +474,18 @@ void core_loop(void*) { } } +void mqtt_loop(void*) { + esp_task_wdt_add(NULL); // Register this task with WDT + + while (true) { + START_TIME_MEASUREMENT(mqtt); + mqtt_client_loop(); + END_TIME_MEASUREMENT_MAX(mqtt, datalayer.system.status.mqtt_task_10s_max_us); + esp_task_wdt_reset(); // Reset watchdog + delay(1); + } +} + // Initialization void setup() { init_hal(); @@ -573,15 +585,3 @@ void setup() { // Loop empty, all functionality runs in tasks void loop() {} - -void mqtt_loop(void*) { - esp_task_wdt_add(NULL); // Register this task with WDT - - while (true) { - START_TIME_MEASUREMENT(mqtt); - mqtt_loop(); - END_TIME_MEASUREMENT_MAX(mqtt, datalayer.system.status.mqtt_task_10s_max_us); - esp_task_wdt_reset(); // Reset watchdog - delay(1); - } -} diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index c6ed1640..d50e25b1 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -675,7 +675,7 @@ bool init_mqtt(void) { return true; } -void mqtt_loop(void) { +void mqtt_client_loop(void) { // Only attempt to publish/reconnect MQTT if Wi-Fi is connectedand checkTimmer is elapsed if (check_global_timer.elapsed() && WiFi.status() == WL_CONNECTED) { diff --git a/Software/src/devboard/mqtt/mqtt.h b/Software/src/devboard/mqtt/mqtt.h index 4189ca91..9ea4e50e 100644 --- a/Software/src/devboard/mqtt/mqtt.h +++ b/Software/src/devboard/mqtt/mqtt.h @@ -58,7 +58,7 @@ extern const char* ha_device_id; extern char mqtt_msg[MQTT_MSG_BUFFER_SIZE]; bool init_mqtt(void); -void mqtt_loop(void); +void mqtt_client_loop(void); bool mqtt_publish(const char* topic, const char* mqtt_msg, bool retain); #endif From a9185be603c0dc8a25f1e296c3450436d181b5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 4 Sep 2025 20:26:17 +0300 Subject: [PATCH 042/150] Add manual override charge(discharge limits --- Software/src/battery/BMW-IX-BATTERY.cpp | 6 ++--- Software/src/battery/BMW-IX-BATTERY.h | 2 -- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 6 ++--- Software/src/battery/BOLT-AMPERA-BATTERY.h | 2 -- Software/src/battery/CELLPOWER-BMS.cpp | 6 +++-- .../src/battery/IMIEV-CZERO-ION-BATTERY.cpp | 6 +++-- Software/src/battery/RJXZS-BMS.cpp | 10 +++---- Software/src/battery/RJXZS-BMS.h | 3 --- Software/src/battery/TESLA-BATTERY.cpp | 6 ++--- Software/src/battery/TESLA-BATTERY.h | 9 ------- Software/src/communication/nvm/comm_nvm.cpp | 4 +++ Software/src/datalayer/datalayer.h | 7 +++++ .../src/devboard/webserver/settings_html.cpp | 27 +++++++++++++++++++ Software/src/devboard/webserver/webserver.cpp | 6 +++++ 14 files changed, 66 insertions(+), 34 deletions(-) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index 93596ca8..cf8dc1de 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -60,7 +60,7 @@ void BmwIXBattery::update_values() { //This function maps all the values fetche datalayer.battery.status.soh_pptt = min_soh_state; - datalayer.battery.status.max_discharge_power_W = MAX_DISCHARGE_POWER_ALLOWED_W; + datalayer.battery.status.max_discharge_power_W = datalayer.battery.status.override_discharge_power_W; //datalayer.battery.status.max_charge_power_W = 3200; //10000; //Aux HV Port has 100A Fuse Moved to Ramping @@ -70,10 +70,10 @@ void BmwIXBattery::update_values() { //This function maps all the values fetche } 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 * + datalayer.battery.status.override_charge_power_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 = datalayer.battery.status.override_charge_power_W; } datalayer.battery.status.temperature_min_dC = min_battery_temperature; diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 7bc54095..d892c100 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -48,8 +48,6 @@ class BmwIXBattery : public CanBattery { static const int MAX_CELL_DEVIATION_MV = 250; static const int MAX_CELL_VOLTAGE_MV = 4300; //Battery is put into emergency stop if one cell goes over this value static const int MIN_CELL_VOLTAGE_MV = 2800; //Battery is put into emergency stop if one cell goes below this value - static const int MAX_DISCHARGE_POWER_ALLOWED_W = 10000; - static const int MAX_CHARGE_POWER_ALLOWED_W = 10000; static const int MAX_CHARGE_POWER_WHEN_TOPBALANCING_W = 500; static const int RAMPDOWN_SOC = 9000; // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00% diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index b740c11b..fce8e1b8 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -96,14 +96,14 @@ void BoltAmperaBattery::update_values() { //This function maps all the values f } 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 * + datalayer.battery.status.override_charge_power_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 = datalayer.battery.status.override_charge_power_W; } // Discharge power is also set in .h file (TODO: Remove this estimation when real value has been found) - datalayer.battery.status.max_discharge_power_W = MAX_DISCHARGE_POWER_ALLOWED_W; + datalayer.battery.status.max_discharge_power_W = datalayer.battery.status.override_discharge_power_W; datalayer.battery.status.temperature_min_dC = temperature_lowest_C * 10; diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.h b/Software/src/battery/BOLT-AMPERA-BATTERY.h index 05b28f80..02d8bbda 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.h +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.h @@ -16,8 +16,6 @@ class BoltAmperaBattery : public CanBattery { private: BoltAmperaHtmlRenderer renderer; - static const int MAX_DISCHARGE_POWER_ALLOWED_W = 10000; - static const int MAX_CHARGE_POWER_ALLOWED_W = 10000; static const int MAX_CHARGE_POWER_WHEN_TOPBALANCING_W = 500; static const int RAMPDOWN_SOC = 9000; // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00% diff --git a/Software/src/battery/CELLPOWER-BMS.cpp b/Software/src/battery/CELLPOWER-BMS.cpp index baa375d6..8d5d089d 100644 --- a/Software/src/battery/CELLPOWER-BMS.cpp +++ b/Software/src/battery/CELLPOWER-BMS.cpp @@ -20,9 +20,11 @@ void CellPowerBms::update_values() { datalayer.battery.status.current_dA = battery_pack_current_dA; - datalayer.battery.status.max_charge_power_W = 5000; //TODO, is this available via CAN? + datalayer.battery.status.max_charge_power_W = + datalayer.battery.status.override_charge_power_W; //TODO, is this available via CAN? - datalayer.battery.status.max_discharge_power_W = 5000; //TODO, is this available via CAN? + datalayer.battery.status.max_discharge_power_W = + datalayer.battery.status.override_discharge_power_W; //TODO, is this available via CAN? datalayer.battery.status.temperature_min_dC = (int16_t)(pack_temperature_low_C * 10); diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index d77820a9..d6825caa 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -20,9 +20,11 @@ void ImievCZeroIonBattery:: (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); //We do not know the max charge/discharge power is sent by the battery. We hardcode value for now. - datalayer.battery.status.max_charge_power_W = 10000; // 10kW //TODO: Fix when CAN is decoded + datalayer.battery.status.max_charge_power_W = + datalayer.battery.status.override_charge_power_W; //TODO: Fix when CAN is decoded - datalayer.battery.status.max_discharge_power_W = 10000; // 10kW //TODO: Fix when CAN is decoded + datalayer.battery.status.max_discharge_power_W = + datalayer.battery.status.override_discharge_power_W; //TODO: Fix when CAN is decoded 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 diff --git a/Software/src/battery/RJXZS-BMS.cpp b/Software/src/battery/RJXZS-BMS.cpp index 6bbb4fe8..b6bb91cf 100644 --- a/Software/src/battery/RJXZS-BMS.cpp +++ b/Software/src/battery/RJXZS-BMS.cpp @@ -33,20 +33,20 @@ void RjxzsBms::update_values() { datalayer.battery.status.current_dA = total_current; } - // Charge power is set in .h file + // Charge power is manually set 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 * + datalayer.battery.status.override_charge_power_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 = datalayer.battery.status.override_charge_power_W; } - // Discharge power is also set in .h file - datalayer.battery.status.max_discharge_power_W = MAX_DISCHARGE_POWER_ALLOWED_W; + // Discharge power is manually set + datalayer.battery.status.max_discharge_power_W = datalayer.battery.status.override_discharge_power_W; uint16_t temperatures[] = { module_1_temperature, module_2_temperature, module_3_temperature, module_4_temperature, diff --git a/Software/src/battery/RJXZS-BMS.h b/Software/src/battery/RJXZS-BMS.h index 6d549752..aadc4f8d 100644 --- a/Software/src/battery/RJXZS-BMS.h +++ b/Software/src/battery/RJXZS-BMS.h @@ -15,9 +15,6 @@ class RjxzsBms : public CanBattery { static constexpr const char* Name = "RJXZS BMS, DIY battery"; private: - /* Tweak these according to your battery build */ - static const int MAX_DISCHARGE_POWER_ALLOWED_W = 5000; - static const int MAX_CHARGE_POWER_ALLOWED_W = 5000; static const int MAX_CHARGE_POWER_WHEN_TOPBALANCING_W = 500; static const int RAMPDOWN_SOC = 9000; // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00% diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 3f338ee4..42226c9f 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -627,8 +627,8 @@ void TeslaBattery:: // Define the allowed discharge power datalayer.battery.status.max_discharge_power_W = (battery_max_discharge_current * (battery_volts / 10)); // Cap the allowed discharge power if higher than the maximum discharge power allowed - if (datalayer.battery.status.max_discharge_power_W > MAXDISCHARGEPOWERALLOWED) { - datalayer.battery.status.max_discharge_power_W = MAXDISCHARGEPOWERALLOWED; + if (datalayer.battery.status.max_discharge_power_W > datalayer.battery.status.override_discharge_power_W) { + datalayer.battery.status.max_discharge_power_W = datalayer.battery.status.override_discharge_power_W; } //The allowed charge power behaves strangely. We instead estimate this value @@ -649,7 +649,7 @@ void TeslaBattery:: } } } else { // No limits, max charging power allowed - datalayer.battery.status.max_charge_power_W = MAXCHARGEPOWERALLOWED; + datalayer.battery.status.max_charge_power_W = datalayer.battery.status.override_charge_power_W; } datalayer.battery.status.temperature_min_dC = battery_min_temp; diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 6276cf3c..0bf4037f 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -39,15 +39,6 @@ class TeslaBattery : public CanBattery { TeslaHtmlRenderer renderer; protected: - /* Modify these if needed */ - static const int MAXCHARGEPOWERALLOWED = - 15000; // 15000W we use a define since the value supplied by Tesla is always 0 - static const int MAXDISCHARGEPOWERALLOWED = - 60000; // 60000W we use a define since the value supplied by Tesla is always 0 - - // Set this to true to try to close contactors/full startup even with no inverter defined/connected - bool batteryTestOverride = false; - /* Do not change anything below this line! */ static const int RAMPDOWN_SOC = 900; // 90.0 SOC% to start ramping down from max charge power towards 0 at 100.00% static const int RAMPDOWNPOWERALLOWED = 10000; // What power we ramp down from towards top balancing diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index df9cae1b..e433a064 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -156,6 +156,10 @@ void init_stored_settings() { datalayer.system.info.SD_logging_active = settings.getBool("SDLOGENABLED", false); datalayer.battery.status.led_mode = (led_mode_enum)settings.getUInt("LEDMODE", false); + //Some early integrations need manually set allowed charge/discharge power + datalayer.battery.status.override_charge_power_W = settings.getUInt("CHGPOWER", 1000); + datalayer.battery.status.override_discharge_power_W = settings.getUInt("DCHGPOWER", 1000); + // WIFI AP is enabled by default unless disabled in the settings wifiap_enabled = settings.getBool("WIFIAPENABLED", true); wifi_channel = settings.getUInt("WIFICHANNEL", 2000); diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index e9ffc8af..8c152325 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -69,6 +69,13 @@ struct DATALAYER_BATTERY_STATUS_TYPE { /** Instantaneous battery current in deciAmpere. 95 = 9.5 A */ int16_t current_dA; + /* Some early integrations do not support reading allowed charge power from battery + On these integrations we need to have the user specify what limits the battery can take */ + /** Overriden allowed battery discharge power in Watts. Set by user */ + uint32_t override_discharge_power_W = 0; + /** Overriden allowed battery charge power in Watts. Set by user */ + uint32_t override_charge_power_W = 0; + /** uint16_t */ /** State of health in integer-percent x 100. 9900 = 99.00% */ uint16_t soh_pptt = 9900; diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 63411805..64ee9cda 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -299,6 +299,14 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return String(settings.getUInt("WIFICHANNEL", 0)); } + if (var == "CHGPOWER") { + return String(settings.getUInt("CHGPOWER", 0)); + } + + if (var == "DCHGPOWER") { + return String(settings.getUInt("DCHGPOWER", 0)); + } + if (var == "LOCALIP1") { return String(settings.getUInt("LOCALIP1", 0)); } @@ -869,6 +877,17 @@ const char* getCANInterfaceName(CAN_Interface interface) { display: contents; } + form .if-estimated { display: none; } /* Integrations with manually set charge/discharge power */ + form[data-battery="3"] .if-estimated, + form[data-battery="4"] .if-estimated, + form[data-battery="6"] .if-estimated, + form[data-battery="14"] .if-estimated, + form[data-battery="24"] .if-estimated, + form[data-battery="32"] .if-estimated, + form[data-battery="33"] .if-estimated { + display: contents; + } + form .if-dblbtr { display: none; } form[data-dblbtr="true"] .if-dblbtr { display: contents; @@ -963,6 +982,14 @@ const char* getCANInterfaceName(CAN_Interface interface) {
+
+ + + + + +
+
- + + + + + + + diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 1236199d..74599e62 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -509,6 +509,8 @@ void init_webserver() { } else if (p->name() == "SUBNET4") { auto type = atoi(p->value().c_str()); settings.saveUInt("SUBNET4", type); + } else if (p->name() == "APPASSWORD") { + settings.saveString("APPASSWORD", p->value().c_str()); } else if (p->name() == "HOSTNAME") { settings.saveString("HOSTNAME", p->value().c_str()); } else if (p->name() == "MQTTSERVER") { From f609427e00f43ff23ec95a659c322a2b6887d07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 9 Sep 2025 20:45:44 +0300 Subject: [PATCH 073/150] Make Zoe2 double-battery possible --- Software/src/battery/BATTERIES.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index f4639e26..ab380b56 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -268,9 +268,15 @@ void setup_battery() { case BatteryType::RenaultZoe1: battery2 = new RenaultZoeGen1Battery(&datalayer.battery2, nullptr, can_config.battery_double); break; + case BatteryType::RenaultZoe2: + battery2 = new RenaultZoeGen2Battery(&datalayer.battery2, nullptr, can_config.battery_double); + break; case BatteryType::TestFake: battery2 = new TestFakeBattery(&datalayer.battery2, can_config.battery_double); break; + default: + DEBUG_PRINTF("User tried enabling double battery on non-supported integration!\n"); + break; } if (battery2) { From 5f73a4c32bbd43412ec5d08331a011063426aab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 9 Sep 2025 20:46:31 +0300 Subject: [PATCH 074/150] Update version number --- Software/Software.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index a2d045e9..681f222c 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.0.RC8"; +const char* version_number = "9.0.RC9experimental"; // Interval timers volatile unsigned long currentMillis = 0; From fc109cd954545a86659605a2d2c68b3863e9be3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 9 Sep 2025 21:08:07 +0300 Subject: [PATCH 075/150] Add Rivian battery support --- Software/src/battery/BATTERIES.cpp | 8 +- Software/src/battery/BATTERIES.h | 1 + Software/src/battery/Battery.h | 1 + Software/src/battery/RIVIAN-BATTERY.cpp | 177 ++++++++++++++++++++++++ Software/src/battery/RIVIAN-BATTERY.h | 60 ++++++++ 5 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 Software/src/battery/RIVIAN-BATTERY.cpp create mode 100644 Software/src/battery/RIVIAN-BATTERY.h diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index f4639e26..a58c1062 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -116,6 +116,8 @@ const char* name_for_battery_type(BatteryType type) { return RenaultZoeGen1Battery::Name; case BatteryType::RenaultZoe2: return RenaultZoeGen2Battery::Name; + case BatteryType::RivianBattery: + return RivianBattery::Name; case BatteryType::SamsungSdiLv: return SamsungSdiLVBattery::Name; case BatteryType::SantaFePhev: @@ -137,11 +139,7 @@ const char* name_for_battery_type(BatteryType type) { } } -#ifdef LFP_CHEMISTRY -const battery_chemistry_enum battery_chemistry_default = battery_chemistry_enum::LFP; -#else const battery_chemistry_enum battery_chemistry_default = battery_chemistry_enum::NMC; -#endif battery_chemistry_enum user_selected_battery_chemistry = battery_chemistry_default; @@ -216,6 +214,8 @@ Battery* create_battery(BatteryType type) { return new RenaultZoeGen1Battery(); case BatteryType::RenaultZoe2: return new RenaultZoeGen2Battery(); + case BatteryType::RivianBattery: + return new RivianBattery(); case BatteryType::SamsungSdiLv: return new SamsungSdiLVBattery(); case BatteryType::SantaFePhev: diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 84ebbe87..0324c189 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -44,6 +44,7 @@ void setup_can_shunt(); #include "RENAULT-TWIZY.h" #include "RENAULT-ZOE-GEN1-BATTERY.h" #include "RENAULT-ZOE-GEN2-BATTERY.h" +#include "RIVIAN-BATTERY.h" #include "RJXZS-BMS.h" #include "SAMSUNG-SDI-LV-BATTERY.h" #include "SANTA-FE-PHEV-BATTERY.h" diff --git a/Software/src/battery/Battery.h b/Software/src/battery/Battery.h index 0b99f588..c929519f 100644 --- a/Software/src/battery/Battery.h +++ b/Software/src/battery/Battery.h @@ -47,6 +47,7 @@ enum class BatteryType { HyundaiIoniq28 = 39, Kia64FD = 40, RelionBattery = 41, + RivianBattery = 42, Highest }; diff --git a/Software/src/battery/RIVIAN-BATTERY.cpp b/Software/src/battery/RIVIAN-BATTERY.cpp new file mode 100644 index 00000000..4492710b --- /dev/null +++ b/Software/src/battery/RIVIAN-BATTERY.cpp @@ -0,0 +1,177 @@ +#include "RIVIAN-BATTERY.h" + +#include "../battery/BATTERIES.h" +#include "../communication/can/comm_can.h" +#include "../datalayer/datalayer.h" +#include "../devboard/utils/events.h" + +/* +Initial support for Rivian BIG battery (135kWh) +The battery has 3x CAN channels +- Failover CAN (CAN-FD) lots of content, not required for operation +- Platform CAN (500kbps) with all the control messages needed to control the battery <- This is the one we want +- Battery CAN (500kbps) lots of content, not required for operation +*/ + +void RivianBattery::update_values() { + + datalayer.battery.status.real_soc = battery_SOC; + + datalayer.battery.status.soh_pptt; + + datalayer.battery.status.voltage_dV = battery_voltage; + datalayer.battery.status.current_dA = ((int16_t)battery_current / 10.0 - 3200) * 10; + + datalayer.battery.info.total_capacity_Wh = kWh_available_total * 5; + datalayer.battery.status.remaining_capacity_Wh = kWh_available_max * 5; + + //static lower limits for testing + // datalayer.battery.info.total_capacity_Wh = 10000; + // datalayer.battery.status.remaining_capacity_Wh = 9800; + + datalayer.battery.status.max_charge_power_W = ((battery_voltage / 10) * ((battery_charge_limit_amp / 20))); + datalayer.battery.status.max_discharge_power_W = + (abs((battery_voltage / 10) * ((battery_discharge_limit_amp / 20) - 3276.75))); + + //static lower limits for testing + // datalayer.battery.status.max_charge_power_W = 2000; + // datalayer.battery.status.max_discharge_power_W = 3000; + + datalayer.battery.status.cell_min_voltage_mV = 3700 - BMS_state; + datalayer.battery.status.cell_max_voltage_mV = 3700; + + datalayer.battery.status.temperature_min_dC = battery_min_temperature * 10; + datalayer.battery.status.temperature_max_dC = battery_max_temperature * 10; +} + +void RivianBattery::handle_incoming_can_frame(CAN_frame rx_frame) { + switch (rx_frame.ID) { + case 0x160: //Current [Platform CAN]+ + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_current = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + break; + case 0x151: //Celltemps (requires other CAN channel) + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x120: //Voltages [Platform CAN]+ + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_voltage = (((rx_frame.data.u8[7] & 0x1F) << 8) | rx_frame.data.u8[6]); + break; + case 0x25A: //SOC and kWh [Platform CAN]+ + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + //battery_SOC = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); + kWh_available_max = ((uint32_t)((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | + (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) & + 0b11111111111111110000000000) >> + 10; + kWh_available_total = ((uint32_t)((rx_frame.data.u8[6] << 24) | (rx_frame.data.u8[5] << 16) | + (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[3]) & + 0b111111111111111100) >> + 2; + ; + break; + case 0x405: //State [Platform CAN]+ + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + BMS_state = (rx_frame.data.u8[0] & 0x03); + break; + case 0x100: //Discharge/Charge speed (Not visible on Platform-CAN?) + battery_charge_limit_amp = ((uint32_t)((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | + (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) & + 0b1111111111111111000000000000) >> + 12; + battery_discharge_limit_amp = + ((uint32_t)((rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[3]) & + 0b11111111111111110000) >> + 4; + break; + case 0x153: //Temperatures (Not visible on Platform-CAN?)+ + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_max_temperature = (rx_frame.data.u8[5] / 2) - 40; + battery_min_temperature = (rx_frame.data.u8[6] / 2) - 40; + break; + case 0x55B: //Temperatures (Not visible on Platform-CAN?)+ + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_SOC = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + default: + break; + } +} + +void RivianBattery::transmit_can(unsigned long currentMillis) { + // Send 500ms CAN Message, too fast and the pack can't change states (pre-charge is built in, seems we can't change state during pre-charge) + // 100ms seems to draw too much current for a 5A supply during contactor pull in + if (currentMillis - previousMillis10 >= (INTERVAL_200_MS)) { + previousMillis10 = currentMillis; + + //If we want to close contactors, and preconditions are met + if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { + //Standby -> Ready Mode + if (BMS_state == STANDBY || BMS_state == SLEEP) { + RIVIAN_150.data.u8[0] = 0x03; + RIVIAN_150.data.u8[2] = 0x01; + RIVIAN_420.data.u8[0] = 0x02; + RIVIAN_200.data.u8[0] = 0x08; + + transmit_can_frame(&RIVIAN_150); + transmit_can_frame(&RIVIAN_420); + transmit_can_frame(&RIVIAN_41F); + transmit_can_frame(&RIVIAN_207); + transmit_can_frame(&RIVIAN_200); + } + //Ready mode -> Go Mode + + if (BMS_state == READY) { + RIVIAN_150.data.u8[0] = 0x3E; + RIVIAN_150.data.u8[2] = 0x03; + RIVIAN_420.data.u8[0] = 0x03; + + transmit_can_frame(&RIVIAN_150); + transmit_can_frame(&RIVIAN_420); + } + + } else { //If we want to open contactors, transition the other way + //Go mode -> Ready Mode + + if (BMS_state == GO) { + RIVIAN_150.data.u8[0] = 0x03; + RIVIAN_150.data.u8[2] = 0x01; + + transmit_can_frame(&RIVIAN_150); + } + + if (BMS_state == READY) { + RIVIAN_150.data.u8[0] = 0x03; + RIVIAN_150.data.u8[2] = 0x01; + RIVIAN_420.data.u8[0] = 0x01; + RIVIAN_200.data.u8[0] = 0x10; + + transmit_can_frame(&RIVIAN_245); + transmit_can_frame(&RIVIAN_150); + transmit_can_frame(&RIVIAN_420); + transmit_can_frame(&RIVIAN_41F); + transmit_can_frame(&RIVIAN_200); + } + } + //disabled this because the battery didn't like it so fast (slowed to 100ms) and because the battery couldn't change states fast enough + //as much as I don't like the "free-running" aspect of it, checking the BMS_state and acting on it should fix issues caused by that. + //transmit_can_frame(&RIVIAN_150); + //transmit_can_frame(&RIVIAN_420); + //transmit_can_frame(&RIVIAN_41F); + //transmit_can_frame(&RIVIAN_207); + //transmit_can_frame(&RIVIAN_200); + } +} + +void RivianBattery::setup(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, Name, 63); + datalayer.system.info.battery_protocol[63] = '\0'; + datalayer.battery.info.number_of_cells = 108; + datalayer.battery.info.total_capacity_Wh = 135000; + datalayer.battery.info.chemistry = NMC; + 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.system.status.battery_allows_contactor_closing = true; +} diff --git a/Software/src/battery/RIVIAN-BATTERY.h b/Software/src/battery/RIVIAN-BATTERY.h new file mode 100644 index 00000000..d74acb65 --- /dev/null +++ b/Software/src/battery/RIVIAN-BATTERY.h @@ -0,0 +1,60 @@ +#ifndef RIVIAN_BATTERY_H +#define RIVIAN_BATTERY_H +#include "CanBattery.h" + +class RivianBattery : public CanBattery { + public: + virtual void setup(void); + virtual void handle_incoming_can_frame(CAN_frame rx_frame); + virtual void update_values(); + virtual void transmit_can(unsigned long currentMillis); + static constexpr const char* Name = "Rivian R1T large 135kWh battery"; + + private: + static const int MAX_PACK_VOLTAGE_DV = 4480; + static const int MIN_PACK_VOLTAGE_DV = 2920; + static const int MAX_CELL_DEVIATION_MV = 150; + static const int MAX_CELL_VOLTAGE_MV = 4200; //Battery is put into emergency stop if one cell goes over this value + static const int MIN_CELL_VOLTAGE_MV = 3300; //Battery is put into emergency stop if one cell goes below this value + + uint8_t BMS_state = 0; + uint16_t battery_voltage = 3700; + uint16_t battery_SOC = 5000; + int32_t battery_current = 0; + uint16_t kWh_available_total = 135; + uint16_t kWh_available_max = 135; + int16_t battery_min_temperature = 0; + int16_t battery_max_temperature = 0; + uint16_t battery_discharge_limit_amp = 0; + uint16_t battery_charge_limit_amp = 0; + static const uint8_t SLEEP = 0; + static const uint8_t STANDBY = 1; + static const uint8_t READY = 2; + static const uint8_t GO = 3; + unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent + + CAN_frame RIVIAN_150 = {.FD = false, + .ext_ID = false, + .DLC = 6, + .ID = 0x150, + .data = {0x03, 0x00, 0x01, 0x00, 0x01, 0x00}}; + CAN_frame RIVIAN_420 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x420, + .data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame RIVIAN_41F = {.FD = false, .ext_ID = false, .DLC = 3, .ID = 0x41F, .data = {0x62, 0x10, 0x00}}; + CAN_frame RIVIAN_245 = {.FD = false, + .ext_ID = false, + .DLC = 6, + .ID = 0x245, + .data = {0x10, 0x00, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame RIVIAN_200 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x200, .data = {0x08}}; + CAN_frame RIVIAN_207 = {.FD = false, + .ext_ID = false, + .DLC = 1, + .ID = 0x207, + .data = {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}}; +}; + +#endif From ac153ec901ab9cb644bad02a3764c4141e87d6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 9 Sep 2025 21:15:35 +0300 Subject: [PATCH 076/150] Simplify capacity calculation and initial values --- Software/src/battery/RIVIAN-BATTERY.cpp | 4 ++-- Software/src/battery/RIVIAN-BATTERY.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/RIVIAN-BATTERY.cpp b/Software/src/battery/RIVIAN-BATTERY.cpp index 4492710b..d0f5ce75 100644 --- a/Software/src/battery/RIVIAN-BATTERY.cpp +++ b/Software/src/battery/RIVIAN-BATTERY.cpp @@ -22,8 +22,8 @@ void RivianBattery::update_values() { datalayer.battery.status.voltage_dV = battery_voltage; datalayer.battery.status.current_dA = ((int16_t)battery_current / 10.0 - 3200) * 10; - datalayer.battery.info.total_capacity_Wh = kWh_available_total * 5; - datalayer.battery.status.remaining_capacity_Wh = kWh_available_max * 5; + datalayer.battery.status.remaining_capacity_Wh = static_cast( + (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); //static lower limits for testing // datalayer.battery.info.total_capacity_Wh = 10000; diff --git a/Software/src/battery/RIVIAN-BATTERY.h b/Software/src/battery/RIVIAN-BATTERY.h index d74acb65..156ad84a 100644 --- a/Software/src/battery/RIVIAN-BATTERY.h +++ b/Software/src/battery/RIVIAN-BATTERY.h @@ -20,7 +20,7 @@ class RivianBattery : public CanBattery { uint8_t BMS_state = 0; uint16_t battery_voltage = 3700; uint16_t battery_SOC = 5000; - int32_t battery_current = 0; + int32_t battery_current = 32000; uint16_t kWh_available_total = 135; uint16_t kWh_available_max = 135; int16_t battery_min_temperature = 0; From 521ab481d7b4443a36638e0c5ab634fc7b5eb1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 9 Sep 2025 21:25:20 +0300 Subject: [PATCH 077/150] Add Rivian to tests --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 91bcbd9d..e00fd2b9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -128,6 +128,7 @@ add_executable(tests ../Software/src/battery/RENAULT-TWIZY.cpp ../Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp ../Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp + ../Software/src/battery/RIVIAN-BATTERY.cpp ../Software/src/battery/RJXZS-BMS.cpp ../Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp ../Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp From 8ba6a04d610c887c5c4ad383abe3665b822b574c Mon Sep 17 00:00:00 2001 From: Jonny Date: Tue, 9 Sep 2025 21:16:52 +0100 Subject: [PATCH 078/150] Use ths correct chip ID for the T-2CAN factory image --- .github/workflows/release-assets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml index d707ae14..3d9b84d3 100644 --- a/.github/workflows/release-assets.yml +++ b/.github/workflows/release-assets.yml @@ -64,7 +64,7 @@ jobs: - name: 🛠 Build factory image for Lilygo 2-CAN run: | - esptool --chip esp32 merge-bin -o .pio/build/lilygo_2CAN_330/factory.bin --flash-mode dio --flash-freq 40m --flash-size 4MB 0x1000 .pio/build/lilygo_2CAN_330/bootloader.bin 0x8000 .pio/build/lilygo_2CAN_330/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/lilygo_2CAN_330/firmware.bin + esptool --chip esp32s3 merge-bin -o .pio/build/lilygo_2CAN_330/factory.bin --flash-mode dio --flash-freq 40m --flash-size 4MB 0x1000 .pio/build/lilygo_2CAN_330/bootloader.bin 0x8000 .pio/build/lilygo_2CAN_330/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/lilygo_2CAN_330/firmware.bin mv .pio/build/lilygo_2CAN_330/factory.bin output/BE_${{ steps.vars.outputs.tag }}_LilygoT-2CAN.factory.bin - name: 🛠 Build ota image for Stark From 2e859a1ee69e0415bf7bd711af9ead192a7e83be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 10 Sep 2025 21:01:13 +0300 Subject: [PATCH 079/150] Correct shifting of amp limits --- Software/src/battery/RIVIAN-BATTERY.cpp | 31 +++++++------------------ 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/Software/src/battery/RIVIAN-BATTERY.cpp b/Software/src/battery/RIVIAN-BATTERY.cpp index d0f5ce75..b333523b 100644 --- a/Software/src/battery/RIVIAN-BATTERY.cpp +++ b/Software/src/battery/RIVIAN-BATTERY.cpp @@ -8,7 +8,7 @@ /* Initial support for Rivian BIG battery (135kWh) The battery has 3x CAN channels -- Failover CAN (CAN-FD) lots of content, not required for operation +- Failover CAN (CAN-FD) lots of content, not required for operation. Has all cellvoltages! - Platform CAN (500kbps) with all the control messages needed to control the battery <- This is the one we want - Battery CAN (500kbps) lots of content, not required for operation */ @@ -25,17 +25,8 @@ void RivianBattery::update_values() { datalayer.battery.status.remaining_capacity_Wh = static_cast( (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); - //static lower limits for testing - // datalayer.battery.info.total_capacity_Wh = 10000; - // datalayer.battery.status.remaining_capacity_Wh = 9800; - - datalayer.battery.status.max_charge_power_W = ((battery_voltage / 10) * ((battery_charge_limit_amp / 20))); - datalayer.battery.status.max_discharge_power_W = - (abs((battery_voltage / 10) * ((battery_discharge_limit_amp / 20) - 3276.75))); - - //static lower limits for testing - // datalayer.battery.status.max_charge_power_W = 2000; - // datalayer.battery.status.max_discharge_power_W = 3000; + datalayer.battery.status.max_charge_power_W = ((battery_voltage / 10) * battery_charge_limit_amp); + datalayer.battery.status.max_discharge_power_W = ((battery_voltage / 10) * battery_discharge_limit_amp); datalayer.battery.status.cell_min_voltage_mV = 3700 - BMS_state; datalayer.battery.status.cell_max_voltage_mV = 3700; @@ -74,22 +65,18 @@ void RivianBattery::handle_incoming_can_frame(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; BMS_state = (rx_frame.data.u8[0] & 0x03); break; - case 0x100: //Discharge/Charge speed (Not visible on Platform-CAN?) - battery_charge_limit_amp = ((uint32_t)((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | - (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) & - 0b1111111111111111000000000000) >> - 12; + case 0x100: //Discharge/Charge speed + battery_charge_limit_amp = + (((rx_frame.data.u8[3] & 0x0F) << 8) | (rx_frame.data.u8[2] << 4) | (rx_frame.data.u8[1] >> 4)) / 20; battery_discharge_limit_amp = - ((uint32_t)((rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[3]) & - 0b11111111111111110000) >> - 4; + (((rx_frame.data.u8[5] & 0x0F) << 8) | (rx_frame.data.u8[4] << 4) | (rx_frame.data.u8[3] >> 4)) / 20; break; - case 0x153: //Temperatures (Not visible on Platform-CAN?)+ + case 0x153: //Temperatures datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_max_temperature = (rx_frame.data.u8[5] / 2) - 40; battery_min_temperature = (rx_frame.data.u8[6] / 2) - 40; break; - case 0x55B: //Temperatures (Not visible on Platform-CAN?)+ + case 0x55B: //Temperatures datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_SOC = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; From 62d0d59e74ebfe42bd537ace41db4ad0ba5be371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 10 Sep 2025 21:13:38 +0300 Subject: [PATCH 080/150] Simplify CAN writing --- Software/src/battery/RIVIAN-BATTERY.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Software/src/battery/RIVIAN-BATTERY.cpp b/Software/src/battery/RIVIAN-BATTERY.cpp index b333523b..8b4c429b 100644 --- a/Software/src/battery/RIVIAN-BATTERY.cpp +++ b/Software/src/battery/RIVIAN-BATTERY.cpp @@ -28,8 +28,8 @@ void RivianBattery::update_values() { datalayer.battery.status.max_charge_power_W = ((battery_voltage / 10) * battery_charge_limit_amp); datalayer.battery.status.max_discharge_power_W = ((battery_voltage / 10) * battery_discharge_limit_amp); - datalayer.battery.status.cell_min_voltage_mV = 3700 - BMS_state; - datalayer.battery.status.cell_max_voltage_mV = 3700; + //datalayer.battery.status.cell_min_voltage_mV = 3700; //TODO: Take from failover CAN? + //datalayer.battery.status.cell_max_voltage_mV = 3700; //TODO: Take from failover CAN? datalayer.battery.status.temperature_min_dC = battery_min_temperature * 10; datalayer.battery.status.temperature_max_dC = battery_max_temperature * 10; @@ -51,15 +51,10 @@ void RivianBattery::handle_incoming_can_frame(CAN_frame rx_frame) { case 0x25A: //SOC and kWh [Platform CAN]+ datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //battery_SOC = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); - kWh_available_max = ((uint32_t)((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | - (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) & - 0b11111111111111110000000000) >> - 10; - kWh_available_total = ((uint32_t)((rx_frame.data.u8[6] << 24) | (rx_frame.data.u8[5] << 16) | - (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[3]) & - 0b111111111111111100) >> - 2; - ; + kWh_available_max = + (((rx_frame.data.u8[3] & 0x03) << 14) | (rx_frame.data.u8[2] << 6) | (rx_frame.data.u8[1] >> 2)) / 200; + kWh_available_total = + (((rx_frame.data.u8[5] & 0x03) << 14) | (rx_frame.data.u8[4] << 6) | (rx_frame.data.u8[3] >> 2)) / 200; break; case 0x405: //State [Platform CAN]+ datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; From c7b6d0adee3fc13a56d4a3a128d8b2471b18200b Mon Sep 17 00:00:00 2001 From: Jonny Date: Thu, 11 Sep 2025 16:34:24 +0100 Subject: [PATCH 081/150] Change bootloader offset (and flash config) for T-2CAN --- .github/workflows/release-assets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml index 3d9b84d3..1e433b97 100644 --- a/.github/workflows/release-assets.yml +++ b/.github/workflows/release-assets.yml @@ -64,7 +64,7 @@ jobs: - name: 🛠 Build factory image for Lilygo 2-CAN run: | - esptool --chip esp32s3 merge-bin -o .pio/build/lilygo_2CAN_330/factory.bin --flash-mode dio --flash-freq 40m --flash-size 4MB 0x1000 .pio/build/lilygo_2CAN_330/bootloader.bin 0x8000 .pio/build/lilygo_2CAN_330/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/lilygo_2CAN_330/firmware.bin + esptool --chip esp32s3 merge-bin -o .pio/build/lilygo_2CAN_330/factory.bin --flash-mode qio --flash-freq 80m --flash-size 4MB 0x0000 .pio/build/lilygo_2CAN_330/bootloader.bin 0x8000 .pio/build/lilygo_2CAN_330/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/lilygo_2CAN_330/firmware.bin mv .pio/build/lilygo_2CAN_330/factory.bin output/BE_${{ steps.vars.outputs.tag }}_LilygoT-2CAN.factory.bin - name: 🛠 Build ota image for Stark From a2a00a488fd4d954c03d2acabe0539a0d7e6471a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 11 Sep 2025 18:38:29 +0300 Subject: [PATCH 082/150] Update CONTRIBUTING.md --- CONTRIBUTING.md | 64 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b303cd06..14e85c18 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ ### Contributing to the Battery-Emulator project -What can I do? +What can I do? 🦸 -------------- **"Help - I want to contribute something, but I don't know what?"** @@ -15,10 +15,66 @@ You're in luck. There's various sources to contribute: - [Discussion page](https://github.com/dalathegreat/Battery-Emulator/discussions) - [Discord server](https://www.patreon.com/dala) -## Notes on embedded system +## Notes on embedded system 🕙 The Battery-Emulator is a real-time control system, which performs lots of time critical operations. Some operations, like contactor control, need to complete within 10 milliseconds periodically. The resources of the ESP32 microcontroller is limited, so keeping track of CPU and memory usage is essential. Keep this in mind when coding for the system! Performance profiling the system can be done by enabling the "Enable performance profiling:" option in the webserver -## Code formatting +## Setting up the compilation environment (VScode + PlatformIO) 💻 + +This project uses the PlatformIO extension within Visual Studio Code for development and uploading. It handles all the complex toolchains and library management for you. +### 1. Installing VSCode +- Download the stable build of Visual Studio Code for your operating system (Windows, macOS, or Linux) from the official website: https://code.visualstudio.com/ +- Run the installer and follow the setup instructions. +- (Recommended) Launch VSCode after installation. + +### 2. Installing the PlatformIO IDE Plugin + +PlatformIO is an extension that adds all the necessary functionality to VSCode. + - Inside VSCode, open the Extensions view by: + - Clicking the Extensions icon in the Activity Bar on the left side. + - Or using the keyboard shortcut: Ctrl+Shift+X (Windows/Linux) or Cmd+Shift+X (macOS). + - In the extensions search bar, type: PlatformIO IDE. + - Find the extension published by PlatformIO and click the Install button. +- Wait for the installation to complete. This may take a few minutes as PlatformIO downloads and installs its core tools in the background. VSCode might require a reload once finished. + +### 3. Opening the Project and Building +- Clone the repository to your local machine using Git. +- In VSCode: + - Go to File > Open Folder... + - Navigate to and select the root folder of the cloned project (the folder containing the platformio.ini file). + - Click Open. +- PlatformIO will automatically recognize the project structure and begin indexing the code. You'll see the PlatformIO icon (a grey alien) appear in the Activity Bar on the left. + +- To verify everything is set up correctly, build/compile the project: + - Click the PlatformIO icon in the Activity Bar to open the PIO Home screen. + - Go to Quick Access > PIO > Build. + - Alternatively, you can use the checkmark icon in the blue status bar at the bottom of the VSCode window, or the keyboard shortcut Ctrl+Alt+B (Windows/Linux) / Cmd+Alt+B (macOS). + - The build process will start. You can monitor the output in the integrated terminal. A successful build will end with ===== [SUCCESS] Took X.XX seconds =====. + +### 4. Uploading Code to Board via USB + +- Connect your Battery-Emulator hardware to your computer using a USB cable. +- Select the right board type (Stark, LilyGo) +- At the bottom left of VScode, click the Env to bring up a menu of boards. Select the board you are using +image +image + +- Ensure the correct upload port is set in the platformio.ini file (it's often auto-detected, but you may need to set it manually. See Troubleshooting below). +- Upload the code: + - Click the PlatformIO icon in the Activity Bar. + - Go to Quick Access > PIO > Upload. + - Alternatively, use the right-arrow icon (→) in the blue status bar at the bottom of the VSCode window, or the keyboard shortcut Ctrl+Alt+U (Windows/Linux) / Cmd+Alt+U (macOS). +- The upload process will begin. The board may reset automatically. A successful upload will end with ===== [SUCCESS] Took X.XX seconds =====. + +### ⚠️ Troubleshooting & Tips + +#### "Upload port not found" or wrong port errors: + +- Find the correct port: + - Windows: Check Device Manager under "Ports (COM & LPT)". It's usually COM3, COM4, etc. + - macOS/Linux: Run ls /dev/tty.* or ls /dev/ttyUSB* in a terminal. It's often /dev/tty.usbserial-XXX or /dev/ttyUSB0. +- Add the line upload_port = COM4 (replace COM4 with your port) to your platformio.ini file in the [env:...] section. + +## Code formatting 📜 The project enforces a specific code formatting in the workflows. To get your code formatted properly, it is easiest to use a pre-commit hook before pushing the code to a pull request. Before you begin, make sure you have installed Python on the system! @@ -39,7 +95,7 @@ Or force it to check all files with pre-commit run --all-files ``` -## Local Unit test run +## Local Unit test run 🧪 The Unit tests run gtest. Here is how to install this on Debian/Ubuntu and run it locally ``` sudo apt-get install libgtest-dev From 5246cd34c93ec1af004666137002e8d597038356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 11 Sep 2025 20:32:11 +0300 Subject: [PATCH 083/150] Update Software.cpp --- Software/Software.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 681f222c..299b4eb2 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.0.RC9experimental"; +const char* version_number = "9.0.RC9"; // Interval timers volatile unsigned long currentMillis = 0; From b33f42c9c5d2f8186f90f98e4127eb8bff49de3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 11 Sep 2025 20:36:48 +0300 Subject: [PATCH 084/150] Update Software.cpp --- Software/Software.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 299b4eb2..95f25ed8 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.0.RC9"; +const char* version_number = "9.0.RC10experimental"; // Interval timers volatile unsigned long currentMillis = 0; From fd2e5f2e524c2183bc5f9d58f7b5a54ef1eb1396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 11 Sep 2025 21:30:56 +0300 Subject: [PATCH 085/150] Add start for MysteryVan More Info page --- Software/src/battery/ECMP-BATTERY.cpp | 9 ++++ Software/src/battery/ECMP-HTML.h | 52 +++++++++++++++++++++ Software/src/datalayer/datalayer_extended.h | 8 ++++ 3 files changed, 69 insertions(+) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 16f276ac..b2532f49 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -191,6 +191,15 @@ void EcmpBattery::update_values() { datalayer_extended.stellantisECMP.pid_contactor_closing_counter = pid_contactor_closing_counter; datalayer_extended.stellantisECMP.pid_date_of_manufacture = pid_date_of_manufacture; datalayer_extended.stellantisECMP.pid_SOH_cell_1 = pid_SOH_cell_1; + // Update extended datalayer for MysteryVan + datalayer_extended.stellantisECMP.MysteryVan = MysteryVan; + datalayer_extended.stellantisECMP.CrashMemorized = HV_BATT_CRASH_MEMORIZED; + datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON = CONTACTOR_OPENING_REASON; + datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE = TBMU_FAULT_TYPE; + datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_MINUS_RES = HV_BATT_FC_INSU_MINUS_RES; + datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_PLUS_RES = HV_BATT_FC_INSU_PLUS_RES; + datalayer_extended.stellantisECMP.HV_BATT_FC_VHL_INSU_PLUS_RES = HV_BATT_FC_VHL_INSU_PLUS_RES; + datalayer_extended.stellantisECMP.HV_BATT_ONLY_INSU_MINUS_RES = HV_BATT_ONLY_INSU_MINUS_RES; if (battery_InterlockOpen) { set_event(EVENT_HVIL_FAILURE, 0); diff --git a/Software/src/battery/ECMP-HTML.h b/Software/src/battery/ECMP-HTML.h index 96bd56c6..2c2b6cd8 100644 --- a/Software/src/battery/ECMP-HTML.h +++ b/Software/src/battery/ECMP-HTML.h @@ -383,6 +383,58 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer { : String(datalayer_extended.stellantisECMP.pid_SOH_cell_1)) + ""; + if (datalayer_extended.stellantisECMP.MysteryVan) { + content += "

MysteryVan platform detected:

"; + content += "

Crash Memorized: "; + if (datalayer_extended.stellantisECMP.CrashMemorized == 255) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Contactor Opening Reason: "; + if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 0) { + content += "No error"; + } else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 1) { + content += "Crash!"; + } else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 2) { + content += "12V supply source undervoltage"; + } else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 3) { + content += "12V supply source overvoltage"; + } else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 4) { + content += "Battery temperature"; + } else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 5) { + content += "Interlock line open"; + } else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 6) { + content += "e-Service plug disconnected"; + } + content += "

"; + content += "

Battery fault type: "; + if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 0) { + content += "No fault"; + } else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 1) { + content += "FirstLevelFault: Warning Lamp"; + } else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 2) { + content += "SecondLevelFault: Stop Lamp"; + } else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 3) { + content += "ThirdLevelFault: Stop Lamp + contactor opening (EPS shutdown)"; + } else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 4) { + content += "FourthLevelFault: Stop Lamp + Active Discharge"; + } else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 5) { + content += "Inhibition of powertrain activation"; + } else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 6) { + content += "Reserved"; + } + content += "

"; + content += "

FC insulation minus resistance " + + String(datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_MINUS_RES) + " kOhm

"; + content += "

FC insulation plus resistance " + + String(datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_PLUS_RES) + " kOhm

"; + content += "

FC vehicle insulation plus resistance " + + String(datalayer_extended.stellantisECMP.HV_BATT_FC_VHL_INSU_PLUS_RES) + " kOhm

"; + content += "

FC vehicle insulation plus resistance " + + String(datalayer_extended.stellantisECMP.HV_BATT_ONLY_INSU_MINUS_RES) + " kOhm

"; + } + return content; } }; diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index b982e10f..5756a05a 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -235,6 +235,14 @@ struct DATALAYER_INFO_CMFAEV { }; struct DATALAYER_INFO_ECMP { + //mysteryvan parameters + bool MysteryVan = false; + bool CrashMemorized = false; + uint8_t CONTACTOR_OPENING_REASON = 0; + uint8_t TBMU_FAULT_TYPE = 0; + uint16_t HV_BATT_FC_INSU_MINUS_RES, HV_BATT_FC_INSU_PLUS_RES, HV_BATT_FC_VHL_INSU_PLUS_RES, + HV_BATT_ONLY_INSU_MINUS_RES = 0; + //ecmp below uint8_t MainConnectorState = 0; uint16_t InsulationResistance = 0; uint8_t InsulationDiag = 0; From 29e6f52c4cac1f386f43433390e65bad21d08a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 11 Sep 2025 23:05:06 +0300 Subject: [PATCH 086/150] Add alerts to more battery info page --- Software/src/battery/ECMP-BATTERY.cpp | 12 ++++ Software/src/battery/ECMP-HTML.h | 71 ++++++++++++++++++++- Software/src/datalayer/datalayer_extended.h | 2 + 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index b2532f49..eb47aff9 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -200,6 +200,18 @@ void EcmpBattery::update_values() { datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_PLUS_RES = HV_BATT_FC_INSU_PLUS_RES; datalayer_extended.stellantisECMP.HV_BATT_FC_VHL_INSU_PLUS_RES = HV_BATT_FC_VHL_INSU_PLUS_RES; datalayer_extended.stellantisECMP.HV_BATT_ONLY_INSU_MINUS_RES = HV_BATT_ONLY_INSU_MINUS_RES; + datalayer_extended.stellantisECMP.HV_BATT_ONLY_INSU_MINUS_RES = HV_BATT_ONLY_INSU_MINUS_RES; + datalayer_extended.stellantisECMP.ALERT_CELL_POOR_CONSIST = ALERT_CELL_POOR_CONSIST; + datalayer_extended.stellantisECMP.ALERT_OVERCHARGE = ALERT_OVERCHARGE; + datalayer_extended.stellantisECMP.ALERT_BATT = ALERT_BATT; + datalayer_extended.stellantisECMP.ALERT_LOW_SOC = ALERT_LOW_SOC; + datalayer_extended.stellantisECMP.ALERT_HIGH_SOC = ALERT_HIGH_SOC; + datalayer_extended.stellantisECMP.ALERT_SOC_JUMP = ALERT_SOC_JUMP; + datalayer_extended.stellantisECMP.ALERT_TEMP_DIFF = ALERT_TEMP_DIFF; + datalayer_extended.stellantisECMP.ALERT_HIGH_TEMP = ALERT_HIGH_TEMP; + datalayer_extended.stellantisECMP.ALERT_OVERVOLTAGE = ALERT_OVERVOLTAGE; + datalayer_extended.stellantisECMP.ALERT_CELL_OVERVOLTAGE = ALERT_CELL_OVERVOLTAGE; + datalayer_extended.stellantisECMP.ALERT_CELL_UNDERVOLTAGE = ALERT_CELL_UNDERVOLTAGE; if (battery_InterlockOpen) { set_event(EVENT_HVIL_FAILURE, 0); diff --git a/Software/src/battery/ECMP-HTML.h b/Software/src/battery/ECMP-HTML.h index 2c2b6cd8..4b8da671 100644 --- a/Software/src/battery/ECMP-HTML.h +++ b/Software/src/battery/ECMP-HTML.h @@ -384,9 +384,9 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer { ""; if (datalayer_extended.stellantisECMP.MysteryVan) { - content += "

MysteryVan platform detected:

"; + content += "

MysteryVan platform detected!

"; content += "

Crash Memorized: "; - if (datalayer_extended.stellantisECMP.CrashMemorized == 255) { + if (datalayer_extended.stellantisECMP.CrashMemorized) { content += "Yes

"; } else { content += "No"; @@ -434,7 +434,72 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer { content += "

FC vehicle insulation plus resistance " + String(datalayer_extended.stellantisECMP.HV_BATT_ONLY_INSU_MINUS_RES) + " kOhm

"; } - + content += "

Alert Battery: "; + if (datalayer_extended.stellantisECMP.ALERT_BATT) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert Low SOC: "; + if (datalayer_extended.stellantisECMP.ALERT_LOW_SOC) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert High SOC: "; + if (datalayer_extended.stellantisECMP.ALERT_HIGH_SOC) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert SOC Jump: "; + if (datalayer_extended.stellantisECMP.ALERT_SOC_JUMP) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert Overcharge: "; + if (datalayer_extended.stellantisECMP.ALERT_OVERCHARGE) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert Temp Diff: "; + if (datalayer_extended.stellantisECMP.ALERT_TEMP_DIFF) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert Temp High: "; + if (datalayer_extended.stellantisECMP.ALERT_HIGH_TEMP) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert Overvoltage: "; + if (datalayer_extended.stellantisECMP.ALERT_OVERVOLTAGE) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert Cell Overvoltage: "; + if (datalayer_extended.stellantisECMP.ALERT_CELL_OVERVOLTAGE) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert Cell Undervoltage: "; + if (datalayer_extended.stellantisECMP.ALERT_CELL_UNDERVOLTAGE) { + content += "Yes

"; + } else { + content += "No"; + } + content += "

Alert Cell Poor Consistency: "; + if (datalayer_extended.stellantisECMP.ALERT_CELL_POOR_CONSIST) { + content += "Yes

"; + } else { + content += "No"; + } return content; } }; diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 5756a05a..ebd6fbc3 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -242,6 +242,8 @@ struct DATALAYER_INFO_ECMP { uint8_t TBMU_FAULT_TYPE = 0; uint16_t HV_BATT_FC_INSU_MINUS_RES, HV_BATT_FC_INSU_PLUS_RES, HV_BATT_FC_VHL_INSU_PLUS_RES, HV_BATT_ONLY_INSU_MINUS_RES = 0; + bool ALERT_CELL_POOR_CONSIST, ALERT_OVERCHARGE, ALERT_BATT, ALERT_LOW_SOC, ALERT_HIGH_SOC, ALERT_SOC_JUMP, + ALERT_TEMP_DIFF, ALERT_HIGH_TEMP, ALERT_OVERVOLTAGE, ALERT_CELL_OVERVOLTAGE, ALERT_CELL_UNDERVOLTAGE = false; //ecmp below uint8_t MainConnectorState = 0; uint16_t InsulationResistance = 0; From 0aad11d9bc7c47a96fd0eca977856e419542dd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 11 Sep 2025 23:27:15 +0300 Subject: [PATCH 087/150] Add contactor state to more battery info --- Software/src/battery/ECMP-BATTERY.cpp | 3 ++- Software/src/battery/ECMP-HTML.h | 11 ++++++++++- Software/src/datalayer/datalayer_extended.h | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index eb47aff9..ebcd0c27 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -193,6 +193,7 @@ void EcmpBattery::update_values() { datalayer_extended.stellantisECMP.pid_SOH_cell_1 = pid_SOH_cell_1; // Update extended datalayer for MysteryVan datalayer_extended.stellantisECMP.MysteryVan = MysteryVan; + datalayer_extended.stellantisECMP.CONTACTORS_STATE = CONTACTORS_STATE; datalayer_extended.stellantisECMP.CrashMemorized = HV_BATT_CRASH_MEMORIZED; datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON = CONTACTOR_OPENING_REASON; datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE = TBMU_FAULT_TYPE; @@ -268,7 +269,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { //TBMU_EVSE_DC_MES_CURRENT = (rx_frame.data.u8[3] << 4) | ((rx_frame.data.u8[4] & 0xF0) >> 4); //A -2000 - 2000 //Fastcharger info, not needed for BE //TBMU_EVSE_CHRG_REQ = (rx_frame.data.u8[4] & 0x0C) >> 2; //00 No request, 01 Stop request //Fastcharger info, not needed for BE //HV_STORAGE_MAX_I = ((rx_frame.data.u8[4] & 0x03) << 12) | (rx_frame.data.u8[5] << 2) | //Fastcharger info, not needed for BE - ((rx_frame.data.u8[6] & 0xC0) >> 6); //A -2000 - 2000 + //((rx_frame.data.u8[6] & 0xC0) >> 6); //A -2000 - 2000 //TBMU_EVSE_DC_MAX_POWER = ((rx_frame.data.u8[6] & 0x3F) << 8) | rx_frame.data.u8[7]; //W -1000000 - 0 //Fastcharger info, not needed for BE break; case 0x3F4: //MysteryVan 50/75kWh platform (Temperature sensors) diff --git a/Software/src/battery/ECMP-HTML.h b/Software/src/battery/ECMP-HTML.h index 4b8da671..0b177feb 100644 --- a/Software/src/battery/ECMP-HTML.h +++ b/Software/src/battery/ECMP-HTML.h @@ -384,7 +384,16 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer { ""; if (datalayer_extended.stellantisECMP.MysteryVan) { - content += "

MysteryVan platform detected!

"; + content += "

MysteryVan platform detected!

"; + content += "

Contactor State: "; + if (datalayer_extended.stellantisECMP.CONTACTORS_STATE == 0) { + content += "Open"; + } else if (datalayer_extended.stellantisECMP.CONTACTORS_STATE == 1) { + content += "Precharge"; + } else if (datalayer_extended.stellantisECMP.CONTACTORS_STATE == 2) { + content += "Closed"; + } + content += "

"; content += "

Crash Memorized: "; if (datalayer_extended.stellantisECMP.CrashMemorized) { content += "Yes

"; diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index ebd6fbc3..07406f6f 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -240,6 +240,7 @@ struct DATALAYER_INFO_ECMP { bool CrashMemorized = false; uint8_t CONTACTOR_OPENING_REASON = 0; uint8_t TBMU_FAULT_TYPE = 0; + uint8_t CONTACTORS_STATE = 0; uint16_t HV_BATT_FC_INSU_MINUS_RES, HV_BATT_FC_INSU_PLUS_RES, HV_BATT_FC_VHL_INSU_PLUS_RES, HV_BATT_ONLY_INSU_MINUS_RES = 0; bool ALERT_CELL_POOR_CONSIST, ALERT_OVERCHARGE, ALERT_BATT, ALERT_LOW_SOC, ALERT_HIGH_SOC, ALERT_SOC_JUMP, From 018cd4ed52cedf977449659ca1f4698baa65962b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 11 Sep 2025 23:48:55 +0300 Subject: [PATCH 088/150] Allocate less memory for ELEGANT_HTLM array --- Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp | 2 +- Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp b/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp index f7e4e712..4a00db1f 100644 --- a/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp +++ b/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp @@ -1,3 +1,3 @@ #include "elop.h" -const uint8_t ELEGANT_HTML[41354] PROGMEM = {31,139,8,0,128,47,232,102,0,255,237,125,249,127,219,70,146,239,207,201,231,147,255,1,102,54,50,25,1,16,78,94,18,157,181,157,120,226,93,59,206,139,237,204,225,104,178,16,9,146,136,65,130,3,144,58,44,115,254,246,253,86,117,55,46,66,18,229,57,118,223,123,195,19,232,163,186,186,174,174,238,46,0,39,15,38,201,120,125,181,10,181,249,122,17,63,250,226,243,19,250,215,226,96,57,27,181,194,101,11,41,154,118,50,15,131,9,31,225,120,17,174,3,109,60,15,210,44,92,143,90,111,223,60,51,250,45,237,168,146,187,12,22,225,168,117,30,133,23,171,36,93,183,180,113,178,92,135,75,148,190,136,38,235,249,104,18,158,71,227,208,224,19,93,139,150,209,58,10,98,35,27,7,113,56,178,77,171,4,109,29,173,227,240,209,147,96,189,14,211,43,237,187,197,38,14,214,73,170,189,122,243,88,123,187,154,4,235,240,228,72,20,1,222,217,56,141,86,107,28,197,225,90,139,147,96,18,45,103,223,70,231,111,194,203,181,54,210,90,47,68,138,105,154,173,227,47,62,15,178,171,229,88,155,110,150,227,117,148,44,209,157,112,252,94,129,127,189,14,214,155,236,167,240,44,73,214,237,142,118,253,197,231,159,161,3,217,90,67,131,1,64,5,23,65,180,214,102,225,250,91,156,183,31,30,253,46,92,63,139,210,197,69,144,134,207,151,211,228,97,7,240,63,139,166,90,155,202,139,250,159,129,200,155,5,72,96,162,218,119,113,72,135,79,174,158,79,218,15,167,178,230,207,97,154,1,147,135,29,115,13,132,159,10,130,161,49,130,97,170,66,4,248,102,80,96,201,132,145,248,182,25,138,202,103,40,217,58,89,73,146,124,55,13,199,232,40,39,167,33,184,250,51,24,135,243,207,240,66,218,86,11,227,44,20,221,56,58,42,152,176,76,214,90,178,140,163,101,168,107,239,195,112,165,17,89,0,142,161,135,235,55,209,34,76,54,235,246,141,164,213,53,199,178,172,206,177,6,160,79,169,144,22,204,130,104,9,121,208,28,45,11,65,242,73,70,205,127,241,249,22,168,229,172,202,214,65,186,174,98,126,43,133,91,41,183,134,210,198,34,204,178,96,22,182,106,212,169,202,202,237,52,46,128,145,76,3,221,48,5,177,199,113,144,101,47,162,108,109,166,225,34,57,15,193,139,104,50,9,193,205,219,161,73,189,168,64,8,38,229,102,94,9,24,32,66,137,0,117,206,221,46,97,119,161,204,13,126,58,190,170,199,183,163,12,158,9,174,255,30,66,34,48,222,85,81,81,162,80,82,165,118,209,185,77,50,124,19,86,217,102,60,6,103,159,38,241,102,33,187,32,21,240,1,85,45,225,42,9,144,21,253,149,234,89,146,215,29,249,210,53,155,229,116,127,185,246,85,249,29,217,133,209,249,158,91,126,74,56,85,141,203,29,189,92,165,201,12,218,89,233,102,94,211,185,173,102,192,141,103,79,54,235,53,254,184,166,50,80,251,145,71,227,38,204,108,125,21,135,230,36,202,86,113,112,53,122,120,22,39,227,247,15,171,6,162,185,228,50,89,134,92,80,144,67,96,157,156,101,97,122,30,166,192,124,25,94,104,47,55,32,33,208,124,37,147,219,32,206,232,145,228,78,157,108,36,94,244,83,133,244,12,35,73,54,227,113,1,188,219,7,110,93,44,21,220,218,232,160,76,125,26,130,217,209,121,248,99,176,158,51,101,52,109,141,97,137,15,52,26,228,128,12,88,180,194,65,152,143,19,211,112,61,158,87,171,162,5,170,64,28,80,197,205,228,125,7,40,49,90,13,131,77,94,236,183,44,89,2,79,178,153,63,210,8,92,180,23,100,218,127,188,126,245,131,48,226,235,77,186,100,8,82,10,53,109,171,141,3,32,162,181,195,52,77,82,137,189,6,56,212,90,2,110,113,122,251,225,51,66,87,227,147,225,67,93,28,40,132,37,220,229,38,142,57,69,242,243,34,90,78,146,11,19,99,1,180,6,40,23,20,166,145,88,141,58,218,168,245,13,43,53,37,170,1,77,165,225,131,30,189,70,78,160,173,133,130,105,201,20,138,167,6,2,173,77,74,104,105,139,40,142,35,153,6,130,21,116,87,181,4,215,127,76,147,5,138,181,219,191,234,192,250,55,104,49,227,36,42,208,171,164,200,2,93,81,170,77,149,191,19,148,248,41,252,203,38,148,144,39,26,74,66,29,132,45,176,100,203,66,147,152,138,218,79,193,56,212,206,194,245,69,24,230,2,163,5,203,137,182,158,135,10,57,81,75,226,102,166,168,209,126,119,139,27,161,171,122,167,178,61,122,153,128,183,100,207,66,18,89,101,40,137,202,157,142,114,6,189,254,110,46,200,222,128,239,225,144,148,225,109,201,156,144,28,11,117,248,116,223,169,37,133,157,69,236,211,28,167,26,8,86,37,137,101,153,41,172,91,162,104,110,93,254,22,188,37,227,255,54,204,203,64,10,172,25,34,190,205,14,224,167,143,69,202,10,155,242,128,7,23,93,187,214,224,188,167,209,217,102,29,102,67,152,203,13,188,197,60,229,89,20,195,177,31,106,239,30,242,32,244,240,84,226,183,223,184,214,48,238,55,15,5,101,148,156,79,67,137,236,220,209,17,77,85,32,186,233,123,109,19,125,241,121,142,152,58,144,216,213,124,171,22,85,104,17,16,12,152,65,252,26,238,2,156,80,210,99,154,36,113,38,242,78,142,242,249,11,207,124,196,153,70,51,179,81,107,145,76,54,113,136,121,84,154,100,89,146,70,179,104,137,114,109,53,64,193,159,18,20,155,142,114,156,198,105,136,233,145,196,168,221,130,155,14,28,224,172,197,132,215,113,52,109,79,15,14,166,102,182,89,209,12,45,43,31,183,101,115,43,20,134,124,180,58,29,97,247,143,167,176,138,162,157,128,140,115,222,20,204,100,122,245,58,140,33,68,73,250,56,142,219,15,169,181,119,168,174,48,87,160,78,97,66,39,237,160,115,220,56,50,7,163,71,215,69,27,99,106,35,232,0,211,177,201,84,24,141,90,227,121,20,79,168,3,173,78,81,48,162,130,99,34,117,56,249,33,153,132,89,39,50,215,193,236,7,154,131,162,206,139,231,63,252,103,235,224,32,162,190,211,121,21,163,131,131,73,59,234,108,59,133,136,200,94,233,215,121,99,195,7,150,158,109,206,214,105,24,226,16,226,80,248,115,232,139,36,253,120,116,189,61,150,3,100,96,70,208,194,89,26,173,175,14,14,128,126,126,54,42,229,116,244,0,40,77,97,51,194,244,199,36,142,198,162,108,53,9,21,170,9,84,139,165,224,21,75,1,117,104,147,133,6,184,13,239,136,166,209,89,235,155,49,49,95,157,142,90,209,114,28,111,38,97,107,184,83,51,128,99,118,181,72,54,187,117,48,66,173,91,195,90,98,6,138,26,66,250,90,250,120,155,83,129,56,122,13,62,5,102,184,82,178,66,199,163,7,214,177,34,14,81,234,88,184,66,176,251,232,147,62,238,108,183,29,24,157,6,165,0,106,172,22,31,63,62,104,183,56,9,157,192,148,190,40,216,57,56,144,94,199,130,44,239,203,112,18,5,237,86,27,92,5,177,50,76,116,226,36,197,130,2,85,29,178,194,118,32,252,92,52,204,190,201,121,188,159,226,234,55,206,44,41,255,37,36,142,103,175,103,201,37,218,224,89,65,56,65,215,59,195,125,218,145,179,167,191,169,41,187,115,124,159,122,232,218,119,231,40,64,237,135,152,12,182,91,99,72,214,251,150,94,50,39,159,128,199,189,201,122,163,53,252,36,202,53,65,139,163,217,28,166,162,172,177,143,219,113,231,90,170,105,124,112,16,155,191,254,26,102,232,16,76,194,193,193,171,51,242,1,77,140,110,235,132,76,14,28,148,236,213,197,18,14,219,42,76,215,87,24,229,97,220,98,189,53,9,167,193,38,6,228,111,98,83,30,15,227,237,121,144,106,47,70,215,225,37,91,209,225,245,118,171,95,86,78,143,203,6,155,74,195,62,62,126,242,244,219,239,158,253,238,251,231,255,241,159,47,94,254,240,234,199,255,243,211,235,55,111,127,254,253,31,254,248,167,224,108,12,216,179,121,244,219,251,120,177,76,86,127,73,179,245,230,252,226,242,234,131,101,59,174,231,119,123,253,193,225,17,184,54,186,6,190,241,48,135,157,233,147,188,139,217,201,201,228,99,246,232,209,35,215,49,38,91,29,5,211,27,11,82,17,46,139,130,225,18,10,181,44,21,101,5,207,104,134,152,97,192,36,67,63,26,253,176,89,156,133,169,212,120,109,106,18,26,0,218,239,28,216,221,158,109,15,92,255,99,158,232,120,157,3,207,233,245,29,223,119,187,22,15,37,68,129,201,200,58,158,156,100,102,28,46,103,235,249,241,228,240,176,147,189,155,156,142,166,166,192,160,77,103,29,101,87,51,244,0,46,117,178,120,114,69,67,119,25,187,2,224,187,211,227,236,145,117,156,25,70,103,98,174,54,217,188,253,18,115,46,115,26,39,40,194,135,2,70,187,243,181,227,119,59,57,112,244,250,140,192,190,73,126,159,164,147,155,161,235,193,200,210,199,192,59,40,240,14,14,15,245,241,225,168,223,153,188,27,131,128,254,233,199,81,246,46,56,61,57,113,60,99,252,149,235,148,218,184,32,224,111,146,219,123,64,109,148,224,127,13,8,1,131,23,29,2,108,110,5,63,104,32,64,3,7,160,107,67,79,190,15,47,247,109,131,250,160,224,83,3,4,220,131,79,153,188,134,99,180,156,181,109,144,74,47,231,31,216,126,45,59,111,223,252,45,137,150,237,22,52,79,159,135,151,247,236,44,245,212,81,152,172,104,142,251,28,14,76,6,247,228,12,162,215,14,116,167,163,87,90,203,123,251,36,200,194,174,119,159,118,92,118,35,168,0,70,40,102,152,221,253,136,131,67,27,135,125,62,114,78,245,8,245,162,19,239,56,2,133,130,175,251,135,209,215,221,147,81,206,155,254,55,18,215,24,150,48,72,31,99,101,8,164,235,126,221,118,141,168,115,208,117,59,157,161,44,208,26,193,11,108,160,209,25,227,221,68,166,12,205,164,33,22,81,48,83,60,122,247,231,199,198,159,44,99,112,248,203,209,233,81,52,211,81,183,164,71,205,130,57,30,29,30,6,95,121,157,241,131,145,5,87,71,178,47,134,23,50,9,47,95,177,70,11,156,3,195,238,116,14,88,61,86,201,69,219,209,13,231,235,241,97,191,131,228,147,147,241,215,206,199,166,58,157,14,245,212,64,118,137,27,219,227,75,83,26,189,209,148,71,120,66,240,251,81,158,170,63,27,93,111,214,211,254,240,26,252,132,236,236,116,188,176,208,207,204,179,104,137,213,164,82,177,246,102,25,98,167,96,21,182,195,229,24,3,209,219,159,158,63,77,22,88,2,33,55,55,238,116,136,158,66,28,132,100,54,129,157,96,253,160,86,83,194,20,13,86,0,8,160,128,26,45,111,195,88,113,98,74,156,200,192,133,236,36,86,92,200,32,56,211,178,144,60,69,243,32,96,214,169,232,237,244,54,212,247,132,47,106,154,83,172,49,60,149,13,181,227,119,217,105,161,47,211,66,242,208,171,231,163,103,199,71,95,63,192,164,227,107,237,219,16,51,159,5,214,135,105,29,33,88,98,93,141,134,67,45,202,224,239,63,217,76,225,89,81,49,46,250,239,193,102,61,199,92,87,211,158,133,228,83,106,143,207,146,205,251,57,102,147,191,133,115,108,23,173,215,171,108,120,116,132,42,200,52,147,116,70,211,26,84,131,163,17,210,98,149,246,242,249,27,74,57,162,46,189,26,53,240,40,126,48,162,117,38,248,196,47,145,250,241,227,143,252,251,224,1,70,236,8,75,153,132,77,103,91,140,235,84,72,86,165,50,165,113,234,224,128,134,114,76,17,42,169,166,2,2,95,83,1,193,100,160,185,12,96,23,222,46,33,162,144,204,33,99,178,53,121,134,9,197,250,197,119,85,128,121,137,140,186,94,205,3,206,34,185,109,233,22,100,108,215,61,248,30,163,251,115,147,148,5,44,127,165,79,112,2,49,132,162,231,37,199,122,132,25,72,117,92,22,50,240,77,68,147,30,86,18,156,145,79,141,170,65,122,5,95,127,52,169,233,212,184,51,28,99,204,221,73,164,31,20,127,156,166,193,85,201,45,98,164,133,55,52,6,230,195,7,162,64,148,241,63,234,28,28,84,80,122,48,26,189,197,188,167,207,217,52,203,25,97,74,167,212,11,146,169,100,59,29,197,74,247,120,12,6,36,125,133,178,202,210,234,203,145,221,115,29,191,239,193,185,208,195,145,225,244,112,238,246,123,3,61,25,25,121,150,167,175,71,42,167,175,111,160,43,155,147,84,233,202,6,186,146,190,219,156,142,218,244,75,86,158,254,121,36,45,249,45,50,211,241,84,46,156,154,146,251,146,190,91,201,97,222,118,250,39,39,43,140,192,122,250,174,189,58,236,122,72,31,156,156,120,157,67,219,59,29,173,242,174,45,48,147,251,117,58,213,103,244,63,155,233,115,250,159,207,117,154,225,253,26,69,187,88,142,48,198,177,20,60,29,45,245,215,163,80,127,63,74,244,95,71,235,227,229,104,209,94,234,161,158,232,107,180,185,57,180,78,245,158,110,116,251,86,191,215,29,184,221,14,58,191,104,175,117,81,132,10,216,167,186,13,123,238,246,7,126,215,243,251,40,145,160,4,85,167,50,84,2,99,156,221,211,187,86,215,182,252,190,61,232,128,180,139,182,104,97,201,5,220,83,221,1,8,219,242,60,223,241,93,215,234,128,21,85,52,60,70,195,238,117,61,187,223,31,244,118,209,240,25,13,155,246,252,250,150,231,52,160,209,101,52,12,219,3,35,93,219,245,236,93,68,122,2,17,207,239,89,254,160,239,238,162,209,39,52,236,94,207,178,92,223,3,9,119,208,24,8,106,216,3,18,21,207,179,129,105,29,15,27,36,37,68,60,199,194,240,189,131,131,13,130,50,53,6,3,203,179,208,8,28,146,58,26,54,72,10,60,208,209,174,229,118,251,40,177,195,21,208,148,16,241,44,116,212,182,208,215,29,52,64,82,166,135,111,129,104,142,51,0,213,119,112,1,85,129,11,38,4,93,223,245,93,7,188,91,142,102,85,84,78,117,31,64,186,126,111,208,245,109,192,88,163,64,25,19,144,125,64,188,237,14,124,203,238,186,192,53,65,137,10,38,36,66,158,222,245,92,104,85,207,102,154,204,42,120,128,98,142,5,25,235,65,202,122,174,197,20,169,162,1,68,129,70,207,178,125,136,224,0,221,173,163,65,84,31,232,110,31,56,88,196,217,29,36,72,128,60,72,122,215,242,122,125,215,245,119,177,0,193,8,11,207,130,150,246,250,94,127,23,11,112,223,215,253,110,223,243,208,25,228,239,32,1,16,76,12,123,208,7,227,136,228,117,60,136,111,64,195,238,247,220,174,59,232,178,144,86,209,128,12,2,13,27,180,244,93,48,15,37,118,120,2,32,196,20,15,120,244,109,175,203,234,82,197,4,2,4,68,124,27,242,129,174,236,162,1,77,0,26,48,114,224,122,31,26,179,139,6,201,32,145,195,30,56,160,89,175,231,2,202,114,52,175,115,5,125,65,11,224,10,225,48,175,224,128,142,216,54,60,65,8,159,223,3,170,204,149,249,174,104,116,33,233,238,192,114,45,159,116,33,68,145,10,30,196,22,23,173,248,174,53,240,49,229,218,193,2,48,136,162,148,63,128,206,177,140,86,49,33,85,176,33,230,61,167,63,0,235,27,16,33,122,116,9,136,239,13,122,44,197,59,120,144,144,2,15,219,26,128,94,86,215,99,43,86,195,4,140,129,160,247,209,210,192,238,129,96,117,68,200,52,128,36,174,223,135,136,57,14,43,75,21,17,146,15,32,130,76,223,177,7,61,182,166,85,68,160,112,192,163,215,181,156,129,221,103,141,173,34,1,33,37,57,7,231,187,158,215,103,217,168,34,65,156,37,44,60,199,238,219,126,159,84,97,135,47,164,45,93,29,36,237,121,64,132,77,71,21,11,146,14,80,99,48,128,61,239,195,50,16,30,87,245,145,133,40,58,232,119,93,11,26,67,120,92,85,240,32,154,147,160,59,221,254,192,246,48,31,4,26,87,187,54,140,37,157,180,193,27,88,172,181,87,21,68,200,132,161,51,144,48,151,52,119,23,15,234,46,68,12,54,221,131,156,246,216,118,84,17,33,154,147,164,247,7,30,176,197,64,214,128,9,113,142,48,177,124,219,119,88,93,170,104,144,85,103,97,7,154,14,216,207,140,169,34,2,125,32,81,135,99,97,67,8,81,160,142,7,83,157,236,32,134,82,136,15,171,109,21,13,26,227,8,11,191,75,38,6,214,174,1,17,26,109,33,236,208,6,219,183,187,94,3,34,160,42,113,198,243,209,19,171,199,250,82,67,132,212,146,40,130,241,214,177,97,66,0,164,142,10,9,145,175,247,208,159,126,207,161,222,212,17,129,28,18,69,92,240,5,116,23,18,178,60,124,10,15,199,66,217,240,240,53,31,37,163,228,240,61,31,173,71,235,195,95,233,104,171,124,120,181,138,243,78,34,127,10,151,157,253,160,138,3,171,167,250,74,224,46,60,158,245,104,124,216,142,14,210,143,127,141,14,86,157,195,246,146,96,118,14,19,57,131,105,175,79,78,194,143,107,177,168,21,118,14,163,45,214,196,225,83,237,3,115,245,49,61,248,235,222,48,231,243,61,96,254,57,253,243,222,0,163,232,110,128,233,159,219,209,71,224,184,47,76,14,195,200,162,15,8,157,235,210,249,36,154,97,215,90,37,188,40,230,226,149,41,3,109,171,140,120,134,213,89,207,211,228,130,119,205,197,198,119,235,121,28,135,179,32,214,130,116,198,107,175,90,235,112,44,102,241,228,160,151,23,176,218,1,67,203,231,150,60,229,8,50,206,251,38,29,202,83,57,31,153,212,230,213,105,103,152,187,251,88,168,194,185,216,16,160,134,222,142,114,196,229,22,194,79,163,199,237,183,29,253,124,20,99,151,232,166,229,233,184,33,48,169,37,98,89,104,161,229,201,254,149,121,161,186,168,121,113,107,205,150,218,15,125,67,177,136,88,18,143,150,88,87,255,254,205,203,23,163,120,171,127,119,123,93,222,52,110,172,248,102,143,138,63,133,1,34,66,234,53,191,29,137,8,22,212,175,68,67,76,245,172,3,144,20,129,49,25,181,90,152,72,82,54,182,60,67,192,153,132,41,148,83,68,113,148,164,5,155,1,163,159,104,15,14,226,16,18,85,51,44,119,119,244,105,123,2,186,208,246,84,48,121,44,38,126,197,100,185,163,255,80,96,112,253,164,221,218,172,8,170,216,169,197,98,61,82,16,128,65,91,179,114,247,22,105,231,5,25,85,218,49,135,138,20,123,154,117,10,36,235,128,246,34,208,251,243,32,222,132,199,8,198,225,190,101,35,17,53,243,45,112,57,190,104,183,16,157,149,114,72,16,197,141,130,24,180,107,12,232,114,151,89,22,22,155,83,255,117,4,160,71,28,24,244,13,118,10,195,209,191,93,79,183,7,216,7,152,227,40,219,254,87,135,182,78,31,76,40,92,103,71,111,184,25,110,3,29,161,54,180,105,0,210,98,7,85,54,21,200,166,38,188,85,15,81,87,177,55,113,50,43,87,87,49,61,67,112,72,213,29,11,86,37,233,130,194,69,152,50,17,39,253,225,229,139,239,177,220,34,163,85,142,35,19,155,21,88,222,249,241,213,235,55,45,189,197,221,17,212,7,141,35,83,28,54,236,1,41,218,151,182,129,210,14,83,115,53,18,171,230,201,102,57,105,99,134,138,250,225,228,40,197,12,126,29,196,95,35,30,230,150,237,39,5,245,73,144,130,75,34,44,76,196,0,175,14,91,95,181,110,222,239,82,21,127,38,198,86,196,155,43,110,117,236,122,21,221,73,150,170,124,33,184,192,30,172,82,51,106,90,233,195,126,243,89,28,254,47,238,212,22,61,74,150,164,81,87,144,192,117,136,165,194,229,44,44,186,196,61,162,141,108,20,160,136,67,172,39,121,180,65,30,1,9,138,63,28,141,48,81,236,124,2,222,45,116,120,31,196,69,205,2,109,89,15,234,92,87,93,82,231,74,124,6,148,128,163,4,43,232,122,64,247,110,171,250,207,194,151,13,106,158,240,93,187,245,150,165,171,208,98,18,156,116,68,12,16,250,201,225,194,111,104,224,226,174,253,95,211,17,253,13,172,141,8,190,20,3,55,226,219,4,75,16,76,55,9,49,222,43,22,193,196,35,178,98,5,139,2,100,166,168,221,210,99,61,54,41,190,159,212,47,163,116,44,210,193,198,138,38,200,200,182,14,101,129,173,136,138,194,62,198,167,227,153,153,50,104,155,150,224,127,166,1,81,173,122,63,178,15,14,30,32,252,118,29,173,226,240,155,54,174,29,72,17,231,242,199,100,131,64,71,172,93,47,227,43,77,88,7,28,135,90,155,22,78,59,136,59,140,17,41,169,162,12,77,52,1,59,50,140,223,89,167,140,178,137,128,85,196,129,182,144,129,109,144,85,187,243,128,87,77,91,183,130,47,129,206,20,68,68,62,144,27,243,151,155,199,46,81,89,196,228,162,210,191,221,92,146,0,63,95,194,122,65,2,255,178,199,238,61,150,167,99,44,214,134,84,234,91,177,59,221,70,3,112,110,80,174,93,217,13,255,64,133,105,64,251,153,118,57,228,242,185,125,252,3,182,12,44,248,234,121,185,223,193,244,200,120,11,218,103,167,52,10,167,65,7,0,47,15,255,36,63,130,17,29,125,56,150,137,249,229,4,163,223,113,172,228,78,148,19,233,2,78,190,214,135,103,33,214,74,67,125,24,76,177,11,113,141,208,2,3,62,44,237,130,156,193,225,12,83,3,41,199,242,144,117,103,104,169,83,6,50,196,64,26,77,84,18,7,128,12,191,12,253,176,23,158,109,107,176,13,99,125,193,177,240,32,208,80,107,181,182,116,197,203,53,93,200,96,204,67,10,25,24,218,166,127,108,92,132,103,239,163,181,65,67,53,161,18,26,193,228,183,13,162,129,72,245,142,141,69,242,193,192,120,194,57,67,239,216,72,202,103,165,195,41,218,49,166,1,226,86,175,134,155,200,200,130,101,102,32,210,40,130,43,6,35,31,46,140,77,164,27,208,176,56,52,68,130,254,132,162,167,94,6,227,215,124,250,12,245,245,215,225,44,9,181,183,207,245,159,146,51,44,194,235,223,135,241,121,184,142,198,129,246,67,136,232,181,199,41,2,116,244,31,144,163,189,6,124,189,212,72,235,49,129,214,160,100,216,173,249,110,145,252,22,193,41,80,224,84,66,126,254,250,106,113,150,32,192,129,65,149,235,200,110,32,164,108,147,2,81,233,187,13,151,112,71,130,88,100,66,222,35,150,140,122,246,246,44,153,92,93,47,224,62,98,7,205,58,46,211,57,90,206,129,229,122,59,79,175,101,10,69,12,17,235,100,142,226,39,98,21,37,215,237,213,229,54,56,59,75,135,23,40,128,248,89,190,252,231,180,115,93,97,23,109,240,165,140,204,16,227,123,152,82,155,48,207,184,138,104,114,124,87,129,237,220,214,231,142,62,119,245,185,167,207,125,125,222,197,222,27,250,199,252,84,104,113,202,69,181,19,1,34,193,202,168,215,27,82,229,206,116,236,139,36,203,153,0,43,129,128,236,64,99,75,230,87,127,127,54,1,11,23,43,29,74,44,10,21,242,179,72,150,73,182,194,126,176,254,250,217,75,28,27,63,133,51,92,130,144,234,47,67,56,238,58,146,130,113,162,35,10,20,234,16,100,250,139,8,17,26,220,188,70,165,145,177,73,35,152,253,31,194,11,61,7,37,122,195,253,179,195,197,54,3,207,226,82,159,251,214,87,91,108,190,35,4,110,85,74,237,249,95,85,88,105,29,175,146,12,215,255,160,163,42,214,253,24,3,12,9,105,108,4,136,196,89,14,105,159,155,170,16,52,40,56,44,223,98,104,152,142,79,109,2,54,120,140,83,58,99,63,237,154,233,71,155,206,208,210,92,215,27,165,3,137,113,176,130,191,172,14,182,136,228,132,93,213,35,178,70,122,178,90,207,224,232,173,116,52,79,215,115,16,96,196,204,6,21,218,86,56,187,35,232,149,220,6,73,175,228,11,74,146,149,104,16,147,38,249,175,201,124,174,42,43,24,123,178,128,150,234,143,232,128,160,204,26,97,44,25,204,218,2,106,6,154,202,18,239,56,84,82,156,156,202,51,54,194,234,4,180,71,108,223,105,174,47,52,184,7,0,53,14,135,162,214,241,89,48,126,79,244,90,78,36,181,185,37,68,98,128,17,229,204,104,129,97,89,52,62,100,115,56,197,8,150,209,212,254,26,81,199,212,205,33,118,137,19,153,9,217,141,150,152,166,69,19,97,219,177,87,156,92,136,218,202,53,184,190,73,94,134,67,133,45,123,64,70,182,138,150,134,236,112,145,135,70,171,121,202,166,48,22,178,247,232,235,120,222,216,123,34,234,52,10,227,201,177,196,222,72,166,83,16,110,104,56,48,57,69,51,2,68,73,177,155,128,9,170,228,117,104,8,55,196,136,175,112,187,153,254,36,52,185,177,200,54,11,136,195,213,181,188,150,102,136,139,31,64,5,140,11,91,94,247,249,203,38,89,135,250,36,214,39,19,125,199,110,233,243,84,159,70,51,8,50,150,153,200,150,40,193,218,114,63,209,183,194,42,23,162,134,181,31,120,117,215,69,2,6,132,77,172,195,31,217,96,140,68,235,98,184,165,30,54,73,42,214,251,48,155,45,85,207,181,13,44,38,197,80,76,222,178,114,130,70,36,29,28,226,50,103,27,152,171,231,110,214,117,2,115,133,208,217,161,45,53,230,203,193,56,112,131,169,2,213,12,101,31,0,74,123,82,204,198,149,246,92,143,55,41,130,173,135,43,132,75,64,178,182,67,240,128,12,211,68,101,200,208,191,109,180,152,233,217,249,76,63,143,38,97,162,195,61,60,135,229,13,54,147,40,209,163,105,10,183,82,15,17,40,55,209,69,60,69,206,74,102,96,221,70,46,176,228,20,135,12,146,193,129,67,151,106,228,35,139,82,17,105,177,62,117,154,67,100,169,219,113,165,216,221,81,174,18,245,31,87,2,94,14,53,235,184,41,227,42,207,96,173,135,33,15,75,133,139,180,162,28,162,2,144,144,159,102,239,195,139,82,13,62,45,10,243,53,190,148,109,151,207,145,47,207,87,193,146,114,139,19,100,201,19,132,49,207,141,15,9,198,12,153,2,79,18,230,222,200,150,193,10,50,153,70,227,53,34,131,16,208,15,115,114,25,193,198,93,137,98,179,20,211,18,152,46,131,98,98,140,124,144,146,64,242,220,243,40,184,57,115,157,236,228,129,108,8,167,136,115,100,48,218,206,195,137,241,1,17,47,42,109,9,127,30,104,65,251,73,7,235,169,146,226,59,133,113,89,80,185,29,178,167,48,123,100,136,202,41,194,54,73,201,208,172,213,229,110,158,144,112,237,203,233,116,90,202,148,169,233,236,172,237,15,52,108,50,104,142,215,213,142,52,19,113,72,59,32,164,149,214,44,188,191,164,11,159,74,69,110,200,187,53,89,180,30,78,118,178,207,226,13,144,146,199,136,48,159,75,94,138,20,242,213,211,0,174,119,193,151,43,150,28,149,48,223,132,185,28,138,20,140,53,80,172,156,59,52,156,151,114,179,112,21,5,234,100,130,240,222,28,109,137,2,70,57,78,174,224,149,39,238,32,152,103,213,49,205,51,118,80,206,115,118,113,207,179,170,157,200,147,149,17,171,167,215,123,89,100,136,238,98,64,82,73,255,50,10,255,50,10,255,50,10,255,50,10,48,10,102,150,26,180,156,117,157,11,115,112,134,201,35,156,105,44,226,200,25,183,114,59,232,48,247,236,148,247,103,80,42,118,218,82,132,216,95,12,133,79,114,140,197,166,21,38,130,184,172,16,177,141,244,198,70,204,28,126,43,75,56,121,143,23,105,176,170,173,231,108,77,213,242,46,46,91,90,111,226,89,101,145,167,82,182,166,152,76,26,150,154,85,2,84,28,78,215,72,160,63,58,101,238,224,156,255,139,4,71,38,152,62,118,11,183,88,253,95,161,12,77,68,81,130,78,28,62,145,185,31,12,223,186,254,192,83,210,203,161,143,18,139,51,132,19,72,31,26,54,147,155,118,100,97,202,235,214,242,60,149,227,212,50,138,58,94,45,199,22,25,113,81,133,123,164,42,164,69,122,165,35,139,117,9,51,234,66,142,22,50,242,42,148,225,230,201,121,211,156,92,148,175,20,47,146,43,197,37,154,107,35,239,50,167,202,210,236,233,86,253,222,45,22,179,105,146,149,167,138,211,45,174,211,8,47,243,68,58,81,37,141,74,78,41,109,107,10,153,171,186,193,230,28,136,75,177,149,104,32,229,23,211,207,19,187,142,74,206,211,108,172,70,112,218,133,49,192,130,39,73,165,83,36,253,242,206,233,195,168,254,114,170,178,232,76,100,184,86,57,131,207,100,134,83,201,160,51,202,152,98,227,93,166,145,91,191,253,247,247,225,21,79,21,50,141,38,176,144,186,235,98,126,47,12,65,27,129,167,147,112,134,117,112,51,88,98,238,205,186,132,162,226,132,244,129,78,53,59,211,136,50,88,124,142,150,83,186,94,21,164,16,243,21,140,86,60,145,169,207,107,176,138,79,171,10,6,145,45,159,150,226,162,66,140,255,156,33,166,122,98,18,95,79,173,39,0,183,124,62,91,5,88,155,28,11,120,245,196,250,12,154,165,1,134,240,226,154,15,38,17,89,20,86,253,228,66,102,98,240,168,103,34,9,59,10,144,27,76,147,113,45,32,198,106,116,154,167,87,60,115,206,134,34,105,107,210,114,110,52,189,82,69,242,83,185,52,92,47,38,175,238,223,41,199,38,77,229,110,205,25,92,15,251,26,191,67,37,58,148,226,136,148,34,193,21,9,189,34,197,227,20,161,74,188,196,2,215,129,5,69,154,73,114,60,54,217,112,128,23,73,145,42,18,207,106,5,100,35,42,255,178,14,64,181,41,82,85,102,177,188,42,51,140,9,123,47,42,95,76,251,69,90,94,228,151,119,191,124,137,24,180,129,29,64,198,203,174,99,62,28,217,213,149,59,114,49,28,79,115,124,205,33,7,3,75,105,237,134,106,8,134,47,183,112,102,157,185,103,253,123,180,128,48,100,205,238,193,147,233,123,123,53,66,3,49,34,191,172,253,187,224,12,52,196,40,227,235,239,213,128,76,65,27,205,77,152,206,78,81,247,166,162,238,78,81,239,166,162,30,138,206,200,95,9,141,110,222,59,56,114,165,158,213,23,251,168,119,110,79,27,80,255,170,125,203,235,113,191,102,117,162,221,13,246,38,162,53,2,198,80,187,55,92,15,112,125,248,172,190,125,43,92,118,64,246,135,234,67,70,229,247,70,168,164,198,202,33,82,106,181,186,164,177,87,166,138,225,90,140,190,202,117,146,67,181,26,146,81,222,169,22,111,42,93,20,246,170,133,201,94,212,202,10,19,130,162,126,173,168,48,72,245,210,202,76,161,66,183,94,161,177,188,44,126,5,51,167,178,216,55,168,66,87,190,141,130,142,226,5,89,10,159,164,94,62,39,11,132,171,10,190,17,122,94,56,103,132,40,204,204,216,41,173,88,148,150,72,83,163,2,47,174,203,17,129,143,197,194,156,26,12,196,118,224,162,180,19,98,246,69,91,213,13,196,50,180,203,172,92,188,161,52,23,229,34,184,213,76,180,145,208,229,198,1,238,38,181,69,160,11,46,65,30,99,65,188,190,248,159,103,200,182,206,176,218,249,94,8,57,159,151,196,188,144,109,154,104,89,101,169,46,23,37,185,230,115,214,67,68,221,222,5,13,10,210,245,181,126,69,249,110,6,56,184,27,160,221,195,252,83,115,7,123,0,196,136,11,83,113,39,68,215,211,16,139,173,13,42,195,65,35,72,76,68,247,1,232,0,187,110,159,62,119,1,188,10,99,204,139,96,163,239,134,73,54,204,194,224,120,55,37,37,208,189,16,69,215,49,20,222,141,104,125,52,169,194,164,177,68,149,232,90,249,66,186,217,69,109,18,70,158,146,9,243,153,9,223,85,164,96,225,133,47,158,39,175,44,73,113,173,107,213,212,234,229,161,149,23,237,75,59,43,50,21,187,39,49,239,153,190,167,16,191,28,50,34,56,72,125,85,144,194,112,188,57,195,82,201,89,248,1,27,156,109,211,195,164,211,196,149,49,157,114,149,9,77,133,169,172,105,251,25,124,85,90,31,255,37,159,99,202,245,114,229,214,229,212,146,9,157,98,135,179,152,149,74,16,60,219,196,252,128,124,253,59,193,136,33,129,28,45,89,155,102,154,251,86,102,195,89,170,59,55,188,59,235,84,204,140,172,7,137,188,179,158,116,9,203,213,202,126,233,157,245,155,253,86,9,73,100,238,11,163,228,157,86,234,11,155,130,9,215,157,128,246,118,237,44,120,19,182,139,111,197,254,236,186,118,10,15,233,88,236,137,192,223,201,241,80,146,83,200,54,54,237,239,22,158,6,189,68,189,127,136,86,201,70,201,129,127,136,183,146,236,122,240,13,133,183,54,99,139,153,57,173,42,229,156,86,214,167,111,13,57,227,6,159,183,95,212,43,124,212,74,141,191,147,167,202,219,221,57,118,236,100,195,30,15,57,121,239,137,68,101,185,245,22,97,147,141,169,173,105,154,29,203,150,212,94,59,140,130,198,49,80,184,163,85,177,95,95,219,203,102,203,33,97,241,130,45,110,151,80,224,219,180,202,155,227,84,172,57,119,216,123,176,106,89,229,197,231,78,115,30,119,187,188,162,188,71,35,88,30,29,183,61,244,237,240,182,246,234,13,202,150,74,145,6,141,149,69,30,98,17,43,153,59,169,34,65,47,214,167,11,134,112,133,38,222,139,102,10,206,223,189,216,94,195,112,135,247,156,156,11,244,125,155,186,65,164,239,108,139,76,235,189,219,106,54,161,245,182,86,33,236,191,188,123,208,95,249,204,144,103,172,187,255,136,105,235,29,77,10,127,242,62,109,58,142,134,43,219,180,94,117,157,97,239,54,203,102,92,108,171,237,55,178,238,110,198,113,116,64,49,45,200,243,232,234,115,233,244,21,197,75,178,93,218,189,131,22,201,165,198,130,101,124,142,12,218,178,43,146,197,126,158,76,254,99,45,157,224,240,174,198,31,74,25,98,139,79,229,148,171,136,205,190,61,9,165,188,129,123,12,184,123,140,248,55,12,184,59,70,152,17,100,101,144,232,53,88,229,79,176,199,55,129,21,6,250,95,166,249,190,166,249,86,122,178,85,129,81,187,135,57,195,13,9,120,246,136,59,31,220,105,206,110,106,86,88,150,123,182,139,169,27,205,51,237,158,115,75,187,195,40,107,155,124,79,74,254,205,117,132,22,78,29,186,246,183,251,11,133,199,238,169,11,110,87,131,25,117,43,179,197,29,69,184,173,73,55,112,207,220,241,125,154,244,251,26,198,193,110,101,61,226,94,77,134,94,216,13,207,238,211,164,227,244,65,89,12,188,119,44,223,222,212,42,143,140,24,38,246,111,177,135,5,18,159,134,167,79,105,174,88,61,190,161,65,44,31,239,214,157,85,86,231,85,205,125,150,83,27,150,231,111,151,56,209,84,93,218,246,24,177,155,164,237,174,166,212,178,212,254,205,52,45,80,221,217,76,201,106,119,174,111,139,137,221,173,205,203,24,229,141,11,137,234,109,43,94,141,27,22,181,117,154,155,27,170,169,192,45,203,65,205,146,191,87,67,60,234,222,221,66,243,104,186,87,11,197,2,83,99,51,88,108,218,169,87,138,238,20,146,65,215,148,53,132,142,138,120,161,82,225,102,62,248,224,3,252,57,27,250,90,66,190,161,94,83,31,110,192,229,159,141,134,162,34,110,246,82,172,211,217,187,229,110,159,94,223,100,106,250,55,3,18,102,64,141,0,85,48,123,104,105,211,56,112,171,150,222,54,3,191,199,248,179,223,20,252,166,214,121,56,174,244,187,220,254,126,211,192,134,158,223,53,202,223,60,255,188,87,203,251,76,64,75,109,151,125,28,41,243,141,14,86,63,55,207,123,161,1,20,186,180,76,125,219,212,244,126,88,8,127,235,158,104,208,100,206,178,53,255,54,119,235,139,207,249,249,72,149,107,71,52,190,0,235,24,55,44,23,1,40,8,189,96,39,95,68,120,107,165,93,36,77,108,35,29,19,24,71,2,225,93,33,141,226,112,142,53,25,82,165,89,102,223,13,23,228,213,154,182,69,7,199,90,121,75,72,163,203,133,100,210,223,132,131,91,193,193,169,225,96,113,211,249,193,63,6,135,47,27,158,79,131,91,180,23,161,149,121,56,26,45,125,227,217,42,184,238,136,22,208,249,168,152,240,138,89,22,207,120,161,10,95,233,26,253,118,142,85,184,22,24,43,46,200,186,173,125,121,169,105,137,36,216,235,4,73,106,17,94,20,195,243,197,231,184,86,148,175,70,145,241,17,67,187,155,79,248,190,156,186,244,46,95,188,38,47,55,112,113,127,154,201,89,109,97,156,58,34,215,183,9,118,190,92,207,39,181,240,30,103,39,188,71,133,225,241,37,1,95,124,126,175,72,34,244,162,244,216,30,200,130,188,249,61,69,56,182,49,55,237,28,231,42,99,153,3,236,127,112,196,144,193,151,150,34,206,145,99,118,0,4,87,117,202,235,56,113,73,231,81,254,172,176,19,186,240,79,227,123,106,136,59,59,211,8,241,78,122,164,167,154,90,56,231,251,115,139,241,255,157,116,100,78,53,218,139,22,207,30,195,51,101,0,10,119,238,215,34,220,179,162,65,88,112,91,124,209,132,40,47,94,13,21,212,211,159,30,21,79,2,59,57,66,177,122,45,9,77,178,183,245,168,92,72,29,127,118,50,119,118,30,75,134,174,59,156,183,122,116,50,119,31,209,157,28,54,242,33,101,56,61,57,90,137,76,213,128,220,73,214,40,184,15,241,201,134,223,122,68,87,60,209,245,202,184,48,246,124,166,97,244,164,199,67,224,98,111,211,105,105,151,139,120,137,90,116,107,77,220,89,243,226,226,194,188,112,233,206,154,71,116,71,189,35,148,111,105,244,192,181,39,201,229,168,69,179,225,190,103,209,172,181,165,169,43,205,109,60,88,77,136,214,168,229,226,184,204,152,42,245,91,184,26,28,252,68,94,85,145,143,43,20,94,225,6,10,116,213,115,108,164,184,123,54,30,22,7,169,72,38,147,22,167,225,94,253,27,220,181,126,137,7,82,64,240,91,116,187,145,133,109,153,174,230,219,230,32,134,107,98,186,134,111,14,206,123,221,49,208,52,123,36,95,154,107,98,234,129,175,103,58,113,15,231,158,217,253,176,176,7,166,175,217,54,234,32,20,207,232,82,157,65,76,199,90,47,207,52,171,217,56,21,5,76,123,183,72,143,10,120,57,132,174,105,27,125,207,244,198,6,116,221,0,22,134,11,212,232,223,51,251,154,21,27,93,154,160,0,65,174,0,248,90,119,64,133,6,38,42,27,62,37,122,72,136,209,35,100,81,145,129,217,167,236,46,117,114,0,140,92,224,208,71,175,112,138,102,75,197,186,84,204,167,98,253,106,49,63,198,226,105,15,199,40,228,83,33,207,176,93,163,103,250,40,210,5,86,182,107,246,69,47,186,93,228,1,61,119,44,177,39,250,25,8,161,224,127,208,241,220,232,117,63,144,12,19,183,26,185,215,196,41,220,238,205,180,201,51,56,199,29,29,77,123,110,184,32,10,142,125,211,159,187,24,146,248,112,128,100,117,236,206,81,2,141,217,61,68,83,66,92,207,251,232,212,135,133,107,131,227,0,210,7,70,115,2,229,158,211,225,135,133,131,158,226,38,106,166,61,38,65,0,158,154,103,128,32,196,39,151,15,250,72,130,96,128,109,26,160,211,129,167,33,29,53,93,116,210,246,204,30,49,172,11,17,241,32,71,54,81,11,55,187,66,33,58,232,146,60,17,183,125,128,6,31,28,240,129,8,63,39,122,163,69,27,148,242,32,113,174,1,236,88,16,113,134,187,135,65,58,152,25,14,36,200,96,20,249,136,90,67,62,18,224,31,64,86,197,17,178,6,132,34,121,80,36,187,150,72,243,197,17,234,0,54,166,89,0,194,165,73,206,108,144,196,113,0,12,201,93,112,12,253,5,50,4,19,124,227,250,92,148,143,152,114,4,11,253,34,250,240,17,126,252,115,3,242,214,5,53,187,102,247,28,80,153,14,134,139,78,251,16,17,52,226,3,67,121,224,19,218,16,45,18,94,116,139,142,156,30,117,70,67,38,228,136,26,65,66,151,208,147,71,146,240,46,0,128,231,84,142,180,202,195,67,189,88,83,21,185,128,19,36,215,35,236,233,8,37,136,130,182,1,108,29,84,133,108,162,171,36,189,232,13,88,37,249,225,144,82,137,3,226,14,18,123,64,131,16,230,211,34,3,157,33,44,0,10,28,102,221,67,67,92,3,12,238,49,199,153,189,121,6,100,141,229,199,28,0,203,1,10,129,5,252,3,61,21,71,80,31,238,24,186,133,100,136,175,1,245,134,201,1,19,145,131,115,252,119,209,176,55,71,102,119,12,17,33,49,233,226,219,3,214,30,255,247,161,119,184,233,44,122,68,157,69,38,36,205,0,171,6,134,3,148,196,17,241,133,200,206,180,161,74,56,2,169,81,53,182,33,28,44,242,172,154,56,38,136,46,228,90,252,51,191,192,0,112,2,53,232,31,236,37,33,50,108,50,141,168,67,255,100,61,137,51,232,249,24,116,6,139,192,18,54,11,160,34,91,7,54,123,172,39,144,254,177,176,99,2,83,54,52,68,62,74,33,91,75,199,61,52,67,226,227,146,113,2,12,179,7,102,67,77,128,65,31,217,44,243,104,129,140,55,29,125,88,248,172,30,48,56,160,2,85,167,126,144,50,144,157,162,127,146,37,48,129,148,26,95,250,135,73,60,119,33,65,115,224,230,157,147,226,67,152,136,121,164,171,208,50,100,177,160,136,35,129,30,137,44,99,200,162,10,186,67,38,88,234,251,231,62,58,65,160,128,75,143,112,243,80,21,89,160,223,57,18,129,57,9,45,148,158,218,38,158,209,63,130,191,81,147,196,121,110,91,231,224,137,67,226,76,10,192,98,66,212,198,15,173,192,148,57,1,106,128,63,164,97,176,109,98,148,96,139,65,74,76,194,1,217,231,127,24,100,166,49,87,224,127,26,220,136,72,104,78,152,72,96,96,131,47,88,236,2,37,88,128,152,89,64,148,128,128,93,128,74,71,192,137,52,144,18,72,214,197,1,231,0,95,140,63,66,230,145,0,186,201,44,54,125,160,57,39,208,56,33,14,40,7,99,20,122,68,200,66,238,176,38,67,58,194,156,97,213,146,255,108,147,44,28,19,78,62,253,115,50,224,161,60,110,0,73,36,38,173,150,25,196,37,22,32,218,251,34,27,43,192,96,112,2,99,208,172,28,9,168,199,93,12,227,231,124,8,100,6,231,93,216,189,185,77,188,196,1,4,137,250,39,210,160,188,49,15,39,152,179,153,125,48,11,230,154,19,60,141,19,136,55,49,4,129,48,244,230,52,174,160,103,68,94,172,21,65,179,72,247,161,151,24,146,8,18,101,145,45,195,141,41,73,97,193,71,22,28,48,4,0,33,41,32,200,185,59,0,190,184,202,129,134,39,20,70,9,216,251,115,58,66,109,18,112,8,41,184,68,18,136,47,137,50,169,147,248,74,114,145,218,139,28,200,1,204,7,73,5,165,208,89,254,229,178,156,47,115,168,60,212,147,45,38,186,66,236,58,7,30,220,20,12,26,248,72,6,149,135,68,22,120,96,69,232,17,249,104,240,97,233,70,112,28,17,134,37,219,230,127,232,13,161,68,22,139,199,68,16,133,52,102,64,118,140,68,20,195,129,28,242,8,101,250,167,65,199,130,224,10,43,71,255,208,24,240,13,163,207,28,45,192,113,32,162,224,8,116,194,33,43,6,76,23,228,149,172,44,13,172,132,8,255,3,48,35,69,72,144,234,8,191,141,198,55,152,34,194,128,240,35,141,36,251,71,250,45,254,73,122,73,105,168,101,26,100,28,228,184,16,5,57,66,147,166,65,34,25,109,170,76,86,85,152,36,32,79,30,17,217,6,143,134,58,178,22,56,67,219,144,86,58,32,85,149,38,136,124,1,156,66,24,104,68,230,35,114,226,132,238,195,6,66,155,186,36,16,187,78,18,102,53,231,116,223,250,207,148,231,174,166,20,114,131,113,103,222,81,158,61,208,37,9,154,186,64,65,43,95,137,160,241,37,56,26,95,31,84,248,211,39,15,12,3,143,52,230,27,10,137,59,34,105,134,81,228,170,166,43,247,209,107,110,171,122,81,67,209,154,87,113,222,169,185,167,252,136,48,220,11,73,92,240,94,110,16,37,104,194,88,58,167,233,156,40,86,224,33,239,94,180,59,147,16,243,186,34,148,27,107,5,52,225,149,127,152,104,136,133,113,204,1,235,129,236,26,47,26,150,67,119,196,178,129,90,244,199,122,3,22,121,42,59,174,50,73,236,150,150,79,114,8,229,160,53,154,89,250,26,197,11,107,116,245,20,211,77,16,143,238,230,199,23,102,84,217,85,76,92,197,254,198,169,72,201,241,124,39,23,254,100,122,169,253,90,78,222,121,153,90,230,135,184,25,18,230,124,123,204,242,228,124,206,41,77,231,232,184,50,249,163,61,28,79,205,196,136,72,52,165,163,0,202,186,183,47,82,197,86,45,77,52,253,60,137,232,139,103,98,96,6,77,212,171,36,211,3,36,242,116,201,252,120,51,198,253,10,52,241,167,110,120,1,157,226,121,6,36,230,37,249,137,154,243,125,55,128,115,43,54,144,65,125,231,220,46,37,224,31,195,165,83,78,48,156,159,97,32,95,136,202,31,90,71,0,152,196,87,124,187,30,94,141,64,203,54,250,10,197,70,132,171,131,49,155,139,228,109,34,195,57,239,150,211,48,72,193,251,131,191,76,206,191,75,57,82,205,171,172,192,101,198,181,52,13,143,39,165,235,156,248,118,153,181,226,71,59,229,79,142,132,182,84,19,249,62,21,242,153,126,124,55,53,86,166,226,6,95,138,152,242,198,163,90,128,27,232,173,192,95,126,234,3,63,154,100,246,161,133,245,1,121,99,192,86,233,158,91,109,190,255,88,167,162,228,71,21,29,174,46,118,176,5,192,189,48,249,206,43,183,153,156,218,141,219,246,54,58,30,155,56,40,180,232,75,101,238,89,1,44,238,125,90,89,21,81,96,112,165,164,80,127,44,147,148,215,41,164,249,96,147,125,195,242,77,85,175,43,26,205,215,90,105,23,134,184,156,175,166,135,101,24,226,58,189,220,142,237,152,18,242,41,253,93,3,177,163,216,117,82,210,221,252,84,27,165,64,39,9,175,220,68,190,18,163,174,233,254,170,186,30,213,196,217,6,18,139,27,78,214,22,158,234,104,90,95,85,97,86,40,91,149,157,93,73,122,45,238,245,120,155,32,85,111,7,185,199,64,41,248,36,6,176,6,41,186,159,185,244,176,132,166,204,37,29,255,61,204,37,192,124,154,177,172,94,188,80,182,146,152,72,96,167,26,215,166,6,88,6,99,19,200,51,224,62,252,172,94,15,41,42,13,110,13,29,86,11,201,159,60,13,187,42,84,44,79,144,64,42,133,104,66,72,83,139,74,161,157,230,120,254,216,253,83,197,144,98,174,68,134,154,150,110,188,6,59,138,85,208,178,60,241,179,88,67,37,39,144,237,178,112,21,69,133,104,149,37,139,111,174,123,155,92,149,239,34,185,167,84,193,33,250,127,85,170,228,245,43,37,153,90,96,154,212,35,255,221,192,236,201,43,13,191,152,67,240,10,39,102,161,222,227,98,204,165,11,80,230,149,97,153,234,27,110,133,251,52,180,14,206,153,239,149,209,182,55,55,45,187,81,26,10,94,85,13,62,93,97,94,53,69,111,151,184,245,55,70,90,44,133,51,243,155,37,165,10,83,222,7,187,66,138,203,172,121,208,40,183,245,99,140,138,120,64,55,150,241,131,25,182,19,170,109,229,15,12,223,21,75,60,171,156,111,253,118,171,197,171,222,227,122,239,161,19,220,219,103,80,171,213,220,145,114,27,219,15,242,226,48,49,138,130,32,165,107,189,107,227,94,190,47,209,64,51,177,185,86,190,196,167,62,120,40,114,236,59,132,52,82,169,58,173,170,146,41,31,12,186,52,114,243,21,246,183,140,220,205,132,82,143,103,223,29,101,118,134,236,170,241,162,23,109,231,208,221,198,235,174,95,189,228,137,32,49,119,77,221,160,60,31,236,105,35,84,171,93,34,79,147,17,155,166,37,133,175,83,185,90,174,54,121,218,113,69,226,89,121,166,85,154,127,168,176,0,153,86,11,147,184,105,98,147,79,83,42,169,77,161,45,37,237,42,109,228,53,33,80,202,168,97,81,39,60,232,135,219,53,210,253,42,249,150,238,224,36,217,71,166,104,56,121,164,158,143,127,114,36,10,221,89,25,114,250,34,90,195,220,60,123,141,61,253,215,63,62,127,246,236,245,13,149,97,177,184,153,187,60,171,127,172,148,125,75,1,14,111,159,223,41,100,113,112,22,198,10,15,117,35,20,181,223,206,120,85,154,175,222,1,162,129,232,229,153,9,7,93,211,179,125,89,134,119,158,248,171,136,155,75,181,188,129,140,70,65,24,72,20,33,219,187,77,84,28,235,1,156,93,191,226,89,23,33,28,213,217,125,41,93,78,241,235,41,42,164,87,74,106,83,46,2,65,106,171,0,40,149,107,64,190,184,80,142,57,23,225,229,59,161,249,77,101,202,81,233,154,72,82,87,63,189,123,136,39,200,139,36,21,199,32,79,41,42,128,174,249,83,217,124,9,97,57,33,223,31,175,52,162,46,202,168,164,202,147,74,15,69,18,46,15,148,71,184,224,79,181,92,185,104,172,162,245,42,176,181,218,203,210,28,165,105,250,65,2,202,242,120,151,234,204,33,136,165,49,166,136,83,211,138,192,63,248,14,255,68,117,251,62,72,39,100,80,180,231,223,238,169,114,164,18,120,176,38,215,122,254,109,29,219,127,182,185,80,6,81,251,89,196,10,52,117,226,179,207,62,43,225,62,149,53,100,133,150,118,123,15,154,39,126,136,201,200,135,111,113,103,50,60,41,147,150,59,178,27,67,7,228,4,214,245,41,168,229,31,179,116,137,126,202,211,102,28,100,28,146,186,95,3,118,231,16,177,195,65,54,42,228,201,103,220,176,190,66,183,74,167,73,119,245,150,231,244,220,122,109,164,61,60,122,136,82,194,86,138,6,255,185,75,160,202,151,187,239,82,40,89,141,210,77,6,118,150,69,97,89,209,156,88,22,37,175,188,97,109,212,249,31,90,27,213,180,39,8,25,213,112,87,242,122,208,205,13,139,110,36,161,127,95,97,200,111,101,223,238,252,127,192,124,0,248,31,101,62,248,135,123,148,203,85,3,222,131,145,172,109,88,130,42,130,178,242,68,20,71,236,25,14,17,122,133,112,205,71,255,13,10,108,23,134,230,146,0,0}; +const uint8_t ELEGANT_HTML[11640] PROGMEM = {31,139,8,0,128,47,232,102,0,255,237,125,249,127,219,70,146,239,207,201,231,147,255,1,102,54,50,25,1,16,78,94,18,157,181,157,120,226,93,59,206,139,237,204,225,104,178,16,9,146,136,65,130,3,144,58,44,115,254,246,253,86,117,55,46,66,18,229,57,118,223,123,195,19,232,163,186,186,174,174,238,46,0,39,15,38,201,120,125,181,10,181,249,122,17,63,250,226,243,19,250,215,226,96,57,27,181,194,101,11,41,154,118,50,15,131,9,31,225,120,17,174,3,109,60,15,210,44,92,143,90,111,223,60,51,250,45,237,168,146,187,12,22,225,168,117,30,133,23,171,36,93,183,180,113,178,92,135,75,148,190,136,38,235,249,104,18,158,71,227,208,224,19,93,139,150,209,58,10,98,35,27,7,113,56,178,77,171,4,109,29,173,227,240,209,147,96,189,14,211,43,237,187,197,38,14,214,73,170,189,122,243,88,123,187,154,4,235,240,228,72,20,1,222,217,56,141,86,107,28,197,225,90,139,147,96,18,45,103,223,70,231,111,194,203,181,54,210,90,47,68,138,105,154,173,227,47,62,15,178,171,229,88,155,110,150,227,117,148,44,209,157,112,252,94,129,127,189,14,214,155,236,167,240,44,73,214,237,142,118,253,197,231,159,161,3,217,90,67,131,1,64,5,23,65,180,214,102,225,250,91,156,183,31,30,253,46,92,63,139,210,197,69,144,134,207,151,211,228,97,7,240,63,139,166,90,155,202,139,250,159,129,200,155,5,72,96,162,218,119,113,72,135,79,174,158,79,218,15,167,178,230,207,97,154,1,147,135,29,115,13,132,159,10,130,161,49,130,97,170,66,4,248,102,80,96,201,132,145,248,182,25,138,202,103,40,217,58,89,73,146,124,55,13,199,232,40,39,167,33,184,250,51,24,135,243,207,240,66,218,86,11,227,44,20,221,56,58,42,152,176,76,214,90,178,140,163,101,168,107,239,195,112,165,17,89,0,142,161,135,235,55,209,34,76,54,235,246,141,164,213,53,199,178,172,206,177,6,160,79,169,144,22,204,130,104,9,121,208,28,45,11,65,242,73,70,205,127,241,249,22,168,229,172,202,214,65,186,174,98,126,43,133,91,41,183,134,210,198,34,204,178,96,22,182,106,212,169,202,202,237,52,46,128,145,76,3,221,48,5,177,199,113,144,101,47,162,108,109,166,225,34,57,15,193,139,104,50,9,193,205,219,161,73,189,168,64,8,38,229,102,94,9,24,32,66,137,0,117,206,221,46,97,119,161,204,13,126,58,190,170,199,183,163,12,158,9,174,255,30,66,34,48,222,85,81,81,162,80,82,165,118,209,185,77,50,124,19,86,217,102,60,6,103,159,38,241,102,33,187,32,21,240,1,85,45,225,42,9,144,21,253,149,234,89,146,215,29,249,210,53,155,229,116,127,185,246,85,249,29,217,133,209,249,158,91,126,74,56,85,141,203,29,189,92,165,201,12,218,89,233,102,94,211,185,173,102,192,141,103,79,54,235,53,254,184,166,50,80,251,145,71,227,38,204,108,125,21,135,230,36,202,86,113,112,53,122,120,22,39,227,247,15,171,6,162,185,228,50,89,134,92,80,144,67,96,157,156,101,97,122,30,166,192,124,25,94,104,47,55,32,33,208,124,37,147,219,32,206,232,145,228,78,157,108,36,94,244,83,133,244,12,35,73,54,227,113,1,188,219,7,110,93,44,21,220,218,232,160,76,125,26,130,217,209,121,248,99,176,158,51,101,52,109,141,97,137,15,52,26,228,128,12,88,180,194,65,152,143,19,211,112,61,158,87,171,162,5,170,64,28,80,197,205,228,125,7,40,49,90,13,131,77,94,236,183,44,89,2,79,178,153,63,210,8,92,180,23,100,218,127,188,126,245,131,48,226,235,77,186,100,8,82,10,53,109,171,141,3,32,162,181,195,52,77,82,137,189,6,56,212,90,2,110,113,122,251,225,51,66,87,227,147,225,67,93,28,40,132,37,220,229,38,142,57,69,242,243,34,90,78,146,11,19,99,1,180,6,40,23,20,166,145,88,141,58,218,168,245,13,43,53,37,170,1,77,165,225,131,30,189,70,78,160,173,133,130,105,201,20,138,167,6,2,173,77,74,104,105,139,40,142,35,153,6,130,21,116,87,181,4,215,127,76,147,5,138,181,219,191,234,192,250,55,104,49,227,36,42,208,171,164,200,2,93,81,170,77,149,191,19,148,248,41,252,203,38,148,144,39,26,74,66,29,132,45,176,100,203,66,147,152,138,218,79,193,56,212,206,194,245,69,24,230,2,163,5,203,137,182,158,135,10,57,81,75,226,102,166,168,209,126,119,139,27,161,171,122,167,178,61,122,153,128,183,100,207,66,18,89,101,40,137,202,157,142,114,6,189,254,110,46,200,222,128,239,225,144,148,225,109,201,156,144,28,11,117,248,116,223,169,37,133,157,69,236,211,28,167,26,8,86,37,137,101,153,41,172,91,162,104,110,93,254,22,188,37,227,255,54,204,203,64,10,172,25,34,190,205,14,224,167,143,69,202,10,155,242,128,7,23,93,187,214,224,188,167,209,217,102,29,102,67,152,203,13,188,197,60,229,89,20,195,177,31,106,239,30,242,32,244,240,84,226,183,223,184,214,48,238,55,15,5,101,148,156,79,67,137,236,220,209,17,77,85,32,186,233,123,109,19,125,241,121,142,152,58,144,216,213,124,171,22,85,104,17,16,12,152,65,252,26,238,2,156,80,210,99,154,36,113,38,242,78,142,242,249,11,207,124,196,153,70,51,179,81,107,145,76,54,113,136,121,84,154,100,89,146,70,179,104,137,114,109,53,64,193,159,18,20,155,142,114,156,198,105,136,233,145,196,168,221,130,155,14,28,224,172,197,132,215,113,52,109,79,15,14,166,102,182,89,209,12,45,43,31,183,101,115,43,20,134,124,180,58,29,97,247,143,167,176,138,162,157,128,140,115,222,20,204,100,122,245,58,140,33,68,73,250,56,142,219,15,169,181,119,168,174,48,87,160,78,97,66,39,237,160,115,220,56,50,7,163,71,215,69,27,99,106,35,232,0,211,177,201,84,24,141,90,227,121,20,79,168,3,173,78,81,48,162,130,99,34,117,56,249,33,153,132,89,39,50,215,193,236,7,154,131,162,206,139,231,63,252,103,235,224,32,162,190,211,121,21,163,131,131,73,59,234,108,59,133,136,200,94,233,215,121,99,195,7,150,158,109,206,214,105,24,226,16,226,80,248,115,232,139,36,253,120,116,189,61,150,3,100,96,70,208,194,89,26,173,175,14,14,128,126,126,54,42,229,116,244,0,40,77,97,51,194,244,199,36,142,198,162,108,53,9,21,170,9,84,139,165,224,21,75,1,117,104,147,133,6,184,13,239,136,166,209,89,235,155,49,49,95,157,142,90,209,114,28,111,38,97,107,184,83,51,128,99,118,181,72,54,187,117,48,66,173,91,195,90,98,6,138,26,66,250,90,250,120,155,83,129,56,122,13,62,5,102,184,82,178,66,199,163,7,214,177,34,14,81,234,88,184,66,176,251,232,147,62,238,108,183,29,24,157,6,165,0,106,172,22,31,63,62,104,183,56,9,157,192,148,190,40,216,57,56,144,94,199,130,44,239,203,112,18,5,237,86,27,92,5,177,50,76,116,226,36,197,130,2,85,29,178,194,118,32,252,92,52,204,190,201,121,188,159,226,234,55,206,44,41,255,37,36,142,103,175,103,201,37,218,224,89,65,56,65,215,59,195,125,218,145,179,167,191,169,41,187,115,124,159,122,232,218,119,231,40,64,237,135,152,12,182,91,99,72,214,251,150,94,50,39,159,128,199,189,201,122,163,53,252,36,202,53,65,139,163,217,28,166,162,172,177,143,219,113,231,90,170,105,124,112,16,155,191,254,26,102,232,16,76,194,193,193,171,51,242,1,77,140,110,235,132,76,14,28,148,236,213,197,18,14,219,42,76,215,87,24,229,97,220,98,189,53,9,167,193,38,6,228,111,98,83,30,15,227,237,121,144,106,47,70,215,225,37,91,209,225,245,118,171,95,86,78,143,203,6,155,74,195,62,62,126,242,244,219,239,158,253,238,251,231,255,241,159,47,94,254,240,234,199,255,243,211,235,55,111,127,254,253,31,254,248,167,224,108,12,216,179,121,244,219,251,120,177,76,86,127,73,179,245,230,252,226,242,234,131,101,59,174,231,119,123,253,193,225,17,184,54,186,6,190,241,48,135,157,233,147,188,139,217,201,201,228,99,246,232,209,35,215,49,38,91,29,5,211,27,11,82,17,46,139,130,225,18,10,181,44,21,101,5,207,104,134,152,97,192,36,67,63,26,253,176,89,156,133,169,212,120,109,106,18,26,0,218,239,28,216,221,158,109,15,92,255,99,158,232,120,157,3,207,233,245,29,223,119,187,22,15,37,68,129,201,200,58,158,156,100,102,28,46,103,235,249,241,228,240,176,147,189,155,156,142,166,166,192,160,77,103,29,101,87,51,244,0,46,117,178,120,114,69,67,119,25,187,2,224,187,211,227,236,145,117,156,25,70,103,98,174,54,217,188,253,18,115,46,115,26,39,40,194,135,2,70,187,243,181,227,119,59,57,112,244,250,140,192,190,73,126,159,164,147,155,161,235,193,200,210,199,192,59,40,240,14,14,15,245,241,225,168,223,153,188,27,131,128,254,233,199,81,246,46,56,61,57,113,60,99,252,149,235,148,218,184,32,224,111,146,219,123,64,109,148,224,127,13,8,1,131,23,29,2,108,110,5,63,104,32,64,3,7,160,107,67,79,190,15,47,247,109,131,250,160,224,83,3,4,220,131,79,153,188,134,99,180,156,181,109,144,74,47,231,31,216,126,45,59,111,223,252,45,137,150,237,22,52,79,159,135,151,247,236,44,245,212,81,152,172,104,142,251,28,14,76,6,247,228,12,162,215,14,116,167,163,87,90,203,123,251,36,200,194,174,119,159,118,92,118,35,168,0,70,40,102,152,221,253,136,131,67,27,135,125,62,114,78,245,8,245,162,19,239,56,2,133,130,175,251,135,209,215,221,147,81,206,155,254,55,18,215,24,150,48,72,31,99,101,8,164,235,126,221,118,141,168,115,208,117,59,157,161,44,208,26,193,11,108,160,209,25,227,221,68,166,12,205,164,33,22,81,48,83,60,122,247,231,199,198,159,44,99,112,248,203,209,233,81,52,211,81,183,164,71,205,130,57,30,29,30,6,95,121,157,241,131,145,5,87,71,178,47,134,23,50,9,47,95,177,70,11,156,3,195,238,116,14,88,61,86,201,69,219,209,13,231,235,241,97,191,131,228,147,147,241,215,206,199,166,58,157,14,245,212,64,118,137,27,219,227,75,83,26,189,209,148,71,120,66,240,251,81,158,170,63,27,93,111,214,211,254,240,26,252,132,236,236,116,188,176,208,207,204,179,104,137,213,164,82,177,246,102,25,98,167,96,21,182,195,229,24,3,209,219,159,158,63,77,22,88,2,33,55,55,238,116,136,158,66,28,132,100,54,129,157,96,253,160,86,83,194,20,13,86,0,8,160,128,26,45,111,195,88,113,98,74,156,200,192,133,236,36,86,92,200,32,56,211,178,144,60,69,243,32,96,214,169,232,237,244,54,212,247,132,47,106,154,83,172,49,60,149,13,181,227,119,217,105,161,47,211,66,242,208,171,231,163,103,199,71,95,63,192,164,227,107,237,219,16,51,159,5,214,135,105,29,33,88,98,93,141,134,67,45,202,224,239,63,217,76,225,89,81,49,46,250,239,193,102,61,199,92,87,211,158,133,228,83,106,143,207,146,205,251,57,102,147,191,133,115,108,23,173,215,171,108,120,116,132,42,200,52,147,116,70,211,26,84,131,163,17,210,98,149,246,242,249,27,74,57,162,46,189,26,53,240,40,126,48,162,117,38,248,196,47,145,250,241,227,143,252,251,224,1,70,236,8,75,153,132,77,103,91,140,235,84,72,86,165,50,165,113,234,224,128,134,114,76,17,42,169,166,2,2,95,83,1,193,100,160,185,12,96,23,222,46,33,162,144,204,33,99,178,53,121,134,9,197,250,197,119,85,128,121,137,140,186,94,205,3,206,34,185,109,233,22,100,108,215,61,248,30,163,251,115,147,148,5,44,127,165,79,112,2,49,132,162,231,37,199,122,132,25,72,117,92,22,50,240,77,68,147,30,86,18,156,145,79,141,170,65,122,5,95,127,52,169,233,212,184,51,28,99,204,221,73,164,31,20,127,156,166,193,85,201,45,98,164,133,55,52,6,230,195,7,162,64,148,241,63,234,28,28,84,80,122,48,26,189,197,188,167,207,217,52,203,25,97,74,167,212,11,146,169,100,59,29,197,74,247,120,12,6,36,125,133,178,202,210,234,203,145,221,115,29,191,239,193,185,208,195,145,225,244,112,238,246,123,3,61,25,25,121,150,167,175,71,42,167,175,111,160,43,155,147,84,233,202,6,186,146,190,219,156,142,218,244,75,86,158,254,121,36,45,249,45,50,211,241,84,46,156,154,146,251,146,190,91,201,97,222,118,250,39,39,43,140,192,122,250,174,189,58,236,122,72,31,156,156,120,157,67,219,59,29,173,242,174,45,48,147,251,117,58,213,103,244,63,155,233,115,250,159,207,117,154,225,253,26,69,187,88,142,48,198,177,20,60,29,45,245,215,163,80,127,63,74,244,95,71,235,227,229,104,209,94,234,161,158,232,107,180,185,57,180,78,245,158,110,116,251,86,191,215,29,184,221,14,58,191,104,175,117,81,132,10,216,167,186,13,123,238,246,7,126,215,243,251,40,145,160,4,85,167,50,84,2,99,156,221,211,187,86,215,182,252,190,61,232,128,180,139,182,104,97,201,5,220,83,221,1,8,219,242,60,223,241,93,215,234,128,21,85,52,60,70,195,238,117,61,187,223,31,244,118,209,240,25,13,155,246,252,250,150,231,52,160,209,101,52,12,219,3,35,93,219,245,236,93,68,122,2,17,207,239,89,254,160,239,238,162,209,39,52,236,94,207,178,92,223,3,9,119,208,24,8,106,216,3,18,21,207,179,129,105,29,15,27,36,37,68,60,199,194,240,189,131,131,13,130,50,53,6,3,203,179,208,8,28,146,58,26,54,72,10,60,208,209,174,229,118,251,40,177,195,21,208,148,16,241,44,116,212,182,208,215,29,52,64,82,166,135,111,129,104,142,51,0,213,119,112,1,85,129,11,38,4,93,223,245,93,7,188,91,142,102,85,84,78,117,31,64,186,126,111,208,245,109,192,88,163,64,25,19,144,125,64,188,237,14,124,203,238,186,192,53,65,137,10,38,36,66,158,222,245,92,104,85,207,102,154,204,42,120,128,98,142,5,25,235,65,202,122,174,197,20,169,162,1,68,129,70,207,178,125,136,224,0,221,173,163,65,84,31,232,110,31,56,88,196,217,29,36,72,128,60,72,122,215,242,122,125,215,245,119,177,0,193,8,11,207,130,150,246,250,94,127,23,11,112,223,215,253,110,223,243,208,25,228,239,32,1,16,76,12,123,208,7,227,136,228,117,60,136,111,64,195,238,247,220,174,59,232,178,144,86,209,128,12,2,13,27,180,244,93,48,15,37,118,120,2,32,196,20,15,120,244,109,175,203,234,82,197,4,2,4,68,124,27,242,129,174,236,162,1,77,0,26,48,114,224,122,31,26,179,139,6,201,32,145,195,30,56,160,89,175,231,2,202,114,52,175,115,5,125,65,11,224,10,225,48,175,224,128,142,216,54,60,65,8,159,223,3,170,204,149,249,174,104,116,33,233,238,192,114,45,159,116,33,68,145,10,30,196,22,23,173,248,174,53,240,49,229,218,193,2,48,136,162,148,63,128,206,177,140,86,49,33,85,176,33,230,61,167,63,0,235,27,16,33,122,116,9,136,239,13,122,44,197,59,120,144,144,2,15,219,26,128,94,86,215,99,43,86,195,4,140,129,160,247,209,210,192,238,129,96,117,68,200,52,128,36,174,223,135,136,57,14,43,75,21,17,146,15,32,130,76,223,177,7,61,182,166,85,68,160,112,192,163,215,181,156,129,221,103,141,173,34,1,33,37,57,7,231,187,158,215,103,217,168,34,65,156,37,44,60,199,238,219,126,159,84,97,135,47,164,45,93,29,36,237,121,64,132,77,71,21,11,146,14,80,99,48,128,61,239,195,50,16,30,87,245,145,133,40,58,232,119,93,11,26,67,120,92,85,240,32,154,147,160,59,221,254,192,246,48,31,4,26,87,187,54,140,37,157,180,193,27,88,172,181,87,21,68,200,132,161,51,144,48,151,52,119,23,15,234,46,68,12,54,221,131,156,246,216,118,84,17,33,154,147,164,247,7,30,176,197,64,214,128,9,113,142,48,177,124,219,119,88,93,170,104,144,85,103,97,7,154,14,216,207,140,169,34,2,125,32,81,135,99,97,67,8,81,160,142,7,83,157,236,32,134,82,136,15,171,109,21,13,26,227,8,11,191,75,38,6,214,174,1,17,26,109,33,236,208,6,219,183,187,94,3,34,160,42,113,198,243,209,19,171,199,250,82,67,132,212,146,40,130,241,214,177,97,66,0,164,142,10,9,145,175,247,208,159,126,207,161,222,212,17,129,28,18,69,92,240,5,116,23,18,178,60,124,10,15,199,66,217,240,240,53,31,37,163,228,240,61,31,173,71,235,195,95,233,104,171,124,120,181,138,243,78,34,127,10,151,157,253,160,138,3,171,167,250,74,224,46,60,158,245,104,124,216,142,14,210,143,127,141,14,86,157,195,246,146,96,118,14,19,57,131,105,175,79,78,194,143,107,177,168,21,118,14,163,45,214,196,225,83,237,3,115,245,49,61,248,235,222,48,231,243,61,96,254,57,253,243,222,0,163,232,110,128,233,159,219,209,71,224,184,47,76,14,195,200,162,15,8,157,235,210,249,36,154,97,215,90,37,188,40,230,226,149,41,3,109,171,140,120,134,213,89,207,211,228,130,119,205,197,198,119,235,121,28,135,179,32,214,130,116,198,107,175,90,235,112,44,102,241,228,160,151,23,176,218,1,67,203,231,150,60,229,8,50,206,251,38,29,202,83,57,31,153,212,230,213,105,103,152,187,251,88,168,194,185,216,16,160,134,222,142,114,196,229,22,194,79,163,199,237,183,29,253,124,20,99,151,232,166,229,233,184,33,48,169,37,98,89,104,161,229,201,254,149,121,161,186,168,121,113,107,205,150,218,15,125,67,177,136,88,18,143,150,88,87,255,254,205,203,23,163,120,171,127,119,123,93,222,52,110,172,248,102,143,138,63,133,1,34,66,234,53,191,29,137,8,22,212,175,68,67,76,245,172,3,144,20,129,49,25,181,90,152,72,82,54,182,60,67,192,153,132,41,148,83,68,113,148,164,5,155,1,163,159,104,15,14,226,16,18,85,51,44,119,119,244,105,123,2,186,208,246,84,48,121,44,38,126,197,100,185,163,255,80,96,112,253,164,221,218,172,8,170,216,169,197,98,61,82,16,128,65,91,179,114,247,22,105,231,5,25,85,218,49,135,138,20,123,154,117,10,36,235,128,246,34,208,251,243,32,222,132,199,8,198,225,190,101,35,17,53,243,45,112,57,190,104,183,16,157,149,114,72,16,197,141,130,24,180,107,12,232,114,151,89,22,22,155,83,255,117,4,160,71,28,24,244,13,118,10,195,209,191,93,79,183,7,216,7,152,227,40,219,254,87,135,182,78,31,76,40,92,103,71,111,184,25,110,3,29,161,54,180,105,0,210,98,7,85,54,21,200,166,38,188,85,15,81,87,177,55,113,50,43,87,87,49,61,67,112,72,213,29,11,86,37,233,130,194,69,152,50,17,39,253,225,229,139,239,177,220,34,163,85,142,35,19,155,21,88,222,249,241,213,235,55,45,189,197,221,17,212,7,141,35,83,28,54,236,1,41,218,151,182,129,210,14,83,115,53,18,171,230,201,102,57,105,99,134,138,250,225,228,40,197,12,126,29,196,95,35,30,230,150,237,39,5,245,73,144,130,75,34,44,76,196,0,175,14,91,95,181,110,222,239,82,21,127,38,198,86,196,155,43,110,117,236,122,21,221,73,150,170,124,33,184,192,30,172,82,51,106,90,233,195,126,243,89,28,254,47,238,212,22,61,74,150,164,81,87,144,192,117,136,165,194,229,44,44,186,196,61,162,141,108,20,160,136,67,172,39,121,180,65,30,1,9,138,63,28,141,48,81,236,124,2,222,45,116,120,31,196,69,205,2,109,89,15,234,92,87,93,82,231,74,124,6,148,128,163,4,43,232,122,64,247,110,171,250,207,194,151,13,106,158,240,93,187,245,150,165,171,208,98,18,156,116,68,12,16,250,201,225,194,111,104,224,226,174,253,95,211,17,253,13,172,141,8,190,20,3,55,226,219,4,75,16,76,55,9,49,222,43,22,193,196,35,178,98,5,139,2,100,166,168,221,210,99,61,54,41,190,159,212,47,163,116,44,210,193,198,138,38,200,200,182,14,101,129,173,136,138,194,62,198,167,227,153,153,50,104,155,150,224,127,166,1,81,173,122,63,178,15,14,30,32,252,118,29,173,226,240,155,54,174,29,72,17,231,242,199,100,131,64,71,172,93,47,227,43,77,88,7,28,135,90,155,22,78,59,136,59,140,17,41,169,162,12,77,52,1,59,50,140,223,89,167,140,178,137,128,85,196,129,182,144,129,109,144,85,187,243,128,87,77,91,183,130,47,129,206,20,68,68,62,144,27,243,151,155,199,46,81,89,196,228,162,210,191,221,92,146,0,63,95,194,122,65,2,255,178,199,238,61,150,167,99,44,214,134,84,234,91,177,59,221,70,3,112,110,80,174,93,217,13,255,64,133,105,64,251,153,118,57,228,242,185,125,252,3,182,12,44,248,234,121,185,223,193,244,200,120,11,218,103,167,52,10,167,65,7,0,47,15,255,36,63,130,17,29,125,56,150,137,249,229,4,163,223,113,172,228,78,148,19,233,2,78,190,214,135,103,33,214,74,67,125,24,76,177,11,113,141,208,2,3,62,44,237,130,156,193,225,12,83,3,41,199,242,144,117,103,104,169,83,6,50,196,64,26,77,84,18,7,128,12,191,12,253,176,23,158,109,107,176,13,99,125,193,177,240,32,208,80,107,181,182,116,197,203,53,93,200,96,204,67,10,25,24,218,166,127,108,92,132,103,239,163,181,65,67,53,161,18,26,193,228,183,13,162,129,72,245,142,141,69,242,193,192,120,194,57,67,239,216,72,202,103,165,195,41,218,49,166,1,226,86,175,134,155,200,200,130,101,102,32,210,40,130,43,6,35,31,46,140,77,164,27,208,176,56,52,68,130,254,132,162,167,94,6,227,215,124,250,12,245,245,215,225,44,9,181,183,207,245,159,146,51,44,194,235,223,135,241,121,184,142,198,129,246,67,136,232,181,199,41,2,116,244,31,144,163,189,6,124,189,212,72,235,49,129,214,160,100,216,173,249,110,145,252,22,193,41,80,224,84,66,126,254,250,106,113,150,32,192,129,65,149,235,200,110,32,164,108,147,2,81,233,187,13,151,112,71,130,88,100,66,222,35,150,140,122,246,246,44,153,92,93,47,224,62,98,7,205,58,46,211,57,90,206,129,229,122,59,79,175,101,10,69,12,17,235,100,142,226,39,98,21,37,215,237,213,229,54,56,59,75,135,23,40,128,248,89,190,252,231,180,115,93,97,23,109,240,165,140,204,16,227,123,152,82,155,48,207,184,138,104,114,124,87,129,237,220,214,231,142,62,119,245,185,167,207,125,125,222,197,222,27,250,199,252,84,104,113,202,69,181,19,1,34,193,202,168,215,27,82,229,206,116,236,139,36,203,153,0,43,129,128,236,64,99,75,230,87,127,127,54,1,11,23,43,29,74,44,10,21,242,179,72,150,73,182,194,126,176,254,250,217,75,28,27,63,133,51,92,130,144,234,47,67,56,238,58,146,130,113,162,35,10,20,234,16,100,250,139,8,17,26,220,188,70,165,145,177,73,35,152,253,31,194,11,61,7,37,122,195,253,179,195,197,54,3,207,226,82,159,251,214,87,91,108,190,35,4,110,85,74,237,249,95,85,88,105,29,175,146,12,215,255,160,163,42,214,253,24,3,12,9,105,108,4,136,196,89,14,105,159,155,170,16,52,40,56,44,223,98,104,152,142,79,109,2,54,120,140,83,58,99,63,237,154,233,71,155,206,208,210,92,215,27,165,3,137,113,176,130,191,172,14,182,136,228,132,93,213,35,178,70,122,178,90,207,224,232,173,116,52,79,215,115,16,96,196,204,6,21,218,86,56,187,35,232,149,220,6,73,175,228,11,74,146,149,104,16,147,38,249,175,201,124,174,42,43,24,123,178,128,150,234,143,232,128,160,204,26,97,44,25,204,218,2,106,6,154,202,18,239,56,84,82,156,156,202,51,54,194,234,4,180,71,108,223,105,174,47,52,184,7,0,53,14,135,162,214,241,89,48,126,79,244,90,78,36,181,185,37,68,98,128,17,229,204,104,129,97,89,52,62,100,115,56,197,8,150,209,212,254,26,81,199,212,205,33,118,137,19,153,9,217,141,150,152,166,69,19,97,219,177,87,156,92,136,218,202,53,184,190,73,94,134,67,133,45,123,64,70,182,138,150,134,236,112,145,135,70,171,121,202,166,48,22,178,247,232,235,120,222,216,123,34,234,52,10,227,201,177,196,222,72,166,83,16,110,104,56,48,57,69,51,2,68,73,177,155,128,9,170,228,117,104,8,55,196,136,175,112,187,153,254,36,52,185,177,200,54,11,136,195,213,181,188,150,102,136,139,31,64,5,140,11,91,94,247,249,203,38,89,135,250,36,214,39,19,125,199,110,233,243,84,159,70,51,8,50,150,153,200,150,40,193,218,114,63,209,183,194,42,23,162,134,181,31,120,117,215,69,2,6,132,77,172,195,31,217,96,140,68,235,98,184,165,30,54,73,42,214,251,48,155,45,85,207,181,13,44,38,197,80,76,222,178,114,130,70,36,29,28,226,50,103,27,152,171,231,110,214,117,2,115,133,208,217,161,45,53,230,203,193,56,112,131,169,2,213,12,101,31,0,74,123,82,204,198,149,246,92,143,55,41,130,173,135,43,132,75,64,178,182,67,240,128,12,211,68,101,200,208,191,109,180,152,233,217,249,76,63,143,38,97,162,195,61,60,135,229,13,54,147,40,209,163,105,10,183,82,15,17,40,55,209,69,60,69,206,74,102,96,221,70,46,176,228,20,135,12,146,193,129,67,151,106,228,35,139,82,17,105,177,62,117,154,67,100,169,219,113,165,216,221,81,174,18,245,31,87,2,94,14,53,235,184,41,227,42,207,96,173,135,33,15,75,133,139,180,162,28,162,2,144,144,159,102,239,195,139,82,13,62,45,10,243,53,190,148,109,151,207,145,47,207,87,193,146,114,139,19,100,201,19,132,49,207,141,15,9,198,12,153,2,79,18,230,222,200,150,193,10,50,153,70,227,53,34,131,16,208,15,115,114,25,193,198,93,137,98,179,20,211,18,152,46,131,98,98,140,124,144,146,64,242,220,243,40,184,57,115,157,236,228,129,108,8,167,136,115,100,48,218,206,195,137,241,1,17,47,42,109,9,127,30,104,65,251,73,7,235,169,146,226,59,133,113,89,80,185,29,178,167,48,123,100,136,202,41,194,54,73,201,208,172,213,229,110,158,144,112,237,203,233,116,90,202,148,169,233,236,172,237,15,52,108,50,104,142,215,213,142,52,19,113,72,59,32,164,149,214,44,188,191,164,11,159,74,69,110,200,187,53,89,180,30,78,118,178,207,226,13,144,146,199,136,48,159,75,94,138,20,242,213,211,0,174,119,193,151,43,150,28,149,48,223,132,185,28,138,20,140,53,80,172,156,59,52,156,151,114,179,112,21,5,234,100,130,240,222,28,109,137,2,70,57,78,174,224,149,39,238,32,152,103,213,49,205,51,118,80,206,115,118,113,207,179,170,157,200,147,149,17,171,167,215,123,89,100,136,238,98,64,82,73,255,50,10,255,50,10,255,50,10,255,50,10,48,10,102,150,26,180,156,117,157,11,115,112,134,201,35,156,105,44,226,200,25,183,114,59,232,48,247,236,148,247,103,80,42,118,218,82,132,216,95,12,133,79,114,140,197,166,21,38,130,184,172,16,177,141,244,198,70,204,28,126,43,75,56,121,143,23,105,176,170,173,231,108,77,213,242,46,46,91,90,111,226,89,101,145,167,82,182,166,152,76,26,150,154,85,2,84,28,78,215,72,160,63,58,101,238,224,156,255,139,4,71,38,152,62,118,11,183,88,253,95,161,12,77,68,81,130,78,28,62,145,185,31,12,223,186,254,192,83,210,203,161,143,18,139,51,132,19,72,31,26,54,147,155,118,100,97,202,235,214,242,60,149,227,212,50,138,58,94,45,199,22,25,113,81,133,123,164,42,164,69,122,165,35,139,117,9,51,234,66,142,22,50,242,42,148,225,230,201,121,211,156,92,148,175,20,47,146,43,197,37,154,107,35,239,50,167,202,210,236,233,86,253,222,45,22,179,105,146,149,167,138,211,45,174,211,8,47,243,68,58,81,37,141,74,78,41,109,107,10,153,171,186,193,230,28,136,75,177,149,104,32,229,23,211,207,19,187,142,74,206,211,108,172,70,112,218,133,49,192,130,39,73,165,83,36,253,242,206,233,195,168,254,114,170,178,232,76,100,184,86,57,131,207,100,134,83,201,160,51,202,152,98,227,93,166,145,91,191,253,247,247,225,21,79,21,50,141,38,176,144,186,235,98,126,47,12,65,27,129,167,147,112,134,117,112,51,88,98,238,205,186,132,162,226,132,244,129,78,53,59,211,136,50,88,124,142,150,83,186,94,21,164,16,243,21,140,86,60,145,169,207,107,176,138,79,171,10,6,145,45,159,150,226,162,66,140,255,156,33,166,122,98,18,95,79,173,39,0,183,124,62,91,5,88,155,28,11,120,245,196,250,12,154,165,1,134,240,226,154,15,38,17,89,20,86,253,228,66,102,98,240,168,103,34,9,59,10,144,27,76,147,113,45,32,198,106,116,154,167,87,60,115,206,134,34,105,107,210,114,110,52,189,82,69,242,83,185,52,92,47,38,175,238,223,41,199,38,77,229,110,205,25,92,15,251,26,191,67,37,58,148,226,136,148,34,193,21,9,189,34,197,227,20,161,74,188,196,2,215,129,5,69,154,73,114,60,54,217,112,128,23,73,145,42,18,207,106,5,100,35,42,255,178,14,64,181,41,82,85,102,177,188,42,51,140,9,123,47,42,95,76,251,69,90,94,228,151,119,191,124,137,24,180,129,29,64,198,203,174,99,62,28,217,213,149,59,114,49,28,79,115,124,205,33,7,3,75,105,237,134,106,8,134,47,183,112,102,157,185,103,253,123,180,128,48,100,205,238,193,147,233,123,123,53,66,3,49,34,191,172,253,187,224,12,52,196,40,227,235,239,213,128,76,65,27,205,77,152,206,78,81,247,166,162,238,78,81,239,166,162,30,138,206,200,95,9,141,110,222,59,56,114,165,158,213,23,251,168,119,110,79,27,80,255,170,125,203,235,113,191,102,117,162,221,13,246,38,162,53,2,198,80,187,55,92,15,112,125,248,172,190,125,43,92,118,64,246,135,234,67,70,229,247,70,168,164,198,202,33,82,106,181,186,164,177,87,166,138,225,90,140,190,202,117,146,67,181,26,146,81,222,169,22,111,42,93,20,246,170,133,201,94,212,202,10,19,130,162,126,173,168,48,72,245,210,202,76,161,66,183,94,161,177,188,44,126,5,51,167,178,216,55,168,66,87,190,141,130,142,226,5,89,10,159,164,94,62,39,11,132,171,10,190,17,122,94,56,103,132,40,204,204,216,41,173,88,148,150,72,83,163,2,47,174,203,17,129,143,197,194,156,26,12,196,118,224,162,180,19,98,246,69,91,213,13,196,50,180,203,172,92,188,161,52,23,229,34,184,213,76,180,145,208,229,198,1,238,38,181,69,160,11,46,65,30,99,65,188,190,248,159,103,200,182,206,176,218,249,94,8,57,159,151,196,188,144,109,154,104,89,101,169,46,23,37,185,230,115,214,67,68,221,222,5,13,10,210,245,181,126,69,249,110,6,56,184,27,160,221,195,252,83,115,7,123,0,196,136,11,83,113,39,68,215,211,16,139,173,13,42,195,65,35,72,76,68,247,1,232,0,187,110,159,62,119,1,188,10,99,204,139,96,163,239,134,73,54,204,194,224,120,55,37,37,208,189,16,69,215,49,20,222,141,104,125,52,169,194,164,177,68,149,232,90,249,66,186,217,69,109,18,70,158,146,9,243,153,9,223,85,164,96,225,133,47,158,39,175,44,73,113,173,107,213,212,234,229,161,149,23,237,75,59,43,50,21,187,39,49,239,153,190,167,16,191,28,50,34,56,72,125,85,144,194,112,188,57,195,82,201,89,248,1,27,156,109,211,195,164,211,196,149,49,157,114,149,9,77,133,169,172,105,251,25,124,85,90,31,255,37,159,99,202,245,114,229,214,229,212,146,9,157,98,135,179,152,149,74,16,60,219,196,252,128,124,253,59,193,136,33,129,28,45,89,155,102,154,251,86,102,195,89,170,59,55,188,59,235,84,204,140,172,7,137,188,179,158,116,9,203,213,202,126,233,157,245,155,253,86,9,73,100,238,11,163,228,157,86,234,11,155,130,9,215,157,128,246,118,237,44,120,19,182,139,111,197,254,236,186,118,10,15,233,88,236,137,192,223,201,241,80,146,83,200,54,54,237,239,22,158,6,189,68,189,127,136,86,201,70,201,129,127,136,183,146,236,122,240,13,133,183,54,99,139,153,57,173,42,229,156,86,214,167,111,13,57,227,6,159,183,95,212,43,124,212,74,141,191,147,167,202,219,221,57,118,236,100,195,30,15,57,121,239,137,68,101,185,245,22,97,147,141,169,173,105,154,29,203,150,212,94,59,140,130,198,49,80,184,163,85,177,95,95,219,203,102,203,33,97,241,130,45,110,151,80,224,219,180,202,155,227,84,172,57,119,216,123,176,106,89,229,197,231,78,115,30,119,187,188,162,188,71,35,88,30,29,183,61,244,237,240,182,246,234,13,202,150,74,145,6,141,149,69,30,98,17,43,153,59,169,34,65,47,214,167,11,134,112,133,38,222,139,102,10,206,223,189,216,94,195,112,135,247,156,156,11,244,125,155,186,65,164,239,108,139,76,235,189,219,106,54,161,245,182,86,33,236,191,188,123,208,95,249,204,144,103,172,187,255,136,105,235,29,77,10,127,242,62,109,58,142,134,43,219,180,94,117,157,97,239,54,203,102,92,108,171,237,55,178,238,110,198,113,116,64,49,45,200,243,232,234,115,233,244,21,197,75,178,93,218,189,131,22,201,165,198,130,101,124,142,12,218,178,43,146,197,126,158,76,254,99,45,157,224,240,174,198,31,74,25,98,139,79,229,148,171,136,205,190,61,9,165,188,129,123,12,184,123,140,248,55,12,184,59,70,152,17,100,101,144,232,53,88,229,79,176,199,55,129,21,6,250,95,166,249,190,166,249,86,122,178,85,129,81,187,135,57,195,13,9,120,246,136,59,31,220,105,206,110,106,86,88,150,123,182,139,169,27,205,51,237,158,115,75,187,195,40,107,155,124,79,74,254,205,117,132,22,78,29,186,246,183,251,11,133,199,238,169,11,110,87,131,25,117,43,179,197,29,69,184,173,73,55,112,207,220,241,125,154,244,251,26,198,193,110,101,61,226,94,77,134,94,216,13,207,238,211,164,227,244,65,89,12,188,119,44,223,222,212,42,143,140,24,38,246,111,177,135,5,18,159,134,167,79,105,174,88,61,190,161,65,44,31,239,214,157,85,86,231,85,205,125,150,83,27,150,231,111,151,56,209,84,93,218,246,24,177,155,164,237,174,166,212,178,212,254,205,52,45,80,221,217,76,201,106,119,174,111,139,137,221,173,205,203,24,229,141,11,137,234,109,43,94,141,27,22,181,117,154,155,27,170,169,192,45,203,65,205,146,191,87,67,60,234,222,221,66,243,104,186,87,11,197,2,83,99,51,88,108,218,169,87,138,238,20,146,65,215,148,53,132,142,138,120,161,82,225,102,62,248,224,3,252,57,27,250,90,66,190,161,94,83,31,110,192,229,159,141,134,162,34,110,246,82,172,211,217,187,229,110,159,94,223,100,106,250,55,3,18,102,64,141,0,85,48,123,104,105,211,56,112,171,150,222,54,3,191,199,248,179,223,20,252,166,214,121,56,174,244,187,220,254,126,211,192,134,158,223,53,202,223,60,255,188,87,203,251,76,64,75,109,151,125,28,41,243,141,14,86,63,55,207,123,161,1,20,186,180,76,125,219,212,244,126,88,8,127,235,158,104,208,100,206,178,53,255,54,119,235,139,207,249,249,72,149,107,71,52,190,0,235,24,55,44,23,1,40,8,189,96,39,95,68,120,107,165,93,36,77,108,35,29,19,24,71,2,225,93,33,141,226,112,142,53,25,82,165,89,102,223,13,23,228,213,154,182,69,7,199,90,121,75,72,163,203,133,100,210,223,132,131,91,193,193,169,225,96,113,211,249,193,63,6,135,47,27,158,79,131,91,180,23,161,149,121,56,26,45,125,227,217,42,184,238,136,22,208,249,168,152,240,138,89,22,207,120,161,10,95,233,26,253,118,142,85,184,22,24,43,46,200,186,173,125,121,169,105,137,36,216,235,4,73,106,17,94,20,195,243,197,231,184,86,148,175,70,145,241,17,67,187,155,79,248,190,156,186,244,46,95,188,38,47,55,112,113,127,154,201,89,109,97,156,58,34,215,183,9,118,190,92,207,39,181,240,30,103,39,188,71,133,225,241,37,1,95,124,126,175,72,34,244,162,244,216,30,200,130,188,249,61,69,56,182,49,55,237,28,231,42,99,153,3,236,127,112,196,144,193,151,150,34,206,145,99,118,0,4,87,117,202,235,56,113,73,231,81,254,172,176,19,186,240,79,227,123,106,136,59,59,211,8,241,78,122,164,167,154,90,56,231,251,115,139,241,255,157,116,100,78,53,218,139,22,207,30,195,51,101,0,10,119,238,215,34,220,179,162,65,88,112,91,124,209,132,40,47,94,13,21,212,211,159,30,21,79,2,59,57,66,177,122,45,9,77,178,183,245,168,92,72,29,127,118,50,119,118,30,75,134,174,59,156,183,122,116,50,119,31,209,157,28,54,242,33,101,56,61,57,90,137,76,213,128,220,73,214,40,184,15,241,201,134,223,122,68,87,60,209,245,202,184,48,246,124,166,97,244,164,199,67,224,98,111,211,105,105,151,139,120,137,90,116,107,77,220,89,243,226,226,194,188,112,233,206,154,71,116,71,189,35,148,111,105,244,192,181,39,201,229,168,69,179,225,190,103,209,172,181,165,169,43,205,109,60,88,77,136,214,168,229,226,184,204,152,42,245,91,184,26,28,252,68,94,85,145,143,43,20,94,225,6,10,116,213,115,108,164,184,123,54,30,22,7,169,72,38,147,22,167,225,94,253,27,220,181,126,137,7,82,64,240,91,116,187,145,133,109,153,174,230,219,230,32,134,107,98,186,134,111,14,206,123,221,49,208,52,123,36,95,154,107,98,234,129,175,103,58,113,15,231,158,217,253,176,176,7,166,175,217,54,234,32,20,207,232,82,157,65,76,199,90,47,207,52,171,217,56,21,5,76,123,183,72,143,10,120,57,132,174,105,27,125,207,244,198,6,116,221,0,22,134,11,212,232,223,51,251,154,21,27,93,154,160,0,65,174,0,248,90,119,64,133,6,38,42,27,62,37,122,72,136,209,35,100,81,145,129,217,167,236,46,117,114,0,140,92,224,208,71,175,112,138,102,75,197,186,84,204,167,98,253,106,49,63,198,226,105,15,199,40,228,83,33,207,176,93,163,103,250,40,210,5,86,182,107,246,69,47,186,93,228,1,61,119,44,177,39,250,25,8,161,224,127,208,241,220,232,117,63,144,12,19,183,26,185,215,196,41,220,238,205,180,201,51,56,199,29,29,77,123,110,184,32,10,142,125,211,159,187,24,146,248,112,128,100,117,236,206,81,2,141,217,61,68,83,66,92,207,251,232,212,135,133,107,131,227,0,210,7,70,115,2,229,158,211,225,135,133,131,158,226,38,106,166,61,38,65,0,158,154,103,128,32,196,39,151,15,250,72,130,96,128,109,26,160,211,129,167,33,29,53,93,116,210,246,204,30,49,172,11,17,241,32,71,54,81,11,55,187,66,33,58,232,146,60,17,183,125,128,6,31,28,240,129,8,63,39,122,163,69,27,148,242,32,113,174,1,236,88,16,113,134,187,135,65,58,152,25,14,36,200,96,20,249,136,90,67,62,18,224,31,64,86,197,17,178,6,132,34,121,80,36,187,150,72,243,197,17,234,0,54,166,89,0,194,165,73,206,108,144,196,113,0,12,201,93,112,12,253,5,50,4,19,124,227,250,92,148,143,152,114,4,11,253,34,250,240,17,126,252,115,3,242,214,5,53,187,102,247,28,80,153,14,134,139,78,251,16,17,52,226,3,67,121,224,19,218,16,45,18,94,116,139,142,156,30,117,70,67,38,228,136,26,65,66,151,208,147,71,146,240,46,0,128,231,84,142,180,202,195,67,189,88,83,21,185,128,19,36,215,35,236,233,8,37,136,130,182,1,108,29,84,133,108,162,171,36,189,232,13,88,37,249,225,144,82,137,3,226,14,18,123,64,131,16,230,211,34,3,157,33,44,0,10,28,102,221,67,67,92,3,12,238,49,199,153,189,121,6,100,141,229,199,28,0,203,1,10,129,5,252,3,61,21,71,80,31,238,24,186,133,100,136,175,1,245,134,201,1,19,145,131,115,252,119,209,176,55,71,102,119,12,17,33,49,233,226,219,3,214,30,255,247,161,119,184,233,44,122,68,157,69,38,36,205,0,171,6,134,3,148,196,17,241,133,200,206,180,161,74,56,2,169,81,53,182,33,28,44,242,172,154,56,38,136,46,228,90,252,51,191,192,0,112,2,53,232,31,236,37,33,50,108,50,141,168,67,255,100,61,137,51,232,249,24,116,6,139,192,18,54,11,160,34,91,7,54,123,172,39,144,254,177,176,99,2,83,54,52,68,62,74,33,91,75,199,61,52,67,226,227,146,113,2,12,179,7,102,67,77,128,65,31,217,44,243,104,129,140,55,29,125,88,248,172,30,48,56,160,2,85,167,126,144,50,144,157,162,127,146,37,48,129,148,26,95,250,135,73,60,119,33,65,115,224,230,157,147,226,67,152,136,121,164,171,208,50,100,177,160,136,35,129,30,137,44,99,200,162,10,186,67,38,88,234,251,231,62,58,65,160,128,75,143,112,243,80,21,89,160,223,57,18,129,57,9,45,148,158,218,38,158,209,63,130,191,81,147,196,121,110,91,231,224,137,67,226,76,10,192,98,66,212,198,15,173,192,148,57,1,106,128,63,164,97,176,109,98,148,96,139,65,74,76,194,1,217,231,127,24,100,166,49,87,224,127,26,220,136,72,104,78,152,72,96,96,131,47,88,236,2,37,88,128,152,89,64,148,128,128,93,128,74,71,192,137,52,144,18,72,214,197,1,231,0,95,140,63,66,230,145,0,186,201,44,54,125,160,57,39,208,56,33,14,40,7,99,20,122,68,200,66,238,176,38,67,58,194,156,97,213,146,255,108,147,44,28,19,78,62,253,115,50,224,161,60,110,0,73,36,38,173,150,25,196,37,22,32,218,251,34,27,43,192,96,112,2,99,208,172,28,9,168,199,93,12,227,231,124,8,100,6,231,93,216,189,185,77,188,196,1,4,137,250,39,210,160,188,49,15,39,152,179,153,125,48,11,230,154,19,60,141,19,136,55,49,4,129,48,244,230,52,174,160,103,68,94,172,21,65,179,72,247,161,151,24,146,8,18,101,145,45,195,141,41,73,97,193,71,22,28,48,4,0,33,41,32,200,185,59,0,190,184,202,129,134,39,20,70,9,216,251,115,58,66,109,18,112,8,41,184,68,18,136,47,137,50,169,147,248,74,114,145,218,139,28,200,1,204,7,73,5,165,208,89,254,229,178,156,47,115,168,60,212,147,45,38,186,66,236,58,7,30,220,20,12,26,248,72,6,149,135,68,22,120,96,69,232,17,249,104,240,97,233,70,112,28,17,134,37,219,230,127,232,13,161,68,22,139,199,68,16,133,52,102,64,118,140,68,20,195,129,28,242,8,101,250,167,65,199,130,224,10,43,71,255,208,24,240,13,163,207,28,45,192,113,32,162,224,8,116,194,33,43,6,76,23,228,149,172,44,13,172,132,8,255,3,48,35,69,72,144,234,8,191,141,198,55,152,34,194,128,240,35,141,36,251,71,250,45,254,73,122,73,105,168,101,26,100,28,228,184,16,5,57,66,147,166,65,34,25,109,170,76,86,85,152,36,32,79,30,17,217,6,143,134,58,178,22,56,67,219,144,86,58,32,85,149,38,136,124,1,156,66,24,104,68,230,35,114,226,132,238,195,6,66,155,186,36,16,187,78,18,102,53,231,116,223,250,207,148,231,174,166,20,114,131,113,103,222,81,158,61,208,37,9,154,186,64,65,43,95,137,160,241,37,56,26,95,31,84,248,211,39,15,12,3,143,52,230,27,10,137,59,34,105,134,81,228,170,166,43,247,209,107,110,171,122,81,67,209,154,87,113,222,169,185,167,252,136,48,220,11,73,92,240,94,110,16,37,104,194,88,58,167,233,156,40,86,224,33,239,94,180,59,147,16,243,186,34,148,27,107,5,52,225,149,127,152,104,136,133,113,204,1,235,129,236,26,47,26,150,67,119,196,178,129,90,244,199,122,3,22,121,42,59,174,50,73,236,150,150,79,114,8,229,160,53,154,89,250,26,197,11,107,116,245,20,211,77,16,143,238,230,199,23,102,84,217,85,76,92,197,254,198,169,72,201,241,124,39,23,254,100,122,169,253,90,78,222,121,153,90,230,135,184,25,18,230,124,123,204,242,228,124,206,41,77,231,232,184,50,249,163,61,28,79,205,196,136,72,52,165,163,0,202,186,183,47,82,197,86,45,77,52,253,60,137,232,139,103,98,96,6,77,212,171,36,211,3,36,242,116,201,252,120,51,198,253,10,52,241,167,110,120,1,157,226,121,6,36,230,37,249,137,154,243,125,55,128,115,43,54,144,65,125,231,220,46,37,224,31,195,165,83,78,48,156,159,97,32,95,136,202,31,90,71,0,152,196,87,124,187,30,94,141,64,203,54,250,10,197,70,132,171,131,49,155,139,228,109,34,195,57,239,150,211,48,72,193,251,131,191,76,206,191,75,57,82,205,171,172,192,101,198,181,52,13,143,39,165,235,156,248,118,153,181,226,71,59,229,79,142,132,182,84,19,249,62,21,242,153,126,124,55,53,86,166,226,6,95,138,152,242,198,163,90,128,27,232,173,192,95,126,234,3,63,154,100,246,161,133,245,1,121,99,192,86,233,158,91,109,190,255,88,167,162,228,71,21,29,174,46,118,176,5,192,189,48,249,206,43,183,153,156,218,141,219,246,54,58,30,155,56,40,180,232,75,101,238,89,1,44,238,125,90,89,21,81,96,112,165,164,80,127,44,147,148,215,41,164,249,96,147,125,195,242,77,85,175,43,26,205,215,90,105,23,134,184,156,175,166,135,101,24,226,58,189,220,142,237,152,18,242,41,253,93,3,177,163,216,117,82,210,221,252,84,27,165,64,39,9,175,220,68,190,18,163,174,233,254,170,186,30,213,196,217,6,18,139,27,78,214,22,158,234,104,90,95,85,97,86,40,91,149,157,93,73,122,45,238,245,120,155,32,85,111,7,185,199,64,41,248,36,6,176,6,41,186,159,185,244,176,132,166,204,37,29,255,61,204,37,192,124,154,177,172,94,188,80,182,146,152,72,96,167,26,215,166,6,88,6,99,19,200,51,224,62,252,172,94,15,41,42,13,110,13,29,86,11,201,159,60,13,187,42,84,44,79,144,64,42,133,104,66,72,83,139,74,161,157,230,120,254,216,253,83,197,144,98,174,68,134,154,150,110,188,6,59,138,85,208,178,60,241,179,88,67,37,39,144,237,178,112,21,69,133,104,149,37,139,111,174,123,155,92,149,239,34,185,167,84,193,33,250,127,85,170,228,245,43,37,153,90,96,154,212,35,255,221,192,236,201,43,13,191,152,67,240,10,39,102,161,222,227,98,204,165,11,80,230,149,97,153,234,27,110,133,251,52,180,14,206,153,239,149,209,182,55,55,45,187,81,26,10,94,85,13,62,93,97,94,53,69,111,151,184,245,55,70,90,44,133,51,243,155,37,165,10,83,222,7,187,66,138,203,172,121,208,40,183,245,99,140,138,120,64,55,150,241,131,25,182,19,170,109,229,15,12,223,21,75,60,171,156,111,253,118,171,197,171,222,227,122,239,161,19,220,219,103,80,171,213,220,145,114,27,219,15,242,226,48,49,138,130,32,165,107,189,107,227,94,190,47,209,64,51,177,185,86,190,196,167,62,120,40,114,236,59,132,52,82,169,58,173,170,146,41,31,12,186,52,114,243,21,246,183,140,220,205,132,82,143,103,223,29,101,118,134,236,170,241,162,23,109,231,208,221,198,235,174,95,189,228,137,32,49,119,77,221,160,60,31,236,105,35,84,171,93,34,79,147,17,155,166,37,133,175,83,185,90,174,54,121,218,113,69,226,89,121,166,85,154,127,168,176,0,153,86,11,147,184,105,98,147,79,83,42,169,77,161,45,37,237,42,109,228,53,33,80,202,168,97,81,39,60,232,135,219,53,210,253,42,249,150,238,224,36,217,71,166,104,56,121,164,158,143,127,114,36,10,221,89,25,114,250,34,90,195,220,60,123,141,61,253,215,63,62,127,246,236,245,13,149,97,177,184,153,187,60,171,127,172,148,125,75,1,14,111,159,223,41,100,113,112,22,198,10,15,117,35,20,181,223,206,120,85,154,175,222,1,162,129,232,229,153,9,7,93,211,179,125,89,134,119,158,248,171,136,155,75,181,188,129,140,70,65,24,72,20,33,219,187,77,84,28,235,1,156,93,191,226,89,23,33,28,213,217,125,41,93,78,241,235,41,42,164,87,74,106,83,46,2,65,106,171,0,40,149,107,64,190,184,80,142,57,23,225,229,59,161,249,77,101,202,81,233,154,72,82,87,63,189,123,136,39,200,139,36,21,199,32,79,41,42,128,174,249,83,217,124,9,97,57,33,223,31,175,52,162,46,202,168,164,202,147,74,15,69,18,46,15,148,71,184,224,79,181,92,185,104,172,162,245,42,176,181,218,203,210,28,165,105,250,65,2,202,242,120,151,234,204,33,136,165,49,166,136,83,211,138,192,63,248,14,255,68,117,251,62,72,39,100,80,180,231,223,238,169,114,164,18,120,176,38,215,122,254,109,29,219,127,182,185,80,6,81,251,89,196,10,52,117,226,179,207,62,43,225,62,149,53,100,133,150,118,123,15,154,39,126,136,201,200,135,111,113,103,50,60,41,147,150,59,178,27,67,7,228,4,214,245,41,168,229,31,179,116,137,126,202,211,102,28,100,28,146,186,95,3,118,231,16,177,195,65,54,42,228,201,103,220,176,190,66,183,74,167,73,119,245,150,231,244,220,122,109,164,61,60,122,136,82,194,86,138,6,255,185,75,160,202,151,187,239,82,40,89,141,210,77,6,118,150,69,97,89,209,156,88,22,37,175,188,97,109,212,249,31,90,27,213,180,39,8,25,213,112,87,242,122,208,205,13,139,110,36,161,127,95,97,200,111,101,223,238,252,127,192,124,0,248,31,101,62,248,135,123,148,203,85,3,222,131,145,172,109,88,130,42,130,178,242,68,20,71,236,25,14,17,122,133,112,205,71,255,13,10,108,23,134,230,146,0,0}; diff --git a/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h b/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h index 6df00faf..525c16aa 100644 --- a/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h +++ b/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h @@ -3,6 +3,6 @@ #include -extern const uint8_t ELEGANT_HTML[41354]; +extern const uint8_t ELEGANT_HTML[11640]; #endif From 5b7491c7a71fc762b23de387ddd87074f391a745 Mon Sep 17 00:00:00 2001 From: Jonny Date: Fri, 12 Sep 2025 09:01:28 +0100 Subject: [PATCH 089/150] Switch T-2CAN back to dio, and try 16mb --- .github/workflows/release-assets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml index 1e433b97..74772519 100644 --- a/.github/workflows/release-assets.yml +++ b/.github/workflows/release-assets.yml @@ -64,7 +64,7 @@ jobs: - name: 🛠 Build factory image for Lilygo 2-CAN run: | - esptool --chip esp32s3 merge-bin -o .pio/build/lilygo_2CAN_330/factory.bin --flash-mode qio --flash-freq 80m --flash-size 4MB 0x0000 .pio/build/lilygo_2CAN_330/bootloader.bin 0x8000 .pio/build/lilygo_2CAN_330/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/lilygo_2CAN_330/firmware.bin + esptool --chip esp32s3 merge-bin -o .pio/build/lilygo_2CAN_330/factory.bin --flash-mode dio --flash-freq 40m --flash-size 16MB 0x0000 .pio/build/lilygo_2CAN_330/bootloader.bin 0x8000 .pio/build/lilygo_2CAN_330/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/lilygo_2CAN_330/firmware.bin mv .pio/build/lilygo_2CAN_330/factory.bin output/BE_${{ steps.vars.outputs.tag }}_LilygoT-2CAN.factory.bin - name: 🛠 Build ota image for Stark From 9554cbf808a2c31b9dcdeb957a922d2a3fe6efa6 Mon Sep 17 00:00:00 2001 From: Jonny Date: Fri, 12 Sep 2025 15:19:32 +0100 Subject: [PATCH 090/150] Include CAN interface number in logs (with distinct TX/RX) --- Software/src/battery/MEB-BATTERY.cpp | 2 +- Software/src/communication/can/comm_can.cpp | 26 ++++++++++++------- Software/src/communication/can/comm_can.h | 6 ++--- Software/src/communication/can/obd.cpp | 6 ++--- Software/src/communication/can/obd.h | 4 +-- Software/src/devboard/webserver/webserver.cpp | 2 +- test/emul/can.cpp | 4 +-- 7 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Software/src/battery/MEB-BATTERY.cpp b/Software/src/battery/MEB-BATTERY.cpp index a20ccb2e..bda14b14 100644 --- a/Software/src/battery/MEB-BATTERY.cpp +++ b/Software/src/battery/MEB-BATTERY.cpp @@ -1271,7 +1271,7 @@ void MebBattery::handle_incoming_can_frame(CAN_frame rx_frame) { } break; case 0x18DAF105: - handle_obd_frame(rx_frame); + handle_obd_frame(rx_frame, can_interface); break; default: break; diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index 4696d8df..a9e3e615 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -228,11 +228,11 @@ bool init_CAN() { return true; } -void transmit_can_frame_to_interface(const CAN_frame* tx_frame, int interface) { +void transmit_can_frame_to_interface(const CAN_frame* tx_frame, CAN_Interface interface) { if (!allowed_to_send_CAN) { return; } - print_can_frame(*tx_frame, frameDirection(MSG_TX)); + print_can_frame(*tx_frame, interface, frameDirection(MSG_TX)); if (datalayer.system.info.CAN_SD_logging_active) { add_can_frame_to_buffer(*tx_frame, frameDirection(MSG_TX)); @@ -367,13 +367,20 @@ void receive_frame_canfd_addon() { // This section checks if we have a complete } // Support functions -void print_can_frame(CAN_frame frame, frameDirection msgDir) { +void print_can_frame(CAN_frame frame, CAN_Interface interface, frameDirection msgDir) { if (datalayer.system.info.CAN_usb_logging_active) { uint8_t i = 0; Serial.print("("); Serial.print(millis() / 1000.0); - (msgDir == MSG_RX) ? Serial.print(") RX0 ") : Serial.print(") TX1 "); + if (msgDir == MSG_RX) { + Serial.print(") RX"); + Serial.print((int)(interface * 2)); + } else { + Serial.print(") TX"); + Serial.print((int)(interface * 2) + 1); + } + Serial.print(" "); Serial.print(frame.ID, HEX); Serial.print(" ["); Serial.print(frame.DLC); @@ -388,7 +395,7 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { } if (datalayer.system.info.can_logging_active) { // If user clicked on CAN Logging page in webserver, start recording - dump_can_frame(frame, msgDir); + dump_can_frame(frame, interface, msgDir); } } @@ -396,7 +403,7 @@ void map_can_frame_to_variable(CAN_frame* rx_frame, CAN_Interface interface) { if (interface != CANFD_NATIVE) { //Avoid printing twice due to receive_frame_canfd_addon sending to both FD interfaces //TODO: This check can be removed later when refactored to use inline functions for logging - print_can_frame(*rx_frame, frameDirection(MSG_RX)); + print_can_frame(*rx_frame, interface, frameDirection(MSG_RX)); } if (datalayer.system.info.CAN_SD_logging_active) { @@ -416,7 +423,7 @@ void map_can_frame_to_variable(CAN_frame* rx_frame, CAN_Interface interface) { } } -void dump_can_frame(CAN_frame& frame, frameDirection msgDir) { +void dump_can_frame(CAN_frame& frame, CAN_Interface interface, frameDirection msgDir) { char* message_string = datalayer.system.info.logged_can_messages; int offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer size_t message_string_size = sizeof(datalayer.system.info.logged_can_messages); @@ -430,8 +437,9 @@ void dump_can_frame(CAN_frame& frame, frameDirection msgDir) { offset += snprintf(message_string + offset, message_string_size - offset, "(%lu.%03lu) ", currentTime / 1000, currentTime % 1000); - // Add direction. The 0 and 1 after RX and TX ensures that SavvyCAN puts TX and RX in a different bus. - offset += snprintf(message_string + offset, message_string_size - offset, "%s ", (msgDir == MSG_RX) ? "RX0" : "TX1"); + // Add direction. Multiplying the interface by two ensures that SavvyCAN puts TX and RX in a different bus. + offset += snprintf(message_string + offset, message_string_size - offset, "%s%d ", (msgDir == MSG_RX) ? "RX" : "TX", + (int)(interface * 2) + (msgDir == MSG_RX ? 0 : 1)); // Add ID and DLC offset += snprintf(message_string + offset, message_string_size - offset, "%X [%u] ", frame.ID, frame.DLC); diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h index 2efad224..e77e86c2 100644 --- a/Software/src/communication/can/comm_can.h +++ b/Software/src/communication/can/comm_can.h @@ -7,8 +7,8 @@ extern bool use_canfd_as_can; extern uint8_t user_selected_can_addon_crystal_frequency_mhz; extern uint8_t user_selected_canfd_addon_crystal_frequency_mhz; -void dump_can_frame(CAN_frame& frame, frameDirection msgDir); -void transmit_can_frame_to_interface(const CAN_frame* tx_frame, int interface); +void dump_can_frame(CAN_frame& frame, CAN_Interface interface, frameDirection msgDir); +void transmit_can_frame_to_interface(const CAN_frame* tx_frame, CAN_Interface interface); //These defines are not used if user updates values via Settings page #define CRYSTAL_FREQUENCY_MHZ 8 @@ -94,7 +94,7 @@ void receive_frame_canfd_addon(); * * @return void */ -void print_can_frame(CAN_frame frame, frameDirection msgDir); +void print_can_frame(CAN_frame frame, CAN_Interface interface, frameDirection msgDir); // Stop/pause CAN communication for all interfaces void stop_can(); diff --git a/Software/src/communication/can/obd.cpp b/Software/src/communication/can/obd.cpp index ec2bc49b..26aab251 100644 --- a/Software/src/communication/can/obd.cpp +++ b/Software/src/communication/can/obd.cpp @@ -23,7 +23,7 @@ void show_dtc(uint8_t byte0, uint8_t byte1) { logging.printf("%c%d\n", letter, ((byte0 & 0x3F) << 8) | byte1); } -void handle_obd_frame(CAN_frame& rx_frame) { +void handle_obd_frame(CAN_frame& rx_frame, CAN_Interface interface) { if (rx_frame.data.u8[1] == 0x7F) { const char* error_str = "?"; switch (rx_frame.data.u8[3]) { // See https://automotive.wiki/index.php/ISO_14229 @@ -105,10 +105,10 @@ void handle_obd_frame(CAN_frame& rx_frame) { logging.printf("ODBx reply frame received:\n"); } } - dump_can_frame(rx_frame, MSG_RX); + dump_can_frame(rx_frame, interface, MSG_RX); } -void transmit_obd_can_frame(unsigned int address, int interface, bool canFD) { +void transmit_obd_can_frame(unsigned int address, CAN_Interface interface, bool canFD) { static CAN_frame OBD_frame; OBD_frame.FD = canFD; OBD_frame.ID = address; diff --git a/Software/src/communication/can/obd.h b/Software/src/communication/can/obd.h index 2a495820..38671d4a 100644 --- a/Software/src/communication/can/obd.h +++ b/Software/src/communication/can/obd.h @@ -3,8 +3,8 @@ #include "comm_can.h" -void handle_obd_frame(CAN_frame& rx_frame); +void handle_obd_frame(CAN_frame& rx_frame, CAN_Interface interface); -void transmit_obd_can_frame(unsigned int address, int interface, bool canFD); +void transmit_obd_can_frame(unsigned int address, CAN_Interface interface, bool canFD); #endif // _OBD_H_ diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 74599e62..5a58b66a 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -157,7 +157,7 @@ void canReplayTask(void* param) { (datalayer.system.info.can_replay_interface == CANFD_ADDON_MCP2518); currentFrame.ext_ID = (currentFrame.ID > 0x7F0); - transmit_can_frame_to_interface(¤tFrame, datalayer.system.info.can_replay_interface); + transmit_can_frame_to_interface(¤tFrame, (CAN_Interface)datalayer.system.info.can_replay_interface); } } while (datalayer.system.info.loop_playback); diff --git a/test/emul/can.cpp b/test/emul/can.cpp index 8beb1574..2903a1c6 100644 --- a/test/emul/can.cpp +++ b/test/emul/can.cpp @@ -1,7 +1,7 @@ #include "../../Software/src/communication/Transmitter.h" #include "../../Software/src/communication/can/comm_can.h" -void transmit_can_frame_to_interface(const CAN_frame* tx_frame, int interface) {} +void transmit_can_frame_to_interface(const CAN_frame* tx_frame, CAN_Interface interface) {} void register_can_receiver(CanReceiver* receiver, CAN_Interface interface, CAN_Speed speed) {} @@ -19,4 +19,4 @@ char const* getCANInterfaceName(CAN_Interface) { void register_transmitter(Transmitter* transmitter) {} -void dump_can_frame(CAN_frame& frame, frameDirection msgDir) {} +void dump_can_frame(CAN_frame& frame, CAN_Interface interface, frameDirection msgDir) {} From 5510d3aeb5e83dd3071c8a3b9651c52306fc89f2 Mon Sep 17 00:00:00 2001 From: Jonny Date: Fri, 12 Sep 2025 20:07:25 +0100 Subject: [PATCH 091/150] Wait at most 100ms for Serial in init_serial on 2CAN so it will boot without USB --- Software/Software.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Software/Software.cpp b/Software/Software.cpp index 95f25ed8..19cb5382 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -67,7 +67,18 @@ void register_transmitter(Transmitter* transmitter) { void init_serial() { // Init Serial monitor Serial.begin(115200); +#if HW_LILYGO2CAN + // Wait up to 100ms for Serial to be available. On the ESP32S3 Serial is + // provided by the USB controller, so will only work if the board is connected + // to a computer. + for (int i = 0; i < 10; i++) { + if (Serial) + break; + delay(10); + } +#else while (!Serial) {} +#endif } void connectivity_loop(void*) { From 7178e0376ef0a74a1c2c34254719bdb4182f3e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 12 Sep 2025 22:19:44 +0300 Subject: [PATCH 092/150] Reduce CAN messages used by Kia PHEV --- .../battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp | 16 ++++++++---- .../src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h | 25 ++++--------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp index 38c32872..d17b4aca 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp @@ -201,15 +201,21 @@ void KiaHyundaiHybridBattery::transmit_can(unsigned long currentMillis) { } poll_data_pid++; if (poll_data_pid == 1) { - transmit_can_frame(&KIA_7E4_id1); + KIA_7E4.data.u8[2] = 0x01; + KIA_7E4.data.u8[3] = 0x00; + transmit_can_frame(&KIA_7E4); } else if (poll_data_pid == 2) { - transmit_can_frame(&KIA_7E4_id2); + KIA_7E4.data.u8[2] = 0x02; + transmit_can_frame(&KIA_7E4); } else if (poll_data_pid == 3) { - transmit_can_frame(&KIA_7E4_id3); + KIA_7E4.data.u8[2] = 0x03; + transmit_can_frame(&KIA_7E4); } else if (poll_data_pid == 4) { - + //Group 4 not polled } else if (poll_data_pid == 5) { - transmit_can_frame(&KIA_7E4_id5); + KIA_7E4.data.u8[2] = 0x05; + KIA_7E4.data.u8[3] = 0x04; + transmit_can_frame(&KIA_7E4); } } } diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h index 3bd9f499..e1b5366a 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h @@ -34,26 +34,11 @@ class KiaHyundaiHybridBattery : public CanBattery { uint16_t min_cell_voltage_mv = 3700; uint16_t max_cell_voltage_mv = 3700; - CAN_frame KIA_7E4_id1 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x02, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}}; - CAN_frame KIA_7E4_id2 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x02, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}}; - CAN_frame KIA_7E4_id3 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x02, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}; - CAN_frame KIA_7E4_id5 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x02, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00}}; + CAN_frame KIA_7E4 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E4, + .data = {0x02, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}}; CAN_frame KIA_7E4_ack = {.FD = false, .ext_ID = false, .DLC = 8, From 2546b6da21ac11709d7627d1a6de94e7cff847b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 12 Sep 2025 22:32:03 +0300 Subject: [PATCH 093/150] Reduce CAN templates in BYD-CAN --- Software/src/inverter/BYD-CAN.cpp | 12 ++++++++---- Software/src/inverter/BYD-CAN.h | 25 +++++-------------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index a779a270..10c4a3a0 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -166,8 +166,12 @@ void BydCanInverter::send_initial_data() { transmit_can_frame(&BYD_250); transmit_can_frame(&BYD_290); transmit_can_frame(&BYD_2D0); - transmit_can_frame(&BYD_3D0_0); - transmit_can_frame(&BYD_3D0_1); - transmit_can_frame(&BYD_3D0_2); - transmit_can_frame(&BYD_3D0_3); + BYD_3D0.data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}; //Battery + transmit_can_frame(&BYD_3D0); + BYD_3D0.data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}; //-Box Pr + transmit_can_frame(&BYD_3D0); + BYD_3D0.data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}; //emium H + transmit_can_frame(&BYD_3D0); + BYD_3D0.data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}; //VS + transmit_can_frame(&BYD_3D0); } diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index 4eb63918..e7af38c5 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -40,26 +40,11 @@ class BydCanInverter : public CanInverterProtocol { .DLC = 8, .ID = 0x2D0, .data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //BYD - CAN_frame BYD_3D0_0 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x3D0, - .data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //Battery - CAN_frame BYD_3D0_1 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x3D0, - .data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}}; //-Box Pr - CAN_frame BYD_3D0_2 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x3D0, - .data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}}; //emium H - CAN_frame BYD_3D0_3 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x3D0, - .data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VS + CAN_frame BYD_3D0 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x3D0, + .data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //Battery //Actual content messages CAN_frame BYD_110 = {.FD = false, .ext_ID = false, From fdc1fb61ba162b53d5b72537ceca5c7e12454f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 12 Sep 2025 22:39:01 +0300 Subject: [PATCH 094/150] Improve Afore writing of name --- Software/src/inverter/AFORE-CAN.cpp | 9 ++++----- Software/src/inverter/AFORE-CAN.h | 5 ----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Software/src/inverter/AFORE-CAN.cpp b/Software/src/inverter/AFORE-CAN.cpp index a195e4ab..ade4756b 100644 --- a/Software/src/inverter/AFORE-CAN.cpp +++ b/Software/src/inverter/AFORE-CAN.cpp @@ -139,11 +139,10 @@ void AforeCanInverter::map_can_frame_to_variable(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x305: // Every 1s from inverter datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - char0 = rx_frame.data.u8[0]; // A - char1 = rx_frame.data.u8[0]; // F - char2 = rx_frame.data.u8[0]; // O - char3 = rx_frame.data.u8[0]; // R - char4 = rx_frame.data.u8[0]; // E + for (uint8_t i = 0; i < 5; i++) { + datalayer.system.info.inverter_brand[i] = rx_frame.data.u8[i]; + } + datalayer.system.info.inverter_brand[7] = '\0'; inverter_status = rx_frame.data.u8[7]; time_to_send_info = true; break; diff --git a/Software/src/inverter/AFORE-CAN.h b/Software/src/inverter/AFORE-CAN.h index 96e59ec6..09f9eb09 100644 --- a/Software/src/inverter/AFORE-CAN.h +++ b/Software/src/inverter/AFORE-CAN.h @@ -16,11 +16,6 @@ class AforeCanInverter : public CanInverterProtocol { uint8_t inverter_status = 0; //0 = init, 1 = standby, 2 = starting, 3 = grid connected, 4 off-grid, 5 diesel generator, 6 grid connected, but disconnected, 7off grid and disconnected, 8 = power failure processing, 9 = power off, 10 = Failure bool time_to_send_info = false; - uint8_t char0 = 0; - uint8_t char1 = 0; - uint8_t char2 = 0; - uint8_t char3 = 0; - uint8_t char4 = 0; //Actual content messages CAN_frame AFORE_350 = {.FD = false, // Operation information .ext_ID = false, From bf14553d777621d1f20fde0746181681600be463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 13 Sep 2025 10:53:11 +0300 Subject: [PATCH 095/150] Add notes on BYD messages --- Software/src/inverter/BYD-CAN.cpp | 14 +++++++++----- Software/src/inverter/BYD-CAN.h | 10 +++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 10c4a3a0..e57b2c6c 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -69,6 +69,10 @@ void BydCanInverter:: BYD_150.data.u8[6] = (fully_charged_capacity_ah >> 8); BYD_150.data.u8[7] = (fully_charged_capacity_ah & 0x00FF); + //Alarms + //TODO: BYD Alarms are not implemented yet. Investigation needed on the bits in this message + //BYD_190.data.u8[0] = + //Voltage (ex 370.0) BYD_1D0.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8); BYD_1D0.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF); @@ -144,21 +148,21 @@ void BydCanInverter::transmit_can(unsigned long currentMillis) { if (currentMillis - previousMillis2s >= INTERVAL_2_S) { previousMillis2s = currentMillis; - transmit_can_frame(&BYD_110); + transmit_can_frame(&BYD_110); //Send Limits } // Send 10s CAN Message if (currentMillis - previousMillis10s >= INTERVAL_10_S) { previousMillis10s = currentMillis; - transmit_can_frame(&BYD_150); - transmit_can_frame(&BYD_1D0); - transmit_can_frame(&BYD_210); + transmit_can_frame(&BYD_150); //Send States + transmit_can_frame(&BYD_1D0); //Send Battery Info + transmit_can_frame(&BYD_210); //Send Cell Info } //Send 60s message if (currentMillis - previousMillis60s >= INTERVAL_60_S) { previousMillis60s = currentMillis; - transmit_can_frame(&BYD_190); + transmit_can_frame(&BYD_190); //Send Alarm } } diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index e7af38c5..09538ad3 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -46,27 +46,27 @@ class BydCanInverter : public CanInverterProtocol { .ID = 0x3D0, .data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //Battery //Actual content messages - CAN_frame BYD_110 = {.FD = false, + CAN_frame BYD_110 = {.FD = false, //Limits .ext_ID = false, .DLC = 8, .ID = 0x110, .data = {0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - CAN_frame BYD_150 = {.FD = false, + CAN_frame BYD_150 = {.FD = false, //States .ext_ID = false, .DLC = 8, .ID = 0x150, .data = {0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00}}; - CAN_frame BYD_190 = {.FD = false, + CAN_frame BYD_190 = {.FD = false, //Alarm .ext_ID = false, .DLC = 8, .ID = 0x190, .data = {0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}; - CAN_frame BYD_1D0 = {.FD = false, + CAN_frame BYD_1D0 = {.FD = false, //Battery Info .ext_ID = false, .DLC = 8, .ID = 0x1D0, .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08}}; - CAN_frame BYD_210 = {.FD = false, + CAN_frame BYD_210 = {.FD = false, //Cell info .ext_ID = false, .DLC = 8, .ID = 0x210, From b5d14edb9407a8f5f7f7bb2062073e4ea9e8574c Mon Sep 17 00:00:00 2001 From: korhojoa Date: Sat, 13 Sep 2025 17:28:47 +0300 Subject: [PATCH 096/150] Repackage OTA gzip with zopfli --- Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp | 2 +- Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp b/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp index 4a00db1f..6bab7982 100644 --- a/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp +++ b/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.cpp @@ -1,3 +1,3 @@ #include "elop.h" -const uint8_t ELEGANT_HTML[11640] PROGMEM = {31,139,8,0,128,47,232,102,0,255,237,125,249,127,219,70,146,239,207,201,231,147,255,1,102,54,50,25,1,16,78,94,18,157,181,157,120,226,93,59,206,139,237,204,225,104,178,16,9,146,136,65,130,3,144,58,44,115,254,246,253,86,117,55,46,66,18,229,57,118,223,123,195,19,232,163,186,186,174,174,238,46,0,39,15,38,201,120,125,181,10,181,249,122,17,63,250,226,243,19,250,215,226,96,57,27,181,194,101,11,41,154,118,50,15,131,9,31,225,120,17,174,3,109,60,15,210,44,92,143,90,111,223,60,51,250,45,237,168,146,187,12,22,225,168,117,30,133,23,171,36,93,183,180,113,178,92,135,75,148,190,136,38,235,249,104,18,158,71,227,208,224,19,93,139,150,209,58,10,98,35,27,7,113,56,178,77,171,4,109,29,173,227,240,209,147,96,189,14,211,43,237,187,197,38,14,214,73,170,189,122,243,88,123,187,154,4,235,240,228,72,20,1,222,217,56,141,86,107,28,197,225,90,139,147,96,18,45,103,223,70,231,111,194,203,181,54,210,90,47,68,138,105,154,173,227,47,62,15,178,171,229,88,155,110,150,227,117,148,44,209,157,112,252,94,129,127,189,14,214,155,236,167,240,44,73,214,237,142,118,253,197,231,159,161,3,217,90,67,131,1,64,5,23,65,180,214,102,225,250,91,156,183,31,30,253,46,92,63,139,210,197,69,144,134,207,151,211,228,97,7,240,63,139,166,90,155,202,139,250,159,129,200,155,5,72,96,162,218,119,113,72,135,79,174,158,79,218,15,167,178,230,207,97,154,1,147,135,29,115,13,132,159,10,130,161,49,130,97,170,66,4,248,102,80,96,201,132,145,248,182,25,138,202,103,40,217,58,89,73,146,124,55,13,199,232,40,39,167,33,184,250,51,24,135,243,207,240,66,218,86,11,227,44,20,221,56,58,42,152,176,76,214,90,178,140,163,101,168,107,239,195,112,165,17,89,0,142,161,135,235,55,209,34,76,54,235,246,141,164,213,53,199,178,172,206,177,6,160,79,169,144,22,204,130,104,9,121,208,28,45,11,65,242,73,70,205,127,241,249,22,168,229,172,202,214,65,186,174,98,126,43,133,91,41,183,134,210,198,34,204,178,96,22,182,106,212,169,202,202,237,52,46,128,145,76,3,221,48,5,177,199,113,144,101,47,162,108,109,166,225,34,57,15,193,139,104,50,9,193,205,219,161,73,189,168,64,8,38,229,102,94,9,24,32,66,137,0,117,206,221,46,97,119,161,204,13,126,58,190,170,199,183,163,12,158,9,174,255,30,66,34,48,222,85,81,81,162,80,82,165,118,209,185,77,50,124,19,86,217,102,60,6,103,159,38,241,102,33,187,32,21,240,1,85,45,225,42,9,144,21,253,149,234,89,146,215,29,249,210,53,155,229,116,127,185,246,85,249,29,217,133,209,249,158,91,126,74,56,85,141,203,29,189,92,165,201,12,218,89,233,102,94,211,185,173,102,192,141,103,79,54,235,53,254,184,166,50,80,251,145,71,227,38,204,108,125,21,135,230,36,202,86,113,112,53,122,120,22,39,227,247,15,171,6,162,185,228,50,89,134,92,80,144,67,96,157,156,101,97,122,30,166,192,124,25,94,104,47,55,32,33,208,124,37,147,219,32,206,232,145,228,78,157,108,36,94,244,83,133,244,12,35,73,54,227,113,1,188,219,7,110,93,44,21,220,218,232,160,76,125,26,130,217,209,121,248,99,176,158,51,101,52,109,141,97,137,15,52,26,228,128,12,88,180,194,65,152,143,19,211,112,61,158,87,171,162,5,170,64,28,80,197,205,228,125,7,40,49,90,13,131,77,94,236,183,44,89,2,79,178,153,63,210,8,92,180,23,100,218,127,188,126,245,131,48,226,235,77,186,100,8,82,10,53,109,171,141,3,32,162,181,195,52,77,82,137,189,6,56,212,90,2,110,113,122,251,225,51,66,87,227,147,225,67,93,28,40,132,37,220,229,38,142,57,69,242,243,34,90,78,146,11,19,99,1,180,6,40,23,20,166,145,88,141,58,218,168,245,13,43,53,37,170,1,77,165,225,131,30,189,70,78,160,173,133,130,105,201,20,138,167,6,2,173,77,74,104,105,139,40,142,35,153,6,130,21,116,87,181,4,215,127,76,147,5,138,181,219,191,234,192,250,55,104,49,227,36,42,208,171,164,200,2,93,81,170,77,149,191,19,148,248,41,252,203,38,148,144,39,26,74,66,29,132,45,176,100,203,66,147,152,138,218,79,193,56,212,206,194,245,69,24,230,2,163,5,203,137,182,158,135,10,57,81,75,226,102,166,168,209,126,119,139,27,161,171,122,167,178,61,122,153,128,183,100,207,66,18,89,101,40,137,202,157,142,114,6,189,254,110,46,200,222,128,239,225,144,148,225,109,201,156,144,28,11,117,248,116,223,169,37,133,157,69,236,211,28,167,26,8,86,37,137,101,153,41,172,91,162,104,110,93,254,22,188,37,227,255,54,204,203,64,10,172,25,34,190,205,14,224,167,143,69,202,10,155,242,128,7,23,93,187,214,224,188,167,209,217,102,29,102,67,152,203,13,188,197,60,229,89,20,195,177,31,106,239,30,242,32,244,240,84,226,183,223,184,214,48,238,55,15,5,101,148,156,79,67,137,236,220,209,17,77,85,32,186,233,123,109,19,125,241,121,142,152,58,144,216,213,124,171,22,85,104,17,16,12,152,65,252,26,238,2,156,80,210,99,154,36,113,38,242,78,142,242,249,11,207,124,196,153,70,51,179,81,107,145,76,54,113,136,121,84,154,100,89,146,70,179,104,137,114,109,53,64,193,159,18,20,155,142,114,156,198,105,136,233,145,196,168,221,130,155,14,28,224,172,197,132,215,113,52,109,79,15,14,166,102,182,89,209,12,45,43,31,183,101,115,43,20,134,124,180,58,29,97,247,143,167,176,138,162,157,128,140,115,222,20,204,100,122,245,58,140,33,68,73,250,56,142,219,15,169,181,119,168,174,48,87,160,78,97,66,39,237,160,115,220,56,50,7,163,71,215,69,27,99,106,35,232,0,211,177,201,84,24,141,90,227,121,20,79,168,3,173,78,81,48,162,130,99,34,117,56,249,33,153,132,89,39,50,215,193,236,7,154,131,162,206,139,231,63,252,103,235,224,32,162,190,211,121,21,163,131,131,73,59,234,108,59,133,136,200,94,233,215,121,99,195,7,150,158,109,206,214,105,24,226,16,226,80,248,115,232,139,36,253,120,116,189,61,150,3,100,96,70,208,194,89,26,173,175,14,14,128,126,126,54,42,229,116,244,0,40,77,97,51,194,244,199,36,142,198,162,108,53,9,21,170,9,84,139,165,224,21,75,1,117,104,147,133,6,184,13,239,136,166,209,89,235,155,49,49,95,157,142,90,209,114,28,111,38,97,107,184,83,51,128,99,118,181,72,54,187,117,48,66,173,91,195,90,98,6,138,26,66,250,90,250,120,155,83,129,56,122,13,62,5,102,184,82,178,66,199,163,7,214,177,34,14,81,234,88,184,66,176,251,232,147,62,238,108,183,29,24,157,6,165,0,106,172,22,31,63,62,104,183,56,9,157,192,148,190,40,216,57,56,144,94,199,130,44,239,203,112,18,5,237,86,27,92,5,177,50,76,116,226,36,197,130,2,85,29,178,194,118,32,252,92,52,204,190,201,121,188,159,226,234,55,206,44,41,255,37,36,142,103,175,103,201,37,218,224,89,65,56,65,215,59,195,125,218,145,179,167,191,169,41,187,115,124,159,122,232,218,119,231,40,64,237,135,152,12,182,91,99,72,214,251,150,94,50,39,159,128,199,189,201,122,163,53,252,36,202,53,65,139,163,217,28,166,162,172,177,143,219,113,231,90,170,105,124,112,16,155,191,254,26,102,232,16,76,194,193,193,171,51,242,1,77,140,110,235,132,76,14,28,148,236,213,197,18,14,219,42,76,215,87,24,229,97,220,98,189,53,9,167,193,38,6,228,111,98,83,30,15,227,237,121,144,106,47,70,215,225,37,91,209,225,245,118,171,95,86,78,143,203,6,155,74,195,62,62,126,242,244,219,239,158,253,238,251,231,255,241,159,47,94,254,240,234,199,255,243,211,235,55,111,127,254,253,31,254,248,167,224,108,12,216,179,121,244,219,251,120,177,76,86,127,73,179,245,230,252,226,242,234,131,101,59,174,231,119,123,253,193,225,17,184,54,186,6,190,241,48,135,157,233,147,188,139,217,201,201,228,99,246,232,209,35,215,49,38,91,29,5,211,27,11,82,17,46,139,130,225,18,10,181,44,21,101,5,207,104,134,152,97,192,36,67,63,26,253,176,89,156,133,169,212,120,109,106,18,26,0,218,239,28,216,221,158,109,15,92,255,99,158,232,120,157,3,207,233,245,29,223,119,187,22,15,37,68,129,201,200,58,158,156,100,102,28,46,103,235,249,241,228,240,176,147,189,155,156,142,166,166,192,160,77,103,29,101,87,51,244,0,46,117,178,120,114,69,67,119,25,187,2,224,187,211,227,236,145,117,156,25,70,103,98,174,54,217,188,253,18,115,46,115,26,39,40,194,135,2,70,187,243,181,227,119,59,57,112,244,250,140,192,190,73,126,159,164,147,155,161,235,193,200,210,199,192,59,40,240,14,14,15,245,241,225,168,223,153,188,27,131,128,254,233,199,81,246,46,56,61,57,113,60,99,252,149,235,148,218,184,32,224,111,146,219,123,64,109,148,224,127,13,8,1,131,23,29,2,108,110,5,63,104,32,64,3,7,160,107,67,79,190,15,47,247,109,131,250,160,224,83,3,4,220,131,79,153,188,134,99,180,156,181,109,144,74,47,231,31,216,126,45,59,111,223,252,45,137,150,237,22,52,79,159,135,151,247,236,44,245,212,81,152,172,104,142,251,28,14,76,6,247,228,12,162,215,14,116,167,163,87,90,203,123,251,36,200,194,174,119,159,118,92,118,35,168,0,70,40,102,152,221,253,136,131,67,27,135,125,62,114,78,245,8,245,162,19,239,56,2,133,130,175,251,135,209,215,221,147,81,206,155,254,55,18,215,24,150,48,72,31,99,101,8,164,235,126,221,118,141,168,115,208,117,59,157,161,44,208,26,193,11,108,160,209,25,227,221,68,166,12,205,164,33,22,81,48,83,60,122,247,231,199,198,159,44,99,112,248,203,209,233,81,52,211,81,183,164,71,205,130,57,30,29,30,6,95,121,157,241,131,145,5,87,71,178,47,134,23,50,9,47,95,177,70,11,156,3,195,238,116,14,88,61,86,201,69,219,209,13,231,235,241,97,191,131,228,147,147,241,215,206,199,166,58,157,14,245,212,64,118,137,27,219,227,75,83,26,189,209,148,71,120,66,240,251,81,158,170,63,27,93,111,214,211,254,240,26,252,132,236,236,116,188,176,208,207,204,179,104,137,213,164,82,177,246,102,25,98,167,96,21,182,195,229,24,3,209,219,159,158,63,77,22,88,2,33,55,55,238,116,136,158,66,28,132,100,54,129,157,96,253,160,86,83,194,20,13,86,0,8,160,128,26,45,111,195,88,113,98,74,156,200,192,133,236,36,86,92,200,32,56,211,178,144,60,69,243,32,96,214,169,232,237,244,54,212,247,132,47,106,154,83,172,49,60,149,13,181,227,119,217,105,161,47,211,66,242,208,171,231,163,103,199,71,95,63,192,164,227,107,237,219,16,51,159,5,214,135,105,29,33,88,98,93,141,134,67,45,202,224,239,63,217,76,225,89,81,49,46,250,239,193,102,61,199,92,87,211,158,133,228,83,106,143,207,146,205,251,57,102,147,191,133,115,108,23,173,215,171,108,120,116,132,42,200,52,147,116,70,211,26,84,131,163,17,210,98,149,246,242,249,27,74,57,162,46,189,26,53,240,40,126,48,162,117,38,248,196,47,145,250,241,227,143,252,251,224,1,70,236,8,75,153,132,77,103,91,140,235,84,72,86,165,50,165,113,234,224,128,134,114,76,17,42,169,166,2,2,95,83,1,193,100,160,185,12,96,23,222,46,33,162,144,204,33,99,178,53,121,134,9,197,250,197,119,85,128,121,137,140,186,94,205,3,206,34,185,109,233,22,100,108,215,61,248,30,163,251,115,147,148,5,44,127,165,79,112,2,49,132,162,231,37,199,122,132,25,72,117,92,22,50,240,77,68,147,30,86,18,156,145,79,141,170,65,122,5,95,127,52,169,233,212,184,51,28,99,204,221,73,164,31,20,127,156,166,193,85,201,45,98,164,133,55,52,6,230,195,7,162,64,148,241,63,234,28,28,84,80,122,48,26,189,197,188,167,207,217,52,203,25,97,74,167,212,11,146,169,100,59,29,197,74,247,120,12,6,36,125,133,178,202,210,234,203,145,221,115,29,191,239,193,185,208,195,145,225,244,112,238,246,123,3,61,25,25,121,150,167,175,71,42,167,175,111,160,43,155,147,84,233,202,6,186,146,190,219,156,142,218,244,75,86,158,254,121,36,45,249,45,50,211,241,84,46,156,154,146,251,146,190,91,201,97,222,118,250,39,39,43,140,192,122,250,174,189,58,236,122,72,31,156,156,120,157,67,219,59,29,173,242,174,45,48,147,251,117,58,213,103,244,63,155,233,115,250,159,207,117,154,225,253,26,69,187,88,142,48,198,177,20,60,29,45,245,215,163,80,127,63,74,244,95,71,235,227,229,104,209,94,234,161,158,232,107,180,185,57,180,78,245,158,110,116,251,86,191,215,29,184,221,14,58,191,104,175,117,81,132,10,216,167,186,13,123,238,246,7,126,215,243,251,40,145,160,4,85,167,50,84,2,99,156,221,211,187,86,215,182,252,190,61,232,128,180,139,182,104,97,201,5,220,83,221,1,8,219,242,60,223,241,93,215,234,128,21,85,52,60,70,195,238,117,61,187,223,31,244,118,209,240,25,13,155,246,252,250,150,231,52,160,209,101,52,12,219,3,35,93,219,245,236,93,68,122,2,17,207,239,89,254,160,239,238,162,209,39,52,236,94,207,178,92,223,3,9,119,208,24,8,106,216,3,18,21,207,179,129,105,29,15,27,36,37,68,60,199,194,240,189,131,131,13,130,50,53,6,3,203,179,208,8,28,146,58,26,54,72,10,60,208,209,174,229,118,251,40,177,195,21,208,148,16,241,44,116,212,182,208,215,29,52,64,82,166,135,111,129,104,142,51,0,213,119,112,1,85,129,11,38,4,93,223,245,93,7,188,91,142,102,85,84,78,117,31,64,186,126,111,208,245,109,192,88,163,64,25,19,144,125,64,188,237,14,124,203,238,186,192,53,65,137,10,38,36,66,158,222,245,92,104,85,207,102,154,204,42,120,128,98,142,5,25,235,65,202,122,174,197,20,169,162,1,68,129,70,207,178,125,136,224,0,221,173,163,65,84,31,232,110,31,56,88,196,217,29,36,72,128,60,72,122,215,242,122,125,215,245,119,177,0,193,8,11,207,130,150,246,250,94,127,23,11,112,223,215,253,110,223,243,208,25,228,239,32,1,16,76,12,123,208,7,227,136,228,117,60,136,111,64,195,238,247,220,174,59,232,178,144,86,209,128,12,2,13,27,180,244,93,48,15,37,118,120,2,32,196,20,15,120,244,109,175,203,234,82,197,4,2,4,68,124,27,242,129,174,236,162,1,77,0,26,48,114,224,122,31,26,179,139,6,201,32,145,195,30,56,160,89,175,231,2,202,114,52,175,115,5,125,65,11,224,10,225,48,175,224,128,142,216,54,60,65,8,159,223,3,170,204,149,249,174,104,116,33,233,238,192,114,45,159,116,33,68,145,10,30,196,22,23,173,248,174,53,240,49,229,218,193,2,48,136,162,148,63,128,206,177,140,86,49,33,85,176,33,230,61,167,63,0,235,27,16,33,122,116,9,136,239,13,122,44,197,59,120,144,144,2,15,219,26,128,94,86,215,99,43,86,195,4,140,129,160,247,209,210,192,238,129,96,117,68,200,52,128,36,174,223,135,136,57,14,43,75,21,17,146,15,32,130,76,223,177,7,61,182,166,85,68,160,112,192,163,215,181,156,129,221,103,141,173,34,1,33,37,57,7,231,187,158,215,103,217,168,34,65,156,37,44,60,199,238,219,126,159,84,97,135,47,164,45,93,29,36,237,121,64,132,77,71,21,11,146,14,80,99,48,128,61,239,195,50,16,30,87,245,145,133,40,58,232,119,93,11,26,67,120,92,85,240,32,154,147,160,59,221,254,192,246,48,31,4,26,87,187,54,140,37,157,180,193,27,88,172,181,87,21,68,200,132,161,51,144,48,151,52,119,23,15,234,46,68,12,54,221,131,156,246,216,118,84,17,33,154,147,164,247,7,30,176,197,64,214,128,9,113,142,48,177,124,219,119,88,93,170,104,144,85,103,97,7,154,14,216,207,140,169,34,2,125,32,81,135,99,97,67,8,81,160,142,7,83,157,236,32,134,82,136,15,171,109,21,13,26,227,8,11,191,75,38,6,214,174,1,17,26,109,33,236,208,6,219,183,187,94,3,34,160,42,113,198,243,209,19,171,199,250,82,67,132,212,146,40,130,241,214,177,97,66,0,164,142,10,9,145,175,247,208,159,126,207,161,222,212,17,129,28,18,69,92,240,5,116,23,18,178,60,124,10,15,199,66,217,240,240,53,31,37,163,228,240,61,31,173,71,235,195,95,233,104,171,124,120,181,138,243,78,34,127,10,151,157,253,160,138,3,171,167,250,74,224,46,60,158,245,104,124,216,142,14,210,143,127,141,14,86,157,195,246,146,96,118,14,19,57,131,105,175,79,78,194,143,107,177,168,21,118,14,163,45,214,196,225,83,237,3,115,245,49,61,248,235,222,48,231,243,61,96,254,57,253,243,222,0,163,232,110,128,233,159,219,209,71,224,184,47,76,14,195,200,162,15,8,157,235,210,249,36,154,97,215,90,37,188,40,230,226,149,41,3,109,171,140,120,134,213,89,207,211,228,130,119,205,197,198,119,235,121,28,135,179,32,214,130,116,198,107,175,90,235,112,44,102,241,228,160,151,23,176,218,1,67,203,231,150,60,229,8,50,206,251,38,29,202,83,57,31,153,212,230,213,105,103,152,187,251,88,168,194,185,216,16,160,134,222,142,114,196,229,22,194,79,163,199,237,183,29,253,124,20,99,151,232,166,229,233,184,33,48,169,37,98,89,104,161,229,201,254,149,121,161,186,168,121,113,107,205,150,218,15,125,67,177,136,88,18,143,150,88,87,255,254,205,203,23,163,120,171,127,119,123,93,222,52,110,172,248,102,143,138,63,133,1,34,66,234,53,191,29,137,8,22,212,175,68,67,76,245,172,3,144,20,129,49,25,181,90,152,72,82,54,182,60,67,192,153,132,41,148,83,68,113,148,164,5,155,1,163,159,104,15,14,226,16,18,85,51,44,119,119,244,105,123,2,186,208,246,84,48,121,44,38,126,197,100,185,163,255,80,96,112,253,164,221,218,172,8,170,216,169,197,98,61,82,16,128,65,91,179,114,247,22,105,231,5,25,85,218,49,135,138,20,123,154,117,10,36,235,128,246,34,208,251,243,32,222,132,199,8,198,225,190,101,35,17,53,243,45,112,57,190,104,183,16,157,149,114,72,16,197,141,130,24,180,107,12,232,114,151,89,22,22,155,83,255,117,4,160,71,28,24,244,13,118,10,195,209,191,93,79,183,7,216,7,152,227,40,219,254,87,135,182,78,31,76,40,92,103,71,111,184,25,110,3,29,161,54,180,105,0,210,98,7,85,54,21,200,166,38,188,85,15,81,87,177,55,113,50,43,87,87,49,61,67,112,72,213,29,11,86,37,233,130,194,69,152,50,17,39,253,225,229,139,239,177,220,34,163,85,142,35,19,155,21,88,222,249,241,213,235,55,45,189,197,221,17,212,7,141,35,83,28,54,236,1,41,218,151,182,129,210,14,83,115,53,18,171,230,201,102,57,105,99,134,138,250,225,228,40,197,12,126,29,196,95,35,30,230,150,237,39,5,245,73,144,130,75,34,44,76,196,0,175,14,91,95,181,110,222,239,82,21,127,38,198,86,196,155,43,110,117,236,122,21,221,73,150,170,124,33,184,192,30,172,82,51,106,90,233,195,126,243,89,28,254,47,238,212,22,61,74,150,164,81,87,144,192,117,136,165,194,229,44,44,186,196,61,162,141,108,20,160,136,67,172,39,121,180,65,30,1,9,138,63,28,141,48,81,236,124,2,222,45,116,120,31,196,69,205,2,109,89,15,234,92,87,93,82,231,74,124,6,148,128,163,4,43,232,122,64,247,110,171,250,207,194,151,13,106,158,240,93,187,245,150,165,171,208,98,18,156,116,68,12,16,250,201,225,194,111,104,224,226,174,253,95,211,17,253,13,172,141,8,190,20,3,55,226,219,4,75,16,76,55,9,49,222,43,22,193,196,35,178,98,5,139,2,100,166,168,221,210,99,61,54,41,190,159,212,47,163,116,44,210,193,198,138,38,200,200,182,14,101,129,173,136,138,194,62,198,167,227,153,153,50,104,155,150,224,127,166,1,81,173,122,63,178,15,14,30,32,252,118,29,173,226,240,155,54,174,29,72,17,231,242,199,100,131,64,71,172,93,47,227,43,77,88,7,28,135,90,155,22,78,59,136,59,140,17,41,169,162,12,77,52,1,59,50,140,223,89,167,140,178,137,128,85,196,129,182,144,129,109,144,85,187,243,128,87,77,91,183,130,47,129,206,20,68,68,62,144,27,243,151,155,199,46,81,89,196,228,162,210,191,221,92,146,0,63,95,194,122,65,2,255,178,199,238,61,150,167,99,44,214,134,84,234,91,177,59,221,70,3,112,110,80,174,93,217,13,255,64,133,105,64,251,153,118,57,228,242,185,125,252,3,182,12,44,248,234,121,185,223,193,244,200,120,11,218,103,167,52,10,167,65,7,0,47,15,255,36,63,130,17,29,125,56,150,137,249,229,4,163,223,113,172,228,78,148,19,233,2,78,190,214,135,103,33,214,74,67,125,24,76,177,11,113,141,208,2,3,62,44,237,130,156,193,225,12,83,3,41,199,242,144,117,103,104,169,83,6,50,196,64,26,77,84,18,7,128,12,191,12,253,176,23,158,109,107,176,13,99,125,193,177,240,32,208,80,107,181,182,116,197,203,53,93,200,96,204,67,10,25,24,218,166,127,108,92,132,103,239,163,181,65,67,53,161,18,26,193,228,183,13,162,129,72,245,142,141,69,242,193,192,120,194,57,67,239,216,72,202,103,165,195,41,218,49,166,1,226,86,175,134,155,200,200,130,101,102,32,210,40,130,43,6,35,31,46,140,77,164,27,208,176,56,52,68,130,254,132,162,167,94,6,227,215,124,250,12,245,245,215,225,44,9,181,183,207,245,159,146,51,44,194,235,223,135,241,121,184,142,198,129,246,67,136,232,181,199,41,2,116,244,31,144,163,189,6,124,189,212,72,235,49,129,214,160,100,216,173,249,110,145,252,22,193,41,80,224,84,66,126,254,250,106,113,150,32,192,129,65,149,235,200,110,32,164,108,147,2,81,233,187,13,151,112,71,130,88,100,66,222,35,150,140,122,246,246,44,153,92,93,47,224,62,98,7,205,58,46,211,57,90,206,129,229,122,59,79,175,101,10,69,12,17,235,100,142,226,39,98,21,37,215,237,213,229,54,56,59,75,135,23,40,128,248,89,190,252,231,180,115,93,97,23,109,240,165,140,204,16,227,123,152,82,155,48,207,184,138,104,114,124,87,129,237,220,214,231,142,62,119,245,185,167,207,125,125,222,197,222,27,250,199,252,84,104,113,202,69,181,19,1,34,193,202,168,215,27,82,229,206,116,236,139,36,203,153,0,43,129,128,236,64,99,75,230,87,127,127,54,1,11,23,43,29,74,44,10,21,242,179,72,150,73,182,194,126,176,254,250,217,75,28,27,63,133,51,92,130,144,234,47,67,56,238,58,146,130,113,162,35,10,20,234,16,100,250,139,8,17,26,220,188,70,165,145,177,73,35,152,253,31,194,11,61,7,37,122,195,253,179,195,197,54,3,207,226,82,159,251,214,87,91,108,190,35,4,110,85,74,237,249,95,85,88,105,29,175,146,12,215,255,160,163,42,214,253,24,3,12,9,105,108,4,136,196,89,14,105,159,155,170,16,52,40,56,44,223,98,104,152,142,79,109,2,54,120,140,83,58,99,63,237,154,233,71,155,206,208,210,92,215,27,165,3,137,113,176,130,191,172,14,182,136,228,132,93,213,35,178,70,122,178,90,207,224,232,173,116,52,79,215,115,16,96,196,204,6,21,218,86,56,187,35,232,149,220,6,73,175,228,11,74,146,149,104,16,147,38,249,175,201,124,174,42,43,24,123,178,128,150,234,143,232,128,160,204,26,97,44,25,204,218,2,106,6,154,202,18,239,56,84,82,156,156,202,51,54,194,234,4,180,71,108,223,105,174,47,52,184,7,0,53,14,135,162,214,241,89,48,126,79,244,90,78,36,181,185,37,68,98,128,17,229,204,104,129,97,89,52,62,100,115,56,197,8,150,209,212,254,26,81,199,212,205,33,118,137,19,153,9,217,141,150,152,166,69,19,97,219,177,87,156,92,136,218,202,53,184,190,73,94,134,67,133,45,123,64,70,182,138,150,134,236,112,145,135,70,171,121,202,166,48,22,178,247,232,235,120,222,216,123,34,234,52,10,227,201,177,196,222,72,166,83,16,110,104,56,48,57,69,51,2,68,73,177,155,128,9,170,228,117,104,8,55,196,136,175,112,187,153,254,36,52,185,177,200,54,11,136,195,213,181,188,150,102,136,139,31,64,5,140,11,91,94,247,249,203,38,89,135,250,36,214,39,19,125,199,110,233,243,84,159,70,51,8,50,150,153,200,150,40,193,218,114,63,209,183,194,42,23,162,134,181,31,120,117,215,69,2,6,132,77,172,195,31,217,96,140,68,235,98,184,165,30,54,73,42,214,251,48,155,45,85,207,181,13,44,38,197,80,76,222,178,114,130,70,36,29,28,226,50,103,27,152,171,231,110,214,117,2,115,133,208,217,161,45,53,230,203,193,56,112,131,169,2,213,12,101,31,0,74,123,82,204,198,149,246,92,143,55,41,130,173,135,43,132,75,64,178,182,67,240,128,12,211,68,101,200,208,191,109,180,152,233,217,249,76,63,143,38,97,162,195,61,60,135,229,13,54,147,40,209,163,105,10,183,82,15,17,40,55,209,69,60,69,206,74,102,96,221,70,46,176,228,20,135,12,146,193,129,67,151,106,228,35,139,82,17,105,177,62,117,154,67,100,169,219,113,165,216,221,81,174,18,245,31,87,2,94,14,53,235,184,41,227,42,207,96,173,135,33,15,75,133,139,180,162,28,162,2,144,144,159,102,239,195,139,82,13,62,45,10,243,53,190,148,109,151,207,145,47,207,87,193,146,114,139,19,100,201,19,132,49,207,141,15,9,198,12,153,2,79,18,230,222,200,150,193,10,50,153,70,227,53,34,131,16,208,15,115,114,25,193,198,93,137,98,179,20,211,18,152,46,131,98,98,140,124,144,146,64,242,220,243,40,184,57,115,157,236,228,129,108,8,167,136,115,100,48,218,206,195,137,241,1,17,47,42,109,9,127,30,104,65,251,73,7,235,169,146,226,59,133,113,89,80,185,29,178,167,48,123,100,136,202,41,194,54,73,201,208,172,213,229,110,158,144,112,237,203,233,116,90,202,148,169,233,236,172,237,15,52,108,50,104,142,215,213,142,52,19,113,72,59,32,164,149,214,44,188,191,164,11,159,74,69,110,200,187,53,89,180,30,78,118,178,207,226,13,144,146,199,136,48,159,75,94,138,20,242,213,211,0,174,119,193,151,43,150,28,149,48,223,132,185,28,138,20,140,53,80,172,156,59,52,156,151,114,179,112,21,5,234,100,130,240,222,28,109,137,2,70,57,78,174,224,149,39,238,32,152,103,213,49,205,51,118,80,206,115,118,113,207,179,170,157,200,147,149,17,171,167,215,123,89,100,136,238,98,64,82,73,255,50,10,255,50,10,255,50,10,255,50,10,48,10,102,150,26,180,156,117,157,11,115,112,134,201,35,156,105,44,226,200,25,183,114,59,232,48,247,236,148,247,103,80,42,118,218,82,132,216,95,12,133,79,114,140,197,166,21,38,130,184,172,16,177,141,244,198,70,204,28,126,43,75,56,121,143,23,105,176,170,173,231,108,77,213,242,46,46,91,90,111,226,89,101,145,167,82,182,166,152,76,26,150,154,85,2,84,28,78,215,72,160,63,58,101,238,224,156,255,139,4,71,38,152,62,118,11,183,88,253,95,161,12,77,68,81,130,78,28,62,145,185,31,12,223,186,254,192,83,210,203,161,143,18,139,51,132,19,72,31,26,54,147,155,118,100,97,202,235,214,242,60,149,227,212,50,138,58,94,45,199,22,25,113,81,133,123,164,42,164,69,122,165,35,139,117,9,51,234,66,142,22,50,242,42,148,225,230,201,121,211,156,92,148,175,20,47,146,43,197,37,154,107,35,239,50,167,202,210,236,233,86,253,222,45,22,179,105,146,149,167,138,211,45,174,211,8,47,243,68,58,81,37,141,74,78,41,109,107,10,153,171,186,193,230,28,136,75,177,149,104,32,229,23,211,207,19,187,142,74,206,211,108,172,70,112,218,133,49,192,130,39,73,165,83,36,253,242,206,233,195,168,254,114,170,178,232,76,100,184,86,57,131,207,100,134,83,201,160,51,202,152,98,227,93,166,145,91,191,253,247,247,225,21,79,21,50,141,38,176,144,186,235,98,126,47,12,65,27,129,167,147,112,134,117,112,51,88,98,238,205,186,132,162,226,132,244,129,78,53,59,211,136,50,88,124,142,150,83,186,94,21,164,16,243,21,140,86,60,145,169,207,107,176,138,79,171,10,6,145,45,159,150,226,162,66,140,255,156,33,166,122,98,18,95,79,173,39,0,183,124,62,91,5,88,155,28,11,120,245,196,250,12,154,165,1,134,240,226,154,15,38,17,89,20,86,253,228,66,102,98,240,168,103,34,9,59,10,144,27,76,147,113,45,32,198,106,116,154,167,87,60,115,206,134,34,105,107,210,114,110,52,189,82,69,242,83,185,52,92,47,38,175,238,223,41,199,38,77,229,110,205,25,92,15,251,26,191,67,37,58,148,226,136,148,34,193,21,9,189,34,197,227,20,161,74,188,196,2,215,129,5,69,154,73,114,60,54,217,112,128,23,73,145,42,18,207,106,5,100,35,42,255,178,14,64,181,41,82,85,102,177,188,42,51,140,9,123,47,42,95,76,251,69,90,94,228,151,119,191,124,137,24,180,129,29,64,198,203,174,99,62,28,217,213,149,59,114,49,28,79,115,124,205,33,7,3,75,105,237,134,106,8,134,47,183,112,102,157,185,103,253,123,180,128,48,100,205,238,193,147,233,123,123,53,66,3,49,34,191,172,253,187,224,12,52,196,40,227,235,239,213,128,76,65,27,205,77,152,206,78,81,247,166,162,238,78,81,239,166,162,30,138,206,200,95,9,141,110,222,59,56,114,165,158,213,23,251,168,119,110,79,27,80,255,170,125,203,235,113,191,102,117,162,221,13,246,38,162,53,2,198,80,187,55,92,15,112,125,248,172,190,125,43,92,118,64,246,135,234,67,70,229,247,70,168,164,198,202,33,82,106,181,186,164,177,87,166,138,225,90,140,190,202,117,146,67,181,26,146,81,222,169,22,111,42,93,20,246,170,133,201,94,212,202,10,19,130,162,126,173,168,48,72,245,210,202,76,161,66,183,94,161,177,188,44,126,5,51,167,178,216,55,168,66,87,190,141,130,142,226,5,89,10,159,164,94,62,39,11,132,171,10,190,17,122,94,56,103,132,40,204,204,216,41,173,88,148,150,72,83,163,2,47,174,203,17,129,143,197,194,156,26,12,196,118,224,162,180,19,98,246,69,91,213,13,196,50,180,203,172,92,188,161,52,23,229,34,184,213,76,180,145,208,229,198,1,238,38,181,69,160,11,46,65,30,99,65,188,190,248,159,103,200,182,206,176,218,249,94,8,57,159,151,196,188,144,109,154,104,89,101,169,46,23,37,185,230,115,214,67,68,221,222,5,13,10,210,245,181,126,69,249,110,6,56,184,27,160,221,195,252,83,115,7,123,0,196,136,11,83,113,39,68,215,211,16,139,173,13,42,195,65,35,72,76,68,247,1,232,0,187,110,159,62,119,1,188,10,99,204,139,96,163,239,134,73,54,204,194,224,120,55,37,37,208,189,16,69,215,49,20,222,141,104,125,52,169,194,164,177,68,149,232,90,249,66,186,217,69,109,18,70,158,146,9,243,153,9,223,85,164,96,225,133,47,158,39,175,44,73,113,173,107,213,212,234,229,161,149,23,237,75,59,43,50,21,187,39,49,239,153,190,167,16,191,28,50,34,56,72,125,85,144,194,112,188,57,195,82,201,89,248,1,27,156,109,211,195,164,211,196,149,49,157,114,149,9,77,133,169,172,105,251,25,124,85,90,31,255,37,159,99,202,245,114,229,214,229,212,146,9,157,98,135,179,152,149,74,16,60,219,196,252,128,124,253,59,193,136,33,129,28,45,89,155,102,154,251,86,102,195,89,170,59,55,188,59,235,84,204,140,172,7,137,188,179,158,116,9,203,213,202,126,233,157,245,155,253,86,9,73,100,238,11,163,228,157,86,234,11,155,130,9,215,157,128,246,118,237,44,120,19,182,139,111,197,254,236,186,118,10,15,233,88,236,137,192,223,201,241,80,146,83,200,54,54,237,239,22,158,6,189,68,189,127,136,86,201,70,201,129,127,136,183,146,236,122,240,13,133,183,54,99,139,153,57,173,42,229,156,86,214,167,111,13,57,227,6,159,183,95,212,43,124,212,74,141,191,147,167,202,219,221,57,118,236,100,195,30,15,57,121,239,137,68,101,185,245,22,97,147,141,169,173,105,154,29,203,150,212,94,59,140,130,198,49,80,184,163,85,177,95,95,219,203,102,203,33,97,241,130,45,110,151,80,224,219,180,202,155,227,84,172,57,119,216,123,176,106,89,229,197,231,78,115,30,119,187,188,162,188,71,35,88,30,29,183,61,244,237,240,182,246,234,13,202,150,74,145,6,141,149,69,30,98,17,43,153,59,169,34,65,47,214,167,11,134,112,133,38,222,139,102,10,206,223,189,216,94,195,112,135,247,156,156,11,244,125,155,186,65,164,239,108,139,76,235,189,219,106,54,161,245,182,86,33,236,191,188,123,208,95,249,204,144,103,172,187,255,136,105,235,29,77,10,127,242,62,109,58,142,134,43,219,180,94,117,157,97,239,54,203,102,92,108,171,237,55,178,238,110,198,113,116,64,49,45,200,243,232,234,115,233,244,21,197,75,178,93,218,189,131,22,201,165,198,130,101,124,142,12,218,178,43,146,197,126,158,76,254,99,45,157,224,240,174,198,31,74,25,98,139,79,229,148,171,136,205,190,61,9,165,188,129,123,12,184,123,140,248,55,12,184,59,70,152,17,100,101,144,232,53,88,229,79,176,199,55,129,21,6,250,95,166,249,190,166,249,86,122,178,85,129,81,187,135,57,195,13,9,120,246,136,59,31,220,105,206,110,106,86,88,150,123,182,139,169,27,205,51,237,158,115,75,187,195,40,107,155,124,79,74,254,205,117,132,22,78,29,186,246,183,251,11,133,199,238,169,11,110,87,131,25,117,43,179,197,29,69,184,173,73,55,112,207,220,241,125,154,244,251,26,198,193,110,101,61,226,94,77,134,94,216,13,207,238,211,164,227,244,65,89,12,188,119,44,223,222,212,42,143,140,24,38,246,111,177,135,5,18,159,134,167,79,105,174,88,61,190,161,65,44,31,239,214,157,85,86,231,85,205,125,150,83,27,150,231,111,151,56,209,84,93,218,246,24,177,155,164,237,174,166,212,178,212,254,205,52,45,80,221,217,76,201,106,119,174,111,139,137,221,173,205,203,24,229,141,11,137,234,109,43,94,141,27,22,181,117,154,155,27,170,169,192,45,203,65,205,146,191,87,67,60,234,222,221,66,243,104,186,87,11,197,2,83,99,51,88,108,218,169,87,138,238,20,146,65,215,148,53,132,142,138,120,161,82,225,102,62,248,224,3,252,57,27,250,90,66,190,161,94,83,31,110,192,229,159,141,134,162,34,110,246,82,172,211,217,187,229,110,159,94,223,100,106,250,55,3,18,102,64,141,0,85,48,123,104,105,211,56,112,171,150,222,54,3,191,199,248,179,223,20,252,166,214,121,56,174,244,187,220,254,126,211,192,134,158,223,53,202,223,60,255,188,87,203,251,76,64,75,109,151,125,28,41,243,141,14,86,63,55,207,123,161,1,20,186,180,76,125,219,212,244,126,88,8,127,235,158,104,208,100,206,178,53,255,54,119,235,139,207,249,249,72,149,107,71,52,190,0,235,24,55,44,23,1,40,8,189,96,39,95,68,120,107,165,93,36,77,108,35,29,19,24,71,2,225,93,33,141,226,112,142,53,25,82,165,89,102,223,13,23,228,213,154,182,69,7,199,90,121,75,72,163,203,133,100,210,223,132,131,91,193,193,169,225,96,113,211,249,193,63,6,135,47,27,158,79,131,91,180,23,161,149,121,56,26,45,125,227,217,42,184,238,136,22,208,249,168,152,240,138,89,22,207,120,161,10,95,233,26,253,118,142,85,184,22,24,43,46,200,186,173,125,121,169,105,137,36,216,235,4,73,106,17,94,20,195,243,197,231,184,86,148,175,70,145,241,17,67,187,155,79,248,190,156,186,244,46,95,188,38,47,55,112,113,127,154,201,89,109,97,156,58,34,215,183,9,118,190,92,207,39,181,240,30,103,39,188,71,133,225,241,37,1,95,124,126,175,72,34,244,162,244,216,30,200,130,188,249,61,69,56,182,49,55,237,28,231,42,99,153,3,236,127,112,196,144,193,151,150,34,206,145,99,118,0,4,87,117,202,235,56,113,73,231,81,254,172,176,19,186,240,79,227,123,106,136,59,59,211,8,241,78,122,164,167,154,90,56,231,251,115,139,241,255,157,116,100,78,53,218,139,22,207,30,195,51,101,0,10,119,238,215,34,220,179,162,65,88,112,91,124,209,132,40,47,94,13,21,212,211,159,30,21,79,2,59,57,66,177,122,45,9,77,178,183,245,168,92,72,29,127,118,50,119,118,30,75,134,174,59,156,183,122,116,50,119,31,209,157,28,54,242,33,101,56,61,57,90,137,76,213,128,220,73,214,40,184,15,241,201,134,223,122,68,87,60,209,245,202,184,48,246,124,166,97,244,164,199,67,224,98,111,211,105,105,151,139,120,137,90,116,107,77,220,89,243,226,226,194,188,112,233,206,154,71,116,71,189,35,148,111,105,244,192,181,39,201,229,168,69,179,225,190,103,209,172,181,165,169,43,205,109,60,88,77,136,214,168,229,226,184,204,152,42,245,91,184,26,28,252,68,94,85,145,143,43,20,94,225,6,10,116,213,115,108,164,184,123,54,30,22,7,169,72,38,147,22,167,225,94,253,27,220,181,126,137,7,82,64,240,91,116,187,145,133,109,153,174,230,219,230,32,134,107,98,186,134,111,14,206,123,221,49,208,52,123,36,95,154,107,98,234,129,175,103,58,113,15,231,158,217,253,176,176,7,166,175,217,54,234,32,20,207,232,82,157,65,76,199,90,47,207,52,171,217,56,21,5,76,123,183,72,143,10,120,57,132,174,105,27,125,207,244,198,6,116,221,0,22,134,11,212,232,223,51,251,154,21,27,93,154,160,0,65,174,0,248,90,119,64,133,6,38,42,27,62,37,122,72,136,209,35,100,81,145,129,217,167,236,46,117,114,0,140,92,224,208,71,175,112,138,102,75,197,186,84,204,167,98,253,106,49,63,198,226,105,15,199,40,228,83,33,207,176,93,163,103,250,40,210,5,86,182,107,246,69,47,186,93,228,1,61,119,44,177,39,250,25,8,161,224,127,208,241,220,232,117,63,144,12,19,183,26,185,215,196,41,220,238,205,180,201,51,56,199,29,29,77,123,110,184,32,10,142,125,211,159,187,24,146,248,112,128,100,117,236,206,81,2,141,217,61,68,83,66,92,207,251,232,212,135,133,107,131,227,0,210,7,70,115,2,229,158,211,225,135,133,131,158,226,38,106,166,61,38,65,0,158,154,103,128,32,196,39,151,15,250,72,130,96,128,109,26,160,211,129,167,33,29,53,93,116,210,246,204,30,49,172,11,17,241,32,71,54,81,11,55,187,66,33,58,232,146,60,17,183,125,128,6,31,28,240,129,8,63,39,122,163,69,27,148,242,32,113,174,1,236,88,16,113,134,187,135,65,58,152,25,14,36,200,96,20,249,136,90,67,62,18,224,31,64,86,197,17,178,6,132,34,121,80,36,187,150,72,243,197,17,234,0,54,166,89,0,194,165,73,206,108,144,196,113,0,12,201,93,112,12,253,5,50,4,19,124,227,250,92,148,143,152,114,4,11,253,34,250,240,17,126,252,115,3,242,214,5,53,187,102,247,28,80,153,14,134,139,78,251,16,17,52,226,3,67,121,224,19,218,16,45,18,94,116,139,142,156,30,117,70,67,38,228,136,26,65,66,151,208,147,71,146,240,46,0,128,231,84,142,180,202,195,67,189,88,83,21,185,128,19,36,215,35,236,233,8,37,136,130,182,1,108,29,84,133,108,162,171,36,189,232,13,88,37,249,225,144,82,137,3,226,14,18,123,64,131,16,230,211,34,3,157,33,44,0,10,28,102,221,67,67,92,3,12,238,49,199,153,189,121,6,100,141,229,199,28,0,203,1,10,129,5,252,3,61,21,71,80,31,238,24,186,133,100,136,175,1,245,134,201,1,19,145,131,115,252,119,209,176,55,71,102,119,12,17,33,49,233,226,219,3,214,30,255,247,161,119,184,233,44,122,68,157,69,38,36,205,0,171,6,134,3,148,196,17,241,133,200,206,180,161,74,56,2,169,81,53,182,33,28,44,242,172,154,56,38,136,46,228,90,252,51,191,192,0,112,2,53,232,31,236,37,33,50,108,50,141,168,67,255,100,61,137,51,232,249,24,116,6,139,192,18,54,11,160,34,91,7,54,123,172,39,144,254,177,176,99,2,83,54,52,68,62,74,33,91,75,199,61,52,67,226,227,146,113,2,12,179,7,102,67,77,128,65,31,217,44,243,104,129,140,55,29,125,88,248,172,30,48,56,160,2,85,167,126,144,50,144,157,162,127,146,37,48,129,148,26,95,250,135,73,60,119,33,65,115,224,230,157,147,226,67,152,136,121,164,171,208,50,100,177,160,136,35,129,30,137,44,99,200,162,10,186,67,38,88,234,251,231,62,58,65,160,128,75,143,112,243,80,21,89,160,223,57,18,129,57,9,45,148,158,218,38,158,209,63,130,191,81,147,196,121,110,91,231,224,137,67,226,76,10,192,98,66,212,198,15,173,192,148,57,1,106,128,63,164,97,176,109,98,148,96,139,65,74,76,194,1,217,231,127,24,100,166,49,87,224,127,26,220,136,72,104,78,152,72,96,96,131,47,88,236,2,37,88,128,152,89,64,148,128,128,93,128,74,71,192,137,52,144,18,72,214,197,1,231,0,95,140,63,66,230,145,0,186,201,44,54,125,160,57,39,208,56,33,14,40,7,99,20,122,68,200,66,238,176,38,67,58,194,156,97,213,146,255,108,147,44,28,19,78,62,253,115,50,224,161,60,110,0,73,36,38,173,150,25,196,37,22,32,218,251,34,27,43,192,96,112,2,99,208,172,28,9,168,199,93,12,227,231,124,8,100,6,231,93,216,189,185,77,188,196,1,4,137,250,39,210,160,188,49,15,39,152,179,153,125,48,11,230,154,19,60,141,19,136,55,49,4,129,48,244,230,52,174,160,103,68,94,172,21,65,179,72,247,161,151,24,146,8,18,101,145,45,195,141,41,73,97,193,71,22,28,48,4,0,33,41,32,200,185,59,0,190,184,202,129,134,39,20,70,9,216,251,115,58,66,109,18,112,8,41,184,68,18,136,47,137,50,169,147,248,74,114,145,218,139,28,200,1,204,7,73,5,165,208,89,254,229,178,156,47,115,168,60,212,147,45,38,186,66,236,58,7,30,220,20,12,26,248,72,6,149,135,68,22,120,96,69,232,17,249,104,240,97,233,70,112,28,17,134,37,219,230,127,232,13,161,68,22,139,199,68,16,133,52,102,64,118,140,68,20,195,129,28,242,8,101,250,167,65,199,130,224,10,43,71,255,208,24,240,13,163,207,28,45,192,113,32,162,224,8,116,194,33,43,6,76,23,228,149,172,44,13,172,132,8,255,3,48,35,69,72,144,234,8,191,141,198,55,152,34,194,128,240,35,141,36,251,71,250,45,254,73,122,73,105,168,101,26,100,28,228,184,16,5,57,66,147,166,65,34,25,109,170,76,86,85,152,36,32,79,30,17,217,6,143,134,58,178,22,56,67,219,144,86,58,32,85,149,38,136,124,1,156,66,24,104,68,230,35,114,226,132,238,195,6,66,155,186,36,16,187,78,18,102,53,231,116,223,250,207,148,231,174,166,20,114,131,113,103,222,81,158,61,208,37,9,154,186,64,65,43,95,137,160,241,37,56,26,95,31,84,248,211,39,15,12,3,143,52,230,27,10,137,59,34,105,134,81,228,170,166,43,247,209,107,110,171,122,81,67,209,154,87,113,222,169,185,167,252,136,48,220,11,73,92,240,94,110,16,37,104,194,88,58,167,233,156,40,86,224,33,239,94,180,59,147,16,243,186,34,148,27,107,5,52,225,149,127,152,104,136,133,113,204,1,235,129,236,26,47,26,150,67,119,196,178,129,90,244,199,122,3,22,121,42,59,174,50,73,236,150,150,79,114,8,229,160,53,154,89,250,26,197,11,107,116,245,20,211,77,16,143,238,230,199,23,102,84,217,85,76,92,197,254,198,169,72,201,241,124,39,23,254,100,122,169,253,90,78,222,121,153,90,230,135,184,25,18,230,124,123,204,242,228,124,206,41,77,231,232,184,50,249,163,61,28,79,205,196,136,72,52,165,163,0,202,186,183,47,82,197,86,45,77,52,253,60,137,232,139,103,98,96,6,77,212,171,36,211,3,36,242,116,201,252,120,51,198,253,10,52,241,167,110,120,1,157,226,121,6,36,230,37,249,137,154,243,125,55,128,115,43,54,144,65,125,231,220,46,37,224,31,195,165,83,78,48,156,159,97,32,95,136,202,31,90,71,0,152,196,87,124,187,30,94,141,64,203,54,250,10,197,70,132,171,131,49,155,139,228,109,34,195,57,239,150,211,48,72,193,251,131,191,76,206,191,75,57,82,205,171,172,192,101,198,181,52,13,143,39,165,235,156,248,118,153,181,226,71,59,229,79,142,132,182,84,19,249,62,21,242,153,126,124,55,53,86,166,226,6,95,138,152,242,198,163,90,128,27,232,173,192,95,126,234,3,63,154,100,246,161,133,245,1,121,99,192,86,233,158,91,109,190,255,88,167,162,228,71,21,29,174,46,118,176,5,192,189,48,249,206,43,183,153,156,218,141,219,246,54,58,30,155,56,40,180,232,75,101,238,89,1,44,238,125,90,89,21,81,96,112,165,164,80,127,44,147,148,215,41,164,249,96,147,125,195,242,77,85,175,43,26,205,215,90,105,23,134,184,156,175,166,135,101,24,226,58,189,220,142,237,152,18,242,41,253,93,3,177,163,216,117,82,210,221,252,84,27,165,64,39,9,175,220,68,190,18,163,174,233,254,170,186,30,213,196,217,6,18,139,27,78,214,22,158,234,104,90,95,85,97,86,40,91,149,157,93,73,122,45,238,245,120,155,32,85,111,7,185,199,64,41,248,36,6,176,6,41,186,159,185,244,176,132,166,204,37,29,255,61,204,37,192,124,154,177,172,94,188,80,182,146,152,72,96,167,26,215,166,6,88,6,99,19,200,51,224,62,252,172,94,15,41,42,13,110,13,29,86,11,201,159,60,13,187,42,84,44,79,144,64,42,133,104,66,72,83,139,74,161,157,230,120,254,216,253,83,197,144,98,174,68,134,154,150,110,188,6,59,138,85,208,178,60,241,179,88,67,37,39,144,237,178,112,21,69,133,104,149,37,139,111,174,123,155,92,149,239,34,185,167,84,193,33,250,127,85,170,228,245,43,37,153,90,96,154,212,35,255,221,192,236,201,43,13,191,152,67,240,10,39,102,161,222,227,98,204,165,11,80,230,149,97,153,234,27,110,133,251,52,180,14,206,153,239,149,209,182,55,55,45,187,81,26,10,94,85,13,62,93,97,94,53,69,111,151,184,245,55,70,90,44,133,51,243,155,37,165,10,83,222,7,187,66,138,203,172,121,208,40,183,245,99,140,138,120,64,55,150,241,131,25,182,19,170,109,229,15,12,223,21,75,60,171,156,111,253,118,171,197,171,222,227,122,239,161,19,220,219,103,80,171,213,220,145,114,27,219,15,242,226,48,49,138,130,32,165,107,189,107,227,94,190,47,209,64,51,177,185,86,190,196,167,62,120,40,114,236,59,132,52,82,169,58,173,170,146,41,31,12,186,52,114,243,21,246,183,140,220,205,132,82,143,103,223,29,101,118,134,236,170,241,162,23,109,231,208,221,198,235,174,95,189,228,137,32,49,119,77,221,160,60,31,236,105,35,84,171,93,34,79,147,17,155,166,37,133,175,83,185,90,174,54,121,218,113,69,226,89,121,166,85,154,127,168,176,0,153,86,11,147,184,105,98,147,79,83,42,169,77,161,45,37,237,42,109,228,53,33,80,202,168,97,81,39,60,232,135,219,53,210,253,42,249,150,238,224,36,217,71,166,104,56,121,164,158,143,127,114,36,10,221,89,25,114,250,34,90,195,220,60,123,141,61,253,215,63,62,127,246,236,245,13,149,97,177,184,153,187,60,171,127,172,148,125,75,1,14,111,159,223,41,100,113,112,22,198,10,15,117,35,20,181,223,206,120,85,154,175,222,1,162,129,232,229,153,9,7,93,211,179,125,89,134,119,158,248,171,136,155,75,181,188,129,140,70,65,24,72,20,33,219,187,77,84,28,235,1,156,93,191,226,89,23,33,28,213,217,125,41,93,78,241,235,41,42,164,87,74,106,83,46,2,65,106,171,0,40,149,107,64,190,184,80,142,57,23,225,229,59,161,249,77,101,202,81,233,154,72,82,87,63,189,123,136,39,200,139,36,21,199,32,79,41,42,128,174,249,83,217,124,9,97,57,33,223,31,175,52,162,46,202,168,164,202,147,74,15,69,18,46,15,148,71,184,224,79,181,92,185,104,172,162,245,42,176,181,218,203,210,28,165,105,250,65,2,202,242,120,151,234,204,33,136,165,49,166,136,83,211,138,192,63,248,14,255,68,117,251,62,72,39,100,80,180,231,223,238,169,114,164,18,120,176,38,215,122,254,109,29,219,127,182,185,80,6,81,251,89,196,10,52,117,226,179,207,62,43,225,62,149,53,100,133,150,118,123,15,154,39,126,136,201,200,135,111,113,103,50,60,41,147,150,59,178,27,67,7,228,4,214,245,41,168,229,31,179,116,137,126,202,211,102,28,100,28,146,186,95,3,118,231,16,177,195,65,54,42,228,201,103,220,176,190,66,183,74,167,73,119,245,150,231,244,220,122,109,164,61,60,122,136,82,194,86,138,6,255,185,75,160,202,151,187,239,82,40,89,141,210,77,6,118,150,69,97,89,209,156,88,22,37,175,188,97,109,212,249,31,90,27,213,180,39,8,25,213,112,87,242,122,208,205,13,139,110,36,161,127,95,97,200,111,101,223,238,252,127,192,124,0,248,31,101,62,248,135,123,148,203,85,3,222,131,145,172,109,88,130,42,130,178,242,68,20,71,236,25,14,17,122,133,112,205,71,255,13,10,108,23,134,230,146,0,0}; +const uint8_t ELEGANT_HTML[10615] PROGMEM = {31,139,8,0,0,0,0,0,2,3,172,87,121,87,219,176,150,255,187,249,20,194,231,188,96,131,227,44,44,77,147,136,238,188,238,208,125,230,49,76,143,144,175,19,21,199,202,147,100,32,3,249,238,115,229,45,11,41,221,94,186,196,150,174,126,247,119,119,101,176,17,74,110,166,19,32,35,51,142,15,106,3,251,69,98,150,12,169,3,137,115,80,35,100,48,2,22,218,7,124,28,131,97,132,143,152,210,96,168,243,249,211,97,163,235,144,230,226,102,194,198,64,157,11,1,151,19,169,140,67,184,76,12,36,40,124,41,66,51,162,33,92,8,14,141,236,197,39,34,17,70,176,184,161,57,139,129,182,131,214,28,204,8,19,195,193,19,102,12,168,41,121,62,78,99,102,164,34,71,159,30,147,207,147,144,25,24,52,51,17,164,172,185,18,19,115,80,139,193,144,88,178,80,36,195,103,226,226,19,92,25,66,137,243,38,95,9,130,192,233,215,152,158,38,156,68,105,194,141,144,9,90,2,252,188,196,254,104,152,73,245,7,56,147,210,184,30,185,174,221,67,238,218,16,84,198,16,136,93,50,97,200,16,204,51,124,119,55,155,255,4,115,40,212,248,146,41,120,153,68,114,211,235,215,238,137,136,184,86,60,59,125,15,61,155,142,209,246,0,15,61,143,193,62,62,153,190,12,221,205,168,56,247,5,148,70,26,155,94,96,144,236,211,220,83,132,102,26,131,82,168,127,23,18,70,34,204,24,60,91,15,98,247,75,16,109,228,164,112,198,243,8,56,218,104,87,21,104,48,95,48,92,248,122,15,63,181,123,51,2,177,134,204,130,102,115,238,249,68,26,34,147,88,36,224,147,115,128,9,177,254,64,44,139,12,230,147,24,131,76,141,251,67,143,250,164,211,106,181,188,62,65,204,167,86,136,176,33,19,9,193,191,29,162,1,93,29,106,212,93,155,245,107,85,120,180,97,202,44,83,190,203,175,142,202,52,161,112,99,12,90,179,33,56,43,78,89,206,142,59,61,59,199,178,25,140,76,65,161,139,121,204,180,126,35,180,9,20,140,229,5,96,4,68,24,2,134,240,78,176,162,8,150,0,88,184,168,229,40,131,152,45,218,190,26,173,235,191,161,139,218,254,156,107,97,236,221,116,153,50,121,164,191,50,145,179,189,93,139,185,64,85,141,101,129,137,139,54,238,254,144,145,78,57,7,173,159,202,56,29,231,236,243,74,219,176,7,23,88,22,150,235,185,161,88,135,203,233,121,43,163,124,210,206,210,242,151,179,120,47,23,95,205,84,108,43,47,50,165,79,45,29,219,62,126,213,186,137,146,67,181,108,94,117,176,115,215,65,150,169,214,79,82,99,240,203,30,204,221,242,107,94,33,25,126,160,205,52,134,32,20,122,18,179,41,221,60,139,37,63,223,172,122,192,15,229,18,153,192,102,225,132,156,173,60,211,160,46,64,33,227,4,46,201,219,212,48,75,239,168,88,118,209,37,244,32,15,199,170,175,48,145,188,85,152,67,145,8,61,204,58,61,134,234,23,64,87,243,207,130,174,246,251,170,123,43,136,17,232,2,142,153,25,89,111,16,98,212,212,126,227,39,231,161,64,79,240,1,170,198,31,129,225,163,229,131,253,76,222,186,188,148,14,228,185,87,187,135,124,214,141,142,74,232,187,150,137,155,119,194,99,59,73,231,202,152,38,175,62,30,189,203,218,178,73,85,146,1,100,201,70,200,140,112,134,20,136,11,74,73,149,179,38,136,97,53,73,140,77,182,236,110,30,130,21,202,94,122,155,126,254,80,48,45,48,147,52,142,237,66,22,188,75,145,132,242,50,144,137,45,86,164,90,121,212,14,211,114,122,16,234,60,116,250,249,90,57,150,138,165,154,157,17,31,113,157,17,147,23,15,145,17,214,84,217,210,137,107,235,171,69,198,34,142,69,177,230,205,253,92,29,202,3,124,172,228,24,165,92,247,155,143,108,191,3,55,25,29,148,207,63,11,37,154,19,205,133,92,123,246,121,110,255,7,248,119,10,5,112,72,80,18,243,61,47,242,86,174,215,214,73,230,56,242,129,113,32,103,96,46,1,170,212,32,44,9,137,25,65,73,204,138,150,180,2,133,7,220,147,59,174,0,126,121,236,212,171,56,7,136,150,100,183,130,220,179,100,225,179,120,95,32,43,159,255,212,237,97,21,247,47,239,18,171,144,51,219,40,48,97,109,214,255,197,149,199,41,210,218,230,212,159,220,119,86,17,102,21,201,217,66,40,178,10,202,229,108,48,254,150,114,17,236,63,37,189,138,49,103,108,241,106,235,47,108,127,60,84,202,206,26,20,15,174,197,240,201,53,97,198,40,113,150,26,208,61,98,84,10,254,124,229,80,196,6,84,143,156,108,102,243,100,243,148,204,86,230,211,111,141,237,245,205,125,145,80,231,143,8,97,31,107,54,17,211,54,92,117,78,82,81,171,72,21,15,37,179,149,27,145,99,229,29,68,136,37,103,241,71,35,21,27,2,22,44,202,210,124,175,95,27,52,243,223,23,197,239,146,252,133,152,233,4,69,198,50,76,99,112,8,87,82,107,169,196,80,36,7,53,183,28,55,120,9,202,61,21,209,138,15,87,192,12,20,108,92,39,22,9,234,15,20,196,150,83,95,68,110,84,175,71,129,78,39,246,215,147,94,124,118,11,109,19,5,182,87,59,158,151,247,243,126,36,149,155,235,97,182,247,86,170,176,15,170,233,71,136,129,163,93,143,227,216,221,180,218,78,240,56,93,129,58,197,30,25,186,204,235,175,29,178,140,30,92,207,117,112,171,131,121,200,148,7,153,19,40,117,248,72,196,161,53,192,241,230,130,194,10,114,235,102,8,223,201,16,180,39,2,195,134,239,216,56,59,243,230,229,187,215,78,189,46,2,203,135,174,48,194,141,208,21,222,204,171,114,163,180,202,191,174,148,245,54,90,190,78,207,140,2,192,71,204,131,249,109,204,101,165,235,57,189,158,245,139,193,199,2,145,24,24,42,97,166,245,186,203,231,111,116,97,199,243,25,82,138,64,41,80,199,50,22,60,147,93,89,162,171,50,246,84,150,4,71,89,18,88,131,82,13,13,174,32,68,210,130,197,218,121,200,131,133,87,234,136,132,199,105,8,78,239,214,73,150,200,100,58,150,233,237,51,56,134,140,211,91,89,212,232,209,70,158,124,142,207,103,149,23,66,235,5,140,19,11,96,82,230,138,125,166,27,173,126,233,28,109,163,158,95,109,176,193,163,77,62,247,102,51,15,59,205,154,138,160,69,77,220,220,108,184,78,182,132,70,144,69,65,175,94,47,46,20,99,134,152,111,33,20,204,117,220,73,230,44,221,224,50,150,170,161,185,61,218,203,106,213,115,188,92,20,244,67,247,247,138,214,95,223,120,138,253,183,50,132,236,103,230,153,188,66,29,220,62,66,136,166,123,189,95,209,147,255,224,249,59,85,109,175,255,59,231,208,180,231,23,40,96,245,67,2,202,117,56,102,214,185,227,47,180,147,63,224,241,219,110,253,97,43,252,3,207,173,71,139,197,112,100,28,111,177,98,31,187,177,119,93,148,105,92,175,199,193,183,111,160,223,102,45,161,94,63,58,179,151,188,96,162,164,145,182,229,4,35,166,143,46,19,188,149,77,64,153,105,128,26,98,55,246,157,16,34,150,198,136,252,48,14,138,231,94,60,187,96,138,188,161,215,112,149,117,209,222,245,108,230,95,45,189,246,23,27,182,149,142,169,243,248,201,211,103,207,15,255,249,226,229,171,215,111,222,190,59,58,126,255,225,227,167,207,95,190,254,215,127,255,139,157,113,196,30,142,196,247,243,120,156,200,201,191,149,54,233,197,229,213,244,255,90,237,206,206,238,222,254,253,238,131,237,38,70,141,94,35,223,184,87,97,107,63,172,76,212,131,65,120,163,15,14,14,118,58,141,112,230,163,160,250,161,32,138,228,178,40,8,73,40,88,178,32,154,21,184,14,178,114,86,169,109,244,148,190,75,199,103,160,188,2,33,10,44,13,4,237,122,245,246,254,253,118,251,193,206,222,77,181,216,217,245,234,187,157,251,221,206,222,222,206,126,43,27,37,214,3,33,109,245,195,129,14,98,72,134,102,212,15,183,183,61,125,18,158,210,40,200,25,184,246,205,235,151,36,209,2,134,85,63,126,50,53,160,151,216,205,1,79,78,251,250,160,213,215,141,134,23,6,147,84,143,220,183,204,140,130,40,150,82,229,143,57,134,235,109,117,246,246,189,10,28,173,62,179,176,159,228,87,169,194,31,163,251,140,182,124,142,188,217,156,55,219,222,246,249,54,237,122,225,9,71,7,238,157,222,80,125,194,78,7,131,206,110,131,255,99,167,179,160,227,18,193,81,199,221,22,248,108,9,127,11,17,24,194,151,6,33,118,166,5,255,67,5,12,21,212,209,175,107,44,121,1,87,191,170,195,218,80,226,91,5,22,124,215,11,140,252,104,148,72,134,110,27,93,229,47,238,215,219,123,43,219,149,254,224,187,20,137,235,96,229,249,35,184,250,77,99,173,165,157,146,201,132,41,13,47,19,131,169,135,19,88,27,229,50,191,227,249,237,181,113,123,194,52,236,239,254,142,158,29,175,20,224,69,192,218,251,55,248,176,221,198,199,110,246,212,57,245,5,158,19,131,221,190,64,15,177,173,238,182,216,218,31,208,42,54,221,135,5,215,24,59,33,83,143,141,107,83,96,127,203,221,105,8,175,190,191,227,121,189,66,192,161,206,90,31,157,101,188,215,185,73,163,26,5,147,152,113,112,155,39,255,251,184,241,175,86,227,193,246,255,52,79,155,98,232,59,136,246,179,196,228,116,123,155,253,99,215,227,27,180,85,175,23,60,144,169,72,66,184,58,194,138,46,57,179,70,219,243,234,89,121,76,228,165,219,241,27,157,45,190,221,245,112,121,48,224,91,157,155,117,103,60,207,90,218,192,237,133,104,204,250,87,65,209,244,104,148,77,120,75,240,5,173,86,253,67,122,157,154,168,219,187,214,89,238,172,26,190,208,161,15,131,51,145,4,75,98,110,154,128,230,108,2,46,36,92,134,240,249,195,203,167,114,60,145,9,36,6,79,122,94,149,14,121,102,174,131,13,225,214,201,2,51,87,184,4,144,131,34,170,72,238,98,92,70,34,178,145,208,24,5,61,136,203,40,104,76,156,104,49,73,158,162,122,116,160,246,150,234,54,90,161,254,39,248,249,201,32,82,114,252,180,80,228,198,39,250,212,155,107,153,103,30,90,245,146,30,246,155,91,27,53,178,69,158,129,1,53,22,9,16,17,17,150,16,153,77,67,34,52,97,228,73,26,69,160,80,202,10,62,98,169,25,73,69,8,57,4,123,161,36,143,207,100,122,62,98,161,248,14,35,50,24,25,51,209,189,102,51,202,54,3,169,134,7,217,169,88,112,72,52,16,242,246,229,39,92,104,90,107,142,232,154,240,196,27,52,73,99,156,206,238,91,92,189,185,57,206,254,223,216,192,97,45,116,206,196,155,205,71,250,219,249,81,148,89,28,81,245,186,157,226,50,34,75,171,65,9,66,169,83,130,56,245,250,122,25,196,158,95,116,143,23,72,86,200,10,88,120,24,75,102,222,60,95,6,172,36,180,181,124,121,15,57,231,203,110,203,111,97,122,221,190,25,188,192,193,254,50,176,117,130,209,62,242,67,124,193,12,244,217,220,97,220,23,222,53,95,30,201,121,248,31,10,251,123,39,171,15,124,163,168,26,143,50,53,197,107,62,13,87,202,137,123,61,78,163,219,139,246,63,20,127,172,20,155,206,111,68,57,233,252,34,196,145,121,111,35,23,16,58,251,198,51,245,250,18,165,13,74,63,139,196,116,179,109,140,40,167,124,62,52,188,121,3,83,52,14,22,199,47,34,249,19,202,171,38,235,39,180,125,127,167,179,215,221,197,123,133,15,180,209,185,143,239,59,221,251,15,124,73,27,213,214,174,111,104,185,211,245,83,44,147,116,160,202,50,73,177,76,212,73,122,74,93,251,191,109,240,248,157,15,209,133,43,75,177,217,217,45,119,187,75,55,23,117,50,41,38,124,187,211,29,12,38,56,124,125,117,226,78,182,247,119,113,253,193,96,176,235,109,183,119,79,233,164,50,109,76,89,240,45,138,252,161,253,30,14,253,145,253,30,141,252,169,253,22,226,54,75,218,222,207,179,224,41,77,252,143,20,252,115,42,253,111,212,244,19,58,118,19,31,124,233,155,255,39,171,222,113,3,71,98,32,12,159,199,216,22,192,98,241,121,24,135,3,59,155,100,18,223,126,165,238,72,102,94,193,135,159,13,105,221,184,255,228,115,229,186,162,164,50,154,241,177,254,221,131,127,107,79,246,0,159,11,186,46,86,123,152,215,189,248,123,47,254,174,189,217,11,189,23,185,66,2,226,133,254,88,127,238,193,159,181,39,123,192,207,165,186,46,136,153,171,147,242,177,126,51,108,51,144,97,168,234,156,12,223,12,168,136,148,152,198,100,196,102,92,176,164,18,52,76,72,30,136,121,138,119,113,50,234,97,32,83,132,110,136,201,232,83,3,237,101,48,67,78,7,228,64,76,37,56,13,192,65,160,91,76,12,161,147,1,221,142,18,11,97,148,78,7,120,32,38,52,64,48,25,176,195,128,139,138,168,182,76,11,124,91,160,12,167,83,251,161,124,189,40,183,214,215,133,240,236,112,200,35,249,122,73,238,236,253,220,54,218,5,65,125,36,95,111,9,110,137,173,48,38,50,177,155,124,189,28,114,51,100,93,76,86,39,69,39,195,55,35,5,238,21,141,201,128,60,14,150,32,164,56,17,240,141,184,34,196,178,72,159,10,59,10,19,119,102,89,77,69,63,10,143,50,11,99,77,4,236,196,16,116,9,163,101,58,120,24,168,100,176,3,147,81,155,1,4,157,112,193,100,128,231,40,102,22,5,139,156,18,221,16,135,9,179,108,50,114,51,144,116,106,89,114,50,160,39,7,90,35,36,147,246,64,190,127,95,197,158,179,149,251,174,241,253,50,212,231,2,214,165,162,234,105,22,124,24,223,243,105,196,66,177,133,226,161,143,227,251,237,176,219,193,117,209,41,237,30,83,129,173,128,83,186,85,66,166,196,182,4,154,90,77,58,39,36,183,227,130,187,117,6,117,58,32,199,1,105,75,74,152,76,9,248,80,162,160,217,72,155,16,57,73,232,229,76,85,157,16,30,72,170,186,162,179,39,36,182,35,67,180,81,61,17,189,115,132,9,195,172,114,34,160,71,97,138,130,23,125,42,224,155,225,148,52,117,149,169,208,83,163,219,201,10,199,227,248,249,253,103,121,138,118,5,165,108,199,248,121,57,158,230,178,0,141,106,24,54,227,103,126,195,246,75,71,208,173,197,31,200,207,11,226,55,4,235,242,52,154,184,79,7,244,129,32,69,172,220,19,19,194,13,185,80,109,93,17,18,83,2,57,18,136,195,149,147,129,195,80,113,107,213,236,158,144,218,142,74,18,164,247,116,192,15,132,18,64,154,77,70,28,5,60,4,93,44,153,16,112,75,64,105,56,194,122,66,236,92,198,220,149,146,50,33,192,129,0,42,10,97,246,164,232,166,36,42,43,213,123,66,250,20,161,241,233,254,191,32,41,36,79,219,25,216,194,49,0,170,77,213,14,6,179,242,109,243,181,179,193,172,18,219,18,237,120,16,171,22,214,134,135,13,224,68,67,29,31,11,108,178,131,219,65,40,13,88,157,34,157,2,136,219,33,45,158,18,219,100,109,141,76,181,162,154,186,76,181,2,77,109,141,60,144,153,0,246,173,131,207,81,91,137,127,21,142,52,147,147,56,219,183,215,112,156,222,123,114,229,213,20,25,132,173,156,64,68,18,235,245,114,188,207,254,52,18,2,204,214,95,126,229,213,171,232,63,69,51,210,168,207,70,119,69,119,120,153,233,119,222,161,175,180,187,207,162,209,93,214,34,187,167,186,141,206,234,149,124,243,31,183,214,185,219,221,66,231,207,242,231,91,43,100,236,102,133,242,231,25,123,101,108,188,173,78,155,68,161,216,57,53,59,70,40,103,108,75,149,246,192,215,254,192,61,57,50,192,139,202,218,158,176,34,189,147,98,31,12,143,218,225,23,156,211,45,225,1,145,91,123,237,26,132,119,211,104,229,55,232,227,187,171,25,1,109,195,177,210,30,57,136,178,180,247,100,210,21,187,243,72,54,57,82,203,40,225,241,112,71,101,202,109,127,83,240,124,221,27,222,189,30,252,184,254,96,246,60,66,167,107,190,126,247,202,155,105,126,73,26,81,232,18,81,224,142,229,195,219,11,147,44,27,75,238,175,149,12,253,3,232,51,166,57,164,129,177,178,164,242,243,103,223,124,189,230,45,250,228,122,89,10,141,126,169,224,179,91,8,254,72,137,18,229,84,242,227,181,75,69,49,242,71,137,14,57,82,145,81,9,153,21,217,58,12,17,89,3,249,83,198,169,209,147,81,185,34,93,110,198,40,90,162,38,91,255,8,207,111,68,110,41,180,170,170,185,142,80,62,203,34,136,63,105,4,63,112,7,191,225,176,28,161,111,7,11,154,15,103,97,93,129,86,247,56,27,70,200,32,138,106,120,142,85,61,118,58,52,163,199,86,96,104,190,190,178,5,132,38,240,12,97,188,63,37,188,166,43,45,15,214,55,181,118,57,48,31,27,91,86,251,89,248,212,216,14,149,65,62,39,52,6,60,20,27,237,221,195,242,122,156,114,243,235,61,163,244,158,2,129,247,10,163,123,253,122,147,183,111,238,136,218,153,47,213,254,26,193,171,233,157,12,82,111,166,227,198,85,99,235,168,92,29,65,78,24,167,89,95,21,233,170,202,236,187,188,9,117,159,77,195,197,118,44,238,51,116,146,16,17,47,155,186,174,18,178,128,116,16,219,50,204,66,127,254,230,235,207,181,174,186,76,148,21,139,69,69,203,89,248,253,119,79,159,133,40,180,238,184,214,55,109,204,98,247,121,201,243,143,111,251,209,11,144,140,108,107,86,107,119,97,46,234,50,155,201,24,228,105,118,79,198,218,168,230,111,47,32,65,237,198,129,241,33,145,97,212,165,117,185,212,220,234,110,248,70,136,110,20,124,1,29,59,14,111,39,216,162,59,139,145,59,162,244,252,235,177,245,166,171,252,137,26,46,249,106,77,54,156,254,27,59,213,34,102,92,129,17,117,80,154,104,154,238,72,185,165,131,75,214,35,22,91,134,167,192,176,94,159,68,22,2,246,90,173,215,75,99,248,31,176,59,52,14,131,225,183,147,236,205,246,114,31,14,28,227,225,236,83,50,252,104,182,73,126,71,230,158,24,115,155,127,23,123,221,132,218,3,159,204,194,231,54,186,134,81,12,129,35,215,44,246,227,211,166,245,62,131,133,203,186,246,31,227,8,122,102,102,27,151,63,233,22,110,154,5,174,75,2,184,19,55,235,189,239,162,168,69,105,76,170,138,150,198,152,220,72,135,136,35,30,67,218,61,12,63,5,120,26,161,189,175,130,149,91,35,221,49,180,46,1,74,69,205,31,183,83,197,93,114,53,220,190,191,128,5,209,95,120,191,187,120,243,205,59,69,205,53,171,56,125,111,70,56,149,122,22,254,69,212,65,74,74,200,29,63,4,181,83,39,74,26,204,224,226,52,10,192,133,128,248,252,193,56,140,96,30,73,248,223,230,63,89,147,99,85,113,102,180,24,66,92,137,106,22,221,177,183,166,225,117,234,199,170,149,215,120,103,110,183,49,191,95,189,118,57,97,151,78,107,132,94,191,154,19,20,127,81,86,181,54,17,248,251,45,30,238,121,212,240,184,146,20,184,62,118,15,211,51,83,65,108,249,102,71,15,225,231,192,12,11,218,11,243,17,117,215,231,139,213,183,51,104,145,209,157,247,103,102,234,233,82,45,224,137,29,176,216,229,206,24,125,125,82,231,167,222,208,245,249,170,3,251,124,255,245,103,38,17,114,154,220,164,15,240,19,21,111,163,100,67,115,33,41,74,72,174,169,108,54,226,12,43,118,14,143,31,27,33,51,42,177,65,86,221,167,29,55,201,220,23,173,142,68,9,206,50,15,217,188,143,228,53,250,128,62,162,155,118,162,27,99,189,199,93,210,121,18,132,97,187,211,5,111,56,43,41,222,81,200,20,72,22,241,131,21,222,211,205,75,166,49,44,211,96,10,197,36,251,173,86,58,129,97,183,194,133,56,199,154,108,44,37,57,89,97,49,46,141,62,115,83,15,206,73,193,248,33,169,25,86,164,84,88,81,201,114,164,14,74,211,2,215,12,97,82,85,156,98,7,160,15,33,105,234,27,146,62,181,197,79,141,60,122,74,183,130,6,207,191,64,63,138,141,208,2,125,78,249,41,213,44,37,193,183,180,166,232,3,201,8,71,223,26,74,240,212,232,71,163,74,194,15,64,117,240,17,180,71,240,73,33,126,99,33,10,189,58,15,244,229,167,135,98,35,56,10,65,213,145,76,231,6,37,186,150,20,251,125,91,82,10,89,16,238,136,38,214,153,141,138,41,185,221,136,236,208,20,68,110,89,105,58,109,220,206,172,220,81,201,116,187,147,141,67,12,221,118,157,167,248,254,212,162,234,122,125,81,157,181,100,179,145,201,222,48,152,220,88,13,187,230,159,162,230,168,187,224,93,79,90,99,146,186,52,242,80,103,144,9,173,105,182,186,137,161,221,45,208,110,137,118,247,209,238,4,237,30,160,221,195,6,252,115,253,233,205,178,200,254,216,9,210,28,155,62,173,200,243,109,144,210,82,148,219,102,172,196,52,187,49,163,133,169,23,189,220,100,72,145,162,66,149,164,205,36,126,10,81,10,85,145,148,162,167,159,126,99,190,241,143,116,91,115,34,209,55,180,228,2,25,136,164,2,125,100,247,148,68,161,175,217,134,186,234,3,67,2,66,45,25,149,38,108,246,168,87,181,26,252,91,208,162,85,5,225,124,228,243,227,249,27,173,170,141,213,117,53,66,31,61,120,227,168,43,231,171,74,40,102,29,245,41,235,171,83,42,33,72,57,38,156,109,203,4,158,183,65,4,180,153,1,174,181,40,18,28,47,31,152,58,65,183,22,149,41,66,201,238,209,26,219,126,172,132,180,179,97,172,79,163,195,131,156,84,138,38,254,163,221,216,57,21,49,152,137,144,168,244,86,138,186,66,202,166,38,34,80,76,36,37,227,182,245,42,47,15,244,17,117,26,233,83,186,111,31,152,37,46,11,147,203,226,127,18,243,253,80,169,72,150,193,12,56,247,254,56,7,92,203,104,73,74,149,11,89,36,165,40,123,143,255,102,51,36,93,225,167,174,100,39,96,95,48,109,95,48,253,83,63,94,96,97,39,70,85,74,19,39,181,218,144,244,229,214,110,138,187,214,182,53,85,68,210,82,143,137,172,32,91,234,42,79,236,116,152,139,180,86,112,172,111,68,173,193,205,132,212,90,116,196,154,97,86,158,18,206,50,55,183,239,72,38,246,78,218,111,11,154,171,226,37,73,188,181,118,247,131,85,197,74,220,57,60,208,76,165,199,52,63,167,88,43,58,239,41,145,233,238,82,239,161,81,115,70,121,182,234,172,199,34,207,21,213,9,94,86,103,35,19,156,138,209,192,190,76,89,41,142,204,134,229,27,187,213,222,219,118,117,251,67,208,244,147,133,170,139,130,200,67,211,253,28,76,194,153,210,152,105,90,180,246,206,231,247,90,104,138,50,142,178,12,93,152,183,208,78,162,156,109,107,73,145,155,75,124,96,181,214,79,227,91,115,73,168,113,186,165,101,214,12,128,224,168,230,168,160,101,221,64,237,221,114,11,30,94,22,169,25,35,92,108,71,226,253,104,147,212,14,12,223,201,173,29,156,137,139,14,155,217,178,179,115,32,242,2,23,73,141,168,72,202,244,33,89,172,186,5,254,73,74,238,147,220,171,186,92,203,109,20,248,209,35,5,239,71,79,147,214,82,25,158,74,64,170,174,108,147,140,41,152,152,50,79,232,50,254,90,86,108,145,58,221,162,83,150,81,129,82,98,194,92,33,82,103,76,32,150,75,82,80,68,139,13,205,144,203,163,232,187,210,118,224,116,142,44,88,150,113,10,42,157,58,211,67,103,126,229,131,25,229,40,164,221,221,212,79,94,163,139,186,183,209,101,219,29,191,85,2,255,203,45,62,75,130,249,234,50,194,193,19,220,252,194,137,166,192,60,197,70,124,82,104,3,244,69,245,146,238,189,132,47,14,204,202,120,106,21,46,198,229,67,95,174,72,9,212,161,112,232,11,172,52,163,238,92,136,194,35,42,149,130,115,172,74,82,97,200,90,72,117,73,149,74,224,226,229,140,21,166,151,29,219,86,146,140,81,152,212,165,40,112,191,72,5,19,234,41,35,87,19,181,184,64,19,50,99,37,225,189,49,156,168,29,205,240,57,149,194,99,101,93,80,99,22,118,99,112,130,250,22,191,192,44,73,58,174,71,66,175,176,82,81,61,70,186,185,169,139,140,96,94,157,93,164,185,8,15,94,203,243,124,32,122,84,110,55,179,7,79,2,243,192,16,44,79,30,6,247,130,248,65,116,81,133,155,165,141,126,243,251,181,185,249,53,98,185,156,118,61,236,106,167,217,5,242,134,215,210,251,183,145,16,226,174,47,87,253,94,93,18,165,71,253,114,176,145,227,129,93,77,125,28,118,8,43,97,96,249,146,130,229,124,68,85,180,98,196,23,50,41,42,111,118,7,193,42,7,176,183,107,2,14,6,78,73,83,75,61,97,48,121,74,25,217,62,37,121,39,166,176,159,196,166,184,247,114,74,240,238,182,73,226,161,255,79,10,255,159,20,12,241,255,147,194,255,39,133,88,73,12,87,89,77,31,204,100,163,4,175,53,93,245,39,110,191,237,128,207,126,103,231,119,127,24,80,97,140,202,185,105,44,183,39,89,165,156,85,137,164,169,134,188,70,248,29,173,246,59,166,41,68,184,221,31,239,37,169,38,247,57,109,236,107,190,104,75,27,251,83,229,64,243,72,27,187,195,36,158,55,238,3,84,113,154,107,3,192,127,80,132,222,129,50,252,63,2,150,29,16,63,144,180,104,99,45,42,195,99,254,5,14,40,44,161,224,169,231,248,193,188,57,199,54,253,57,121,96,56,138,13,94,204,187,61,52,238,170,94,118,204,64,123,56,161,157,120,202,114,66,24,100,78,38,148,133,35,240,65,4,60,234,5,228,128,31,57,82,232,145,101,224,194,114,68,88,142,9,247,123,248,228,8,30,248,143,216,7,248,136,125,225,209,135,71,104,199,109,119,186,199,251,222,54,102,37,28,178,122,212,21,219,56,231,244,172,7,161,224,57,241,17,165,199,128,193,197,220,209,54,216,128,198,240,29,29,53,10,32,127,143,31,244,224,195,165,135,123,108,17,119,216,30,63,105,92,84,46,7,232,239,127,91,62,54,147,234,223,127,242,36,40,57,194,253,249,152,0,37,79,88,30,17,150,29,33,175,57,111,134,109,125,251,254,75,122,176,71,5,21,192,1,182,209,162,25,206,247,110,34,152,153,164,211,140,110,163,182,141,73,201,10,131,96,203,234,10,48,30,160,24,44,84,0,45,67,100,192,202,156,149,12,134,142,59,175,224,238,32,51,61,215,196,238,86,1,67,179,245,199,210,90,81,137,29,33,1,130,187,240,188,128,78,129,54,30,206,179,199,10,7,124,164,111,10,78,202,46,26,176,20,251,198,126,100,76,82,183,14,26,168,35,166,130,79,137,169,125,77,104,99,56,38,43,156,82,235,180,61,94,97,11,37,14,106,99,184,206,101,249,193,179,248,162,191,26,158,178,117,63,184,127,129,207,78,105,158,218,198,91,82,225,69,99,254,77,254,201,222,117,173,183,110,195,224,251,60,5,186,163,175,182,62,78,13,251,65,186,151,19,247,236,189,231,179,23,130,96,138,144,105,147,58,235,170,217,38,1,252,144,66,18,83,9,47,29,26,49,227,200,52,96,199,129,118,26,113,52,162,233,53,165,88,246,215,227,66,225,99,114,112,60,158,61,217,244,248,134,171,40,144,220,189,33,9,24,36,204,191,156,9,8,152,227,40,79,70,233,213,154,71,174,201,123,121,35,178,236,227,216,129,4,23,248,239,223,232,78,247,250,31,92,227,177,235,24,204,145,150,153,187,193,197,48,14,140,7,51,56,24,152,74,187,76,176,85,149,64,216,169,157,221,117,11,16,116,219,128,110,123,208,157,43,1,33,67,188,54,74,149,95,130,233,193,88,141,159,62,3,32,70,16,35,13,81,155,35,82,123,138,212,30,145,186,83,164,14,73,111,12,254,202,126,221,132,171,187,33,174,76,36,251,248,234,108,11,125,127,116,109,55,196,117,221,144,55,45,47,86,222,180,172,96,191,64,174,67,185,94,225,167,62,43,151,28,144,114,169,222,3,127,158,150,58,108,99,118,136,194,182,122,248,114,176,189,60,74,230,154,173,239,150,199,216,84,155,58,208,27,73,158,162,158,136,157,36,214,199,180,250,64,234,103,164,181,73,72,166,81,102,104,230,12,73,122,38,127,181,214,129,156,124,3,33,61,248,54,102,34,87,130,222,212,41,122,51,137,55,130,60,73,61,17,91,73,220,38,169,91,38,127,204,183,38,113,23,40,185,206,22,129,126,38,203,193,198,128,167,159,220,139,42,33,117,71,82,69,98,95,74,123,249,36,38,79,80,19,41,145,220,219,227,17,125,79,148,134,188,66,87,243,25,90,198,199,87,152,16,159,39,255,195,4,99,237,238,226,98,30,23,57,189,142,150,249,180,182,21,224,251,180,170,37,105,85,177,40,218,135,173,82,57,105,222,67,227,161,211,101,2,251,188,64,221,130,113,96,251,2,129,104,113,215,62,47,209,58,208,125,11,189,203,138,196,64,180,68,160,65,237,154,14,63,178,2,95,237,239,98,92,180,118,121,153,116,134,41,7,70,151,10,45,82,212,145,41,204,42,42,173,9,19,73,91,114,160,104,84,72,164,215,13,114,227,98,28,67,178,241,248,124,242,38,26,121,200,207,204,111,104,106,53,63,106,87,177,105,93,205,74,166,60,138,213,147,187,84,51,189,179,223,70,146,177,123,99,216,190,220,160,128,59,244,217,14,83,37,187,253,107,44,112,94,214,14,131,206,218,172,116,21,179,92,63,227,90,108,173,253,147,119,53,229,199,127,15,49,38,231,203,15,110,93,184,91,60,80,109,19,81,41,139,160,104,19,227,131,193,215,207,138,161,163,21,73,3,55,30,88,197,204,72,43,120,111,174,93,150,71,28,51,204,247,34,207,199,241,191,96,139,253,210,44,127,218,111,101,73,227,100,169,12,86,69,242,7,215,205,42,149,21,84,236,218,169,30,140,182,248,217,159,117,237,130,30,236,88,100,21,248,164,142,7,131,71,107,251,159,130,95,72,106,95,34,223,103,217,85,12,58,56,240,63,224,251,31,39,154,111,182,39,181,197,200,28,179,74,40,105,230,237,118,106,67,19,39,124,222,110,226,11,62,42,115,124,90,79,149,202,221,65,59,114,178,61,34,209,112,113,32,33,210,173,169,197,38,193,184,52,77,161,53,35,241,208,112,40,0,245,64,65,84,175,159,215,178,145,40,200,162,132,173,99,41,167,178,188,172,147,200,57,87,160,232,93,76,137,228,115,149,158,163,203,142,50,202,37,32,152,30,189,186,116,120,109,63,158,195,155,3,50,82,212,105,144,98,230,185,106,37,39,231,163,60,176,154,242,211,149,188,137,169,223,61,78,136,117,150,79,182,51,156,100,173,36,20,47,232,229,80,114,73,47,192,178,203,177,228,17,122,26,235,225,30,207,127,254,163,65,239,233,213,154,95,225,174,250,244,97,107,30,146,253,201,37,152,198,128,110,44,180,238,195,48,195,49,30,202,106,69,150,53,81,140,163,238,128,41,44,8,115,151,204,44,200,171,85,98,20,149,5,78,53,134,217,241,53,78,12,37,187,48,204,245,60,30,254,69,142,147,28,170,106,252,204,19,83,137,239,48,243,203,124,38,123,163,164,209,207,27,220,188,197,207,27,92,193,25,20,164,205,192,234,37,78,229,229,231,113,90,108,56,160,151,29,205,255,31,205,153,251,73,167,138,85,106,193,113,166,93,75,209,163,241,54,123,156,165,97,249,100,89,138,107,29,12,113,166,110,205,25,220,205,173,39,151,53,253,21,74,250,250,251,38,74,156,26,103,188,105,126,255,163,42,246,71,108,3,182,5,219,165,55,66,1,164,253,199,238,236,213,18,72,223,129,239,161,81,31,12,185,119,251,102,191,91,2,105,76,7,198,42,182,21,203,81,201,50,54,74,149,35,182,30,58,15,125,191,24,78,102,143,79,0,214,38,193,123,67,100,231,171,140,73,203,164,231,207,175,184,27,114,181,101,160,50,171,45,3,21,210,82,229,48,50,65,85,8,19,157,218,213,155,115,61,177,199,220,148,198,136,11,23,85,62,227,37,11,22,201,60,77,26,72,108,129,12,144,88,249,139,129,200,234,230,17,130,53,93,142,48,37,152,146,48,117,115,196,23,186,59,195,182,116,74,85,137,214,81,18,23,19,167,127,15,190,33,127,78,183,66,249,4,95,85,21,235,242,165,213,224,169,181,86,213,148,167,211,199,116,231,195,235,83,71,77,119,90,208,13,97,1,88,76,249,46,101,59,80,190,75,207,69,224,213,167,9,193,51,232,108,222,197,117,11,252,172,161,79,95,57,211,148,161,167,175,124,121,0,154,199,142,125,28,214,35,237,96,117,74,45,81,3,85,104,28,175,246,79,161,5,251,91,139,212,224,96,78,105,240,231,220,173,11,250,119,69,226,209,17,160,231,175,182,112,232,63,1,110,78,25,27,188,33,42,34,193,88,69,218,162,20,3,81,77,8,236,80,18,2,110,168,2,85,119,118,127,15,20,254,160,213,240,195,22,226,130,16,236,240,8,216,194,71,171,96,133,10,102,166,130,82,172,130,250,124,42,124,147,248,39,50,240,6,166,182,202,67,162,157,210,222,224,213,119,99,242,28,188,8,118,97,138,118,215,56,179,130,225,107,181,61,180,106,129,86,219,28,60,63,97,26,221,16,93,123,188,33,178,27,139,218,119,46,234,161,209,230,126,232,156,216,232,38,132,122,223,252,107,135,247,248,177,53,126,208,192,186,190,187,222,205,82,226,168,230,33,201,110,84,104,179,227,23,179,198,30,115,212,216,195,202,141,15,3,92,44,106,33,186,168,163,127,172,131,203,128,255,200,253,208,217,120,137,49,105,181,13,91,69,213,253,150,59,133,214,244,56,233,147,13,80,175,206,187,255,216,186,106,228,8,98,0,86,239,47,52,234,179,28,182,29,120,70,160,11,195,49,61,255,44,195,113,181,96,102,148,36,40,103,68,111,2,166,202,146,93,70,104,63,4,18,141,200,226,172,97,225,57,77,67,95,145,119,203,33,163,56,232,63,167,217,203,43,116,0,77,121,82,4,108,232,219,247,2,223,111,150,39,42,9,115,8,193,58,112,218,126,46,85,186,173,36,151,169,188,181,3,71,201,175,84,172,116,59,118,210,107,97,190,218,35,105,48,159,232,86,70,35,103,190,58,39,210,134,121,210,9,243,159,166,26,5,179,236,121,58,55,134,174,242,65,231,207,116,194,55,9,153,12,51,93,124,98,17,69,31,44,155,178,37,86,255,127,3,239,74,20,154,55,85,181,92,46,203,101,39,6,205,74,220,121,149,183,79,72,241,236,113,184,178,212,218,247,170,175,181,70,37,50,166,188,169,137,88,157,44,187,154,57,26,39,178,157,8,197,104,121,208,114,111,119,243,118,228,153,18,160,131,184,179,201,92,118,85,21,134,111,111,12,255,44,253,149,50,77,133,3,100,148,120,179,92,179,89,229,200,142,235,48,240,42,188,0,80,2,192,245,60,78,28,248,165,10,222,233,127,119,151,202,83,83,243,3,25,77,44,82,99,33,233,159,184,188,218,8,63,31,35,180,225,231,94,243,5,150,190,56,84,173,188,183,196,211,61,63,203,15,228,252,253,137,227,163,69,32,38,61,109,50,230,124,136,219,250,26,253,111,179,199,227,224,241,175,203,162,67,255,190,97,122,216,238,222,95,22,62,12,44,172,188,36,187,239,118,125,108,174,86,27,4,21,48,193,106,30,58,29,71,176,13,42,251,113,48,186,104,242,164,121,211,60,141,42,48,42,112,216,200,10,203,254,151,219,164,219,160,219,254,219,109,124,162,64,190,211,105,208,169,91,148,45,31,112,153,96,21,229,251,86,22,115,194,6,122,245,122,216,179,126,150,62,36,187,231,109,107,254,114,124,217,173,127,155,247,255,141,202,177,60,90,212,117,91,0,189,173,202,11,120,248,120,215,229,33,120,222,246,197,245,134,71,210,251,109,35,128,54,114,250,253,169,240,106,120,201,78,4,194,136,151,0,34,139,220,164,61,60,94,156,131,206,26,218,241,201,54,149,192,134,234,82,215,218,240,34,232,13,122,68,22,114,140,238,139,253,154,173,123,183,1,167,5,73,39,129,201,113,98,179,135,117,159,4,71,189,120,179,220,248,98,216,5,79,126,185,244,59,184,178,216,158,234,133,229,129,139,40,10,69,215,251,18,118,18,89,38,4,211,33,69,176,33,37,148,66,186,33,68,134,5,43,216,118,147,247,228,139,54,248,167,47,170,231,139,244,227,98,157,131,109,83,188,92,133,66,241,117,49,47,214,71,8,63,227,182,126,124,162,154,211,231,61,61,84,7,43,155,62,108,241,35,3,12,31,48,72,123,178,126,137,180,132,114,249,34,237,193,49,10,41,192,227,49,253,41,124,121,88,49,112,104,83,245,59,93,27,245,41,23,243,27,36,22,66,240,80,5,195,58,171,29,118,188,35,85,14,111,94,108,213,211,143,228,158,18,192,143,216,45,208,32,97,45,255,24,38,141,92,71,99,241,5,34,165,4,127,27,207,210,190,6,204,154,230,199,15,88,30,56,101,11,253,28,132,11,45,69,71,89,81,61,252,216,102,129,217,68,88,134,228,108,72,228,29,3,185,154,198,196,39,158,5,214,93,114,251,190,141,21,124,49,89,24,39,148,25,126,44,65,73,72,125,97,217,85,27,4,1,177,212,8,253,196,104,165,145,239,166,150,234,141,213,206,35,135,24,18,165,111,201,233,1,77,90,180,82,12,164,14,207,146,15,90,127,0,184,101,116,42,44,9,102,27,207,62,233,76,68,199,152,137,169,111,201,33,77,111,41,188,218,244,50,60,31,209,13,95,104,246,120,145,201,134,89,51,95,58,176,133,126,127,198,81,174,244,81,56,243,224,102,64,211,37,167,70,247,32,146,89,30,61,251,174,196,212,130,91,191,173,88,96,13,68,183,137,39,97,210,160,8,137,158,172,91,12,53,170,251,230,128,191,149,225,61,144,4,95,5,46,139,220,250,133,181,230,253,134,18,204,57,180,41,70,201,158,81,190,153,253,29,3,40,174,59,193,12,126,218,0,26,147,13,128,159,35,244,167,19,70,135,131,223,121,91,232,146,8,157,24,224,5,57,173,251,144,172,167,198,10,144,228,221,102,25,252,156,142,72,50,8,244,165,118,171,228,0,61,205,2,81,190,36,203,75,136,156,82,39,135,168,173,38,32,11,248,78,63,154,121,42,186,201,36,164,68,46,41,120,77,8,24,45,184,162,98,139,108,32,223,28,220,35,234,140,182,214,35,83,233,0,147,211,160,148,250,50,250,27,252,75,10,123,12,150,169,116,17,78,127,202,158,186,105,7,51,207,231,38,96,198,115,161,12,130,217,129,102,113,6,216,75,0,12,18,243,147,46,142,207,143,174,19,227,205,241,230,52,28,41,122,147,34,54,214,195,55,25,246,119,105,14,85,94,155,48,127,184,247,115,241,74,10,64,154,22,51,77,78,11,247,150,6,7,13,41,77,202,198,136,215,1,223,98,85,181,163,139,218,126,19,33,154,3,94,131,93,106,58,174,53,202,231,251,168,92,68,246,88,140,218,203,160,167,134,171,239,35,95,217,31,11,253,177,61,117,98,34,21,182,235,6,15,125,106,104,222,58,164,174,68,13,60,88,145,30,203,23,33,74,3,161,133,71,147,237,33,153,62,73,201,46,200,238,148,218,49,231,5,52,216,125,190,232,25,221,148,12,81,46,15,198,72,38,43,20,23,154,53,184,75,85,20,32,212,9,80,27,227,5,163,101,11,229,54,73,68,18,47,22,169,148,110,60,127,219,2,171,229,65,6,91,201,39,76,197,253,253,200,210,204,78,125,57,33,19,150,194,40,60,55,116,128,102,138,54,165,18,52,29,73,36,223,45,202,23,229,162,163,86,141,211,42,192,173,250,28,65,83,75,4,235,70,22,250,175,188,171,108,128,28,7,161,159,231,95,188,235,185,116,164,211,157,115,119,119,215,117,119,223,95,127,64,40,203,155,116,236,92,86,70,152,52,105,9,33,121,4,200,170,76,220,166,57,176,144,138,85,32,170,53,210,11,186,162,214,229,186,45,218,3,72,248,78,34,131,13,198,12,26,122,128,33,16,1,57,226,0,22,106,3,139,3,106,162,161,7,218,22,158,225,168,36,61,66,219,198,143,222,46,103,202,27,111,41,133,46,80,91,125,52,229,141,189,110,199,127,225,40,74,84,187,55,231,5,20,27,234,215,32,120,33,185,9,78,78,84,193,7,71,113,247,189,181,81,144,173,191,181,223,187,237,251,71,84,190,234,48,187,96,246,206,1,185,155,194,236,56,180,169,90,72,190,33,154,191,68,13,217,47,13,234,249,12,117,9,134,6,72,33,56,167,145,36,176,216,11,238,169,128,169,190,133,241,99,161,196,125,126,239,182,61,167,71,251,213,47,241,240,78,109,50,115,97,56,111,55,178,11,12,215,5,132,179,207,12,248,186,94,254,13,240,75,121,212,160,184,72,242,26,127,160,182,94,167,204,228,65,82,246,202,97,23,47,54,198,60,34,235,201,16,65,247,190,191,112,243,184,100,36,64,121,27,82,90,52,47,21,116,33,2,243,225,194,38,183,119,86,71,59,116,101,139,184,149,79,183,22,137,32,239,50,73,118,153,208,118,95,137,90,252,160,92,124,175,153,73,133,151,47,220,213,155,128,217,29,164,229,69,47,197,229,69,84,139,204,212,86,36,218,148,31,186,91,171,76,147,169,9,11,65,82,250,23,75,249,197,71,55,247,132,196,17,51,9,40,39,215,89,42,76,46,60,163,210,70,177,129,194,52,75,66,225,199,244,89,154,52,27,70,145,185,43,248,232,25,69,113,84,50,227,93,145,174,181,227,28,244,101,122,250,94,35,230,0,207,248,215,164,100,90,143,89,98,177,199,243,216,158,229,177,107,86,10,210,49,159,120,78,149,45,90,230,138,23,57,84,207,244,176,184,71,248,115,100,156,105,245,114,34,84,178,127,120,45,114,125,7,55,136,144,33,200,117,134,169,231,113,27,13,143,101,26,197,22,66,133,219,109,137,210,163,177,71,85,148,232,59,28,219,164,61,206,216,228,85,233,4,170,143,217,24,233,249,134,38,146,247,82,169,142,90,8,131,203,16,168,253,48,153,156,234,46,37,238,82,254,72,176,117,137,239,81,42,78,95,137,165,84,123,45,61,159,75,214,198,237,194,195,121,29,199,101,167,238,29,159,167,88,114,14,87,140,125,23,138,81,62,255,49,138,177,251,173,106,145,3,17,178,62,20,160,32,187,206,18,103,122,180,71,111,202,206,16,238,51,173,188,60,141,160,233,178,69,63,114,33,127,9,218,188,20,11,130,87,66,133,20,240,41,116,160,66,85,115,134,15,87,223,145,202,20,44,212,65,255,246,109,79,26,211,69,47,203,213,151,102,228,28,100,68,4,58,73,213,149,205,50,101,9,114,183,72,148,37,130,60,76,158,186,255,172,60,121,20,74,147,186,168,19,64,160,43,243,86,112,81,159,166,88,65,7,102,186,20,124,217,191,26,100,104,24,201,25,154,122,245,250,118,249,221,250,244,249,236,173,126,157,36,150,189,233,124,49,38,7,136,158,98,237,174,97,226,13,9,201,37,73,221,45,179,169,24,184,173,227,89,70,184,66,202,98,77,108,184,115,125,108,122,160,134,62,185,32,215,157,180,211,212,143,158,150,189,1,106,8,155,53,156,103,110,219,166,226,188,200,161,243,227,188,217,103,234,226,11,107,217,94,32,34,187,48,240,34,5,106,243,236,22,187,12,35,220,66,21,158,67,215,34,88,177,123,174,216,196,31,70,73,204,160,208,251,43,157,154,151,115,158,154,183,179,136,227,174,43,30,17,216,169,245,20,0,203,164,173,233,193,133,204,79,199,132,194,88,123,42,207,39,30,79,99,219,151,88,139,106,135,6,51,10,204,72,203,24,10,112,99,48,84,175,51,46,156,206,200,201,240,4,239,228,59,109,205,179,97,19,80,241,98,76,29,245,70,193,26,128,171,0,13,55,53,122,23,196,116,99,223,229,43,42,93,176,4,236,210,137,215,26,149,84,27,252,47,13,167,213,191,48,43,133,118,93,43,194,249,193,217,27,162,90,222,250,28,51,124,254,201,187,111,189,245,57,93,155,122,177,52,82,47,154,254,42,225,122,67,88,36,89,83,119,200,214,133,163,199,78,94,24,238,97,72,89,130,148,191,130,155,230,92,13,21,175,9,101,28,247,179,119,13,105,212,39,242,14,76,13,89,246,76,47,80,111,137,6,238,91,93,181,64,75,229,103,33,118,33,90,43,135,171,5,67,244,66,39,156,206,148,112,189,117,217,26,253,245,153,10,202,159,76,248,60,44,4,217,55,188,184,129,87,46,244,35,101,200,123,28,70,138,40,165,239,31,125,244,71,39,185,207,129,151,176,224,60,141,205,243,159,45,212,143,8,177,165,237,95,57,46,141,168,254,133,158,208,72,26,198,231,159,110,199,39,14,238,114,46,176,3,42,63,101,130,29,129,40,88,56,77,24,183,143,152,51,215,242,100,146,156,201,112,223,59,175,153,253,101,131,236,157,163,215,78,168,2,193,187,111,236,51,208,108,36,156,241,107,222,125,163,153,253,125,234,97,80,125,248,170,236,236,215,183,63,153,76,210,93,159,242,242,94,188,65,125,239,219,1,220,36,77,206,37,95,216,245,98,190,187,190,113,139,223,17,232,242,136,58,156,252,25,166,70,121,66,255,198,119,192,238,65,145,84,10,11,185,17,152,251,203,224,137,116,68,62,171,89,196,82,151,139,74,226,20,228,118,132,60,94,196,163,179,71,165,84,81,139,199,254,6,155,165,47,209,14,181,93,154,134,72,129,255,149,29,83,180,168,52,103,118,76,225,252,168,49,179,251,123,140,153,192,107,226,197,9,73,20,190,238,23,51,106,40,155,0,127,176,36,68,94,249,199,30,255,31,244,124,255,247,246,252,4,154,51,220,177,191,110,148,176,1,116,204,99,202,73,66,80,151,176,151,196,93,76,93,39,95,250,21,191,41,40,143,0,146,0,0}; diff --git a/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h b/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h index 525c16aa..9a41a44a 100644 --- a/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h +++ b/Software/src/lib/ayushsharma82-ElegantOTA/src/elop.h @@ -3,6 +3,6 @@ #include -extern const uint8_t ELEGANT_HTML[11640]; +extern const uint8_t ELEGANT_HTML[10615]; #endif From 6094a2c85b4593ae2e4c9f39e2c75bb4c4ea6f1b Mon Sep 17 00:00:00 2001 From: korhojoa Date: Sat, 13 Sep 2025 17:28:56 +0300 Subject: [PATCH 097/150] Add tool to easily replace OTA file --- Software/src/lib/update_ota_html_gzip.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Software/src/lib/update_ota_html_gzip.py diff --git a/Software/src/lib/update_ota_html_gzip.py b/Software/src/lib/update_ota_html_gzip.py new file mode 100644 index 00000000..794fe8e2 --- /dev/null +++ b/Software/src/lib/update_ota_html_gzip.py @@ -0,0 +1,23 @@ +import json +from pathlib import Path +libpath = Path("ayushsharma82-ElegantOTA") +gzipped=libpath/"CurrentPlainHTML.txt.gz" +header=libpath/"src/elop.h" +cpp=libpath/"src/elop.cpp" +if not gzipped.exists(): + print(f"Please create {gzipped.resolve()} to replace OTA file.") + print(f"Example: zopfli -v --i10000 {libpath.resolve()}/CurrentPlainHTML.txt") + raise SystemExit(1) +gzipbytes=gzipped.read_bytes() +intlist = [int(one) for one in gzipbytes] +content = json.dumps(intlist).replace("[","{").replace("]","}").replace(" ", "") +headertext = header.read_text() +header.write_text(headertext[:1+headertext.find("[")]+str(len(gzipbytes))+headertext[headertext.find("]"):]) +cpptext = cpp.read_text() +first_bracket = cpptext.find("[") +second_bracket = cpptext.find("]") +corrected_bytes = cpptext[:1+first_bracket]+str(len(gzipbytes))+cpptext[second_bracket:] +cppout = corrected_bytes[:corrected_bytes.find("{")]+content+corrected_bytes[corrected_bytes.find(";"):]+"\n" +cpp.write_text(cppout) +print("File content updated from", gzipped.resolve()) +print("Bytes fixed:", cpptext[1+first_bracket:second_bracket], "to", len(gzipbytes)) From 9ee0dffb337d9d499e9f496fafba7a569bf9197c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 14 Sep 2025 22:45:03 +0300 Subject: [PATCH 098/150] Refactor Settings page with cards --- Software/src/battery/BATTERIES.cpp | 2 + .../src/devboard/webserver/settings_html.cpp | 136 +++++++++++++----- 2 files changed, 100 insertions(+), 38 deletions(-) diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index 9fb09e25..a444ed1a 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -18,6 +18,8 @@ std::vector supported_battery_types() { const char* name_for_chemistry(battery_chemistry_enum chem) { switch (chem) { + case battery_chemistry_enum::Autodetect: + return "Autodetect"; case battery_chemistry_enum::LFP: return "LFP"; case battery_chemistry_enum::NCA: diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 55bddc4a..1d249e65 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -864,6 +864,21 @@ const char* getCANInterfaceName(CAN_Interface interface) { grid-column: span 2; } + .settings-card { + background-color: #3a4b54; /* Slightly lighter than main background */ + padding: 15px 20px; + margin-bottom: 20px; + border-radius: 20px; /* Less rounded than 50px for a more card-like feel */ + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + } + .settings-card h3 { + color: #fff; + margin-top: 0; + margin-bottom: 15px; + padding-bottom: 8px; + border-bottom: 1px solid #4d5f69; + } + form .if-battery, form .if-inverter, form .if-charger, form .if-shunt { display: contents; } form[data-battery="0"] .if-battery { display: none; } form[data-inverter="0"] .if-inverter { display: none; } @@ -960,8 +975,12 @@ const char* getCANInterfaceName(CAN_Interface interface) {
-
- + + +
+

Battery config

+
+ + @@ -1023,12 +1042,29 @@ const char* getCANInterfaceName(CAN_Interface interface) {
+ + + +
+ + +
+ +
+
+ +
+

Inverter config

+
+
- %INVCOMM%
@@ -1067,12 +1103,19 @@ const char* getCANInterfaceName(CAN_Interface interface) {
+
+
+ +
+

Optional components config (optional)

+
+
- %CHGCOMM%
@@ -1082,11 +1125,21 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- %SHUNTCOMM%
+
+
+ +
+

Hardware config

+
+ + + + @@ -1097,17 +1150,7 @@ const char* getCANInterfaceName(CAN_Interface interface) { %EQSTOP% - - - - - -
- -
@@ -1149,6 +1192,17 @@ const char* getCANInterfaceName(CAN_Interface interface) {
+ + +
+
+ +
+

Connectivity settings

+
+ @@ -1191,28 +1245,6 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- - - - - - - - - - - - - - - - - - - - @@ -1240,6 +1272,34 @@ const char* getCANInterfaceName(CAN_Interface interface) {
+
+
+ +
+

Debug options

+
+ + + + + + + + + + + + + + + + + + + +
+
+
From 332e982beda6f1d4e4827a2e0b67b04084281126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 14 Sep 2025 23:12:32 +0300 Subject: [PATCH 099/150] Move save button, update naming --- .../src/devboard/webserver/settings_html.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 1d249e65..6c91561c 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -977,6 +977,10 @@ const char* getCANInterfaceName(CAN_Interface interface) {
+
+

Settings saved. Reboot to take the new settings into use.

+

+

Battery config

@@ -1107,7 +1111,7 @@ const char* getCANInterfaceName(CAN_Interface interface) {
-

Optional components config (optional)

+

Optional components config

- +
@@ -1175,12 +1179,9 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- + - - - @@ -1188,7 +1189,7 @@ const char* getCANInterfaceName(CAN_Interface interface) { - +
@@ -1255,6 +1256,8 @@ const char* getCANInterfaceName(CAN_Interface interface) { + + From 50d794d0dee09be91cabb8132b56348f4750a4ef Mon Sep 17 00:00:00 2001 From: Jonny Date: Sun, 14 Sep 2025 20:55:27 +0100 Subject: [PATCH 100/150] Restore previous SMA TRIPOWER behaviour to fix regression and potential issues --- Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 58 +++++++++++++++------- Software/src/inverter/SMA-TRIPOWER-CAN.h | 11 ++++ 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 213c530b..172cd4c0 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -137,6 +137,17 @@ void SmaTripowerInverter::map_can_frame_to_variable(CAN_frame rx_frame) { } } +void SmaTripowerInverter::pushFrame(CAN_frame* frame, std::function callback) { + if (listLength >= 20) { + return; //TODO: scream. + } + framesToSend[listLength] = { + .frame = frame, + .callback = callback, + }; + listLength++; +} + void SmaTripowerInverter::transmit_can(unsigned long currentMillis) { // Send CAN Message only if we're enabled by inverter @@ -144,6 +155,18 @@ void SmaTripowerInverter::transmit_can(unsigned long currentMillis) { return; } + if (listLength > 0 && currentMillis - previousMillis250ms >= INTERVAL_250_MS) { + previousMillis250ms = currentMillis; + // Send next frame. + Frame frame = framesToSend[0]; + transmit_can_frame(frame.frame); + frame.callback(); + for (int i = 0; i < listLength - 1; i++) { + framesToSend[i] = framesToSend[i + 1]; + } + listLength--; + } + if (!pairing_completed) { return; } @@ -151,19 +174,19 @@ void SmaTripowerInverter::transmit_can(unsigned long currentMillis) { // Send CAN Message every 2s if (currentMillis - previousMillis2s >= INTERVAL_2_S) { previousMillis2s = currentMillis; - transmit_can_frame(&SMA_358); + pushFrame(&SMA_358); } // Send CAN Message every 10s if (currentMillis - previousMillis10s >= INTERVAL_10_S) { previousMillis10s = currentMillis; - transmit_can_frame(&SMA_518); - transmit_can_frame(&SMA_4D8); - transmit_can_frame(&SMA_3D8); + pushFrame(&SMA_518); + pushFrame(&SMA_4D8); + pushFrame(&SMA_3D8); } // Send CAN Message every 60s (potentially SMA_458 is not required for stable operation) if (currentMillis - previousMillis60s >= INTERVAL_60_S) { previousMillis60s = currentMillis; - transmit_can_frame(&SMA_458); + pushFrame(&SMA_458); } } @@ -172,17 +195,18 @@ void SmaTripowerInverter::completePairing() { } void SmaTripowerInverter::transmit_can_init() { + listLength = 0; // clear all frames - transmit_can_frame(&SMA_558); //Pairing start - Vendor - transmit_can_frame(&SMA_598); //Serial - transmit_can_frame(&SMA_5D8); //BYD - transmit_can_frame(&SMA_618_0); //BATTERY - transmit_can_frame(&SMA_618_1); //-Box Pr - transmit_can_frame(&SMA_618_2); //emium H - transmit_can_frame(&SMA_618_3); //VS - transmit_can_frame(&SMA_358); - transmit_can_frame(&SMA_3D8); - transmit_can_frame(&SMA_458); - transmit_can_frame(&SMA_4D8); - transmit_can_frame(&SMA_518); + pushFrame(&SMA_558); //Pairing start - Vendor + pushFrame(&SMA_598); //Serial + pushFrame(&SMA_5D8); //BYD + pushFrame(&SMA_618_0); //BATTERY + pushFrame(&SMA_618_1); //-Box Pr + pushFrame(&SMA_618_2); //emium H + pushFrame(&SMA_618_3); //VS + pushFrame(&SMA_358); + pushFrame(&SMA_3D8); + pushFrame(&SMA_458); + pushFrame(&SMA_4D8); + pushFrame(&SMA_518, [this]() { this->completePairing(); }); } diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index 7a18ea2a..15a660cc 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -4,6 +4,8 @@ #include "../devboard/hal/hal.h" #include "SmaInverterBase.h" +#include + class SmaTripowerInverter : public SmaInverterBase { public: const char* name() override { return Name; } @@ -20,6 +22,7 @@ class SmaTripowerInverter : public SmaInverterBase { const int THIRTY_MINUTES = 1200; void transmit_can_init(); + void pushFrame(CAN_frame* frame, std::function callback = []() {}); void completePairing(); unsigned long previousMillis250ms = 0; // will store last time a 250ms CAN Message was send @@ -28,6 +31,14 @@ class SmaTripowerInverter : public SmaInverterBase { unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send + typedef struct { + CAN_frame* frame; + std::function callback; + } Frame; + + unsigned short listLength = 0; + Frame framesToSend[20]; + uint32_t inverter_time = 0; uint16_t inverter_voltage = 0; int16_t inverter_current = 0; From 980e450871ce975d7acde0eb4638f27ecf762f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 15 Sep 2025 13:25:57 +0300 Subject: [PATCH 101/150] Update Software.cpp --- Software/Software.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 19cb5382..6428e12e 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.0.RC10experimental"; +const char* version_number = "9.0.0"; // Interval timers volatile unsigned long currentMillis = 0; From 26126bae1a32f4f4e8bc01e3fbd2f380ca1b3b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 15 Sep 2025 14:42:54 +0300 Subject: [PATCH 102/150] Tweak voltage limits for Zoe1 --- Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h index 1e5d7631..baa759d0 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h @@ -34,10 +34,10 @@ class RenaultZoeGen1Battery : public CanBattery { private: RenaultZoeGen1HtmlRenderer renderer; - static const int MAX_PACK_VOLTAGE_DV = 4200; //5000 = 500.0V + static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V static const int MIN_PACK_VOLTAGE_DV = 3000; static const int MAX_CELL_DEVIATION_MV = 150; - static const int MAX_CELL_VOLTAGE_MV = 4250; //Battery is put into emergency stop if one cell goes over this value + static const int MAX_CELL_VOLTAGE_MV = 4220; //Battery is put into emergency stop if one cell goes over this value static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value DATALAYER_BATTERY_TYPE* datalayer_battery; From 73c6821a9a4bf1c324036c4769801372269982d3 Mon Sep 17 00:00:00 2001 From: Jonny Date: Mon, 15 Sep 2025 20:23:35 +0100 Subject: [PATCH 103/150] Stop erroneous events when saving an empty SSID/pw --- Software/src/communication/nvm/comm_nvm.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 8a47e178..58eba5c9 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -207,10 +207,12 @@ void store_settings() { } if (!settings.putString("SSID", String(ssid.c_str()))) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 1); + if (ssid != "") + set_event(EVENT_PERSISTENT_SAVE_INFO, 1); } if (!settings.putString("PASSWORD", String(password.c_str()))) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 2); + if (password != "") + set_event(EVENT_PERSISTENT_SAVE_INFO, 2); } if (!settings.putUInt("BATTERY_WH_MAX", datalayer.battery.info.total_capacity_Wh)) { From df52d067e78c742096434dfdf5b7124a70c7d16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 16 Sep 2025 13:36:42 +0300 Subject: [PATCH 104/150] Update Software.cpp --- Software/Software.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 6428e12e..5c65c717 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.0.0"; +const char* version_number = "9.0.dev"; // Interval timers volatile unsigned long currentMillis = 0; From 79964a0601a009a20f1c785d74e3384bfe71139b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 16 Sep 2025 14:44:30 +0300 Subject: [PATCH 105/150] Remove old method to disable webserver to save flash --- Software/Software.cpp | 16 +++++----------- Software/src/devboard/webserver/webserver.cpp | 3 --- Software/src/devboard/webserver/webserver.h | 2 -- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 5c65c717..63f2026b 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -86,9 +86,7 @@ void connectivity_loop(void*) { // Init wifi init_WiFi(); - if (webserver_enabled) { - init_webserver(); - } + init_webserver(); if (mdns_enabled) { init_mDNS(); @@ -98,9 +96,7 @@ void connectivity_loop(void*) { START_TIME_MEASUREMENT(wifi); wifi_monitor(); - if (webserver_enabled) { - ota_monitor(); - } + ota_monitor(); END_TIME_MEASUREMENT_MAX(wifi, datalayer.system.status.wifi_task_10s_max_us); @@ -388,11 +384,9 @@ void core_loop(void*) { END_TIME_MEASUREMENT_MAX(comm, datalayer.system.status.time_comm_us); - if (webserver_enabled) { - START_TIME_MEASUREMENT(ota); - ElegantOTA.loop(); - END_TIME_MEASUREMENT_MAX(ota, datalayer.system.status.time_ota_us); - } + START_TIME_MEASUREMENT(ota); + ElegantOTA.loop(); + END_TIME_MEASUREMENT_MAX(ota, datalayer.system.status.time_ota_us); // Process currentMillis = millis(); diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 5a58b66a..70647e95 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -23,9 +23,6 @@ extern std::string http_username; extern std::string http_password; -bool webserver_enabled = - true; // Global flag to enable or disable the webserver //Old method to disable was with #ifdef WEBSERVER - bool webserver_auth = false; // Create AsyncWebServer object on port 80 diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h index 6f3f5c45..6cbb956f 100644 --- a/Software/src/devboard/webserver/webserver.h +++ b/Software/src/devboard/webserver/webserver.h @@ -7,8 +7,6 @@ #include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h" #include "../../lib/mathieucarbou-AsyncTCPSock/src/AsyncTCP.h" -extern bool webserver_enabled; - extern const char* version_number; // The current software version, shown on webserver // Common charger parameters From 5277665dd12149c6969149647ea970c1d1fd818f Mon Sep 17 00:00:00 2001 From: Jonny Date: Tue, 16 Sep 2025 16:11:13 +0100 Subject: [PATCH 106/150] Fix validation so that 8 character WiFi passwords work --- Software/src/devboard/webserver/webserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 5a58b66a..404b5aed 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -621,7 +621,7 @@ void init_webserver() { def_route_with_auth("/updatePassword", server, HTTP_GET, [](AsyncWebServerRequest* request) { if (request->hasParam("value")) { String value = request->getParam("value")->value(); - if (value.length() > 8) { // Check if password is within the allowable length + if (value.length() >= 8) { // Password must be 8 characters or longer password = value.c_str(); store_settings(); request->send(200, "text/plain", "Updated successfully"); From 024446862459f81d928a14d0fe9d9c1a4e36d3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 17 Sep 2025 23:06:30 +0300 Subject: [PATCH 107/150] Make contactor opening take 9s instead of 60s --- Software/src/battery/TESLA-BATTERY.cpp | 30 +++++++++++++------------- Software/src/battery/TESLA-BATTERY.h | 6 +++++- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 42226c9f..ff4208be 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -976,22 +976,22 @@ void TeslaBattery:: if ((datalayer.system.status.inverter_allows_contactor_closing == true) && (datalayer.battery.status.bms_status != FAULT) && (!datalayer.system.settings.equipment_stop_active)) { // Carry on: 0x221 DRIVE state & reset power down timer - vehicleState = 1; - powerDownTimer = 180; //0x221 50ms cyclic, 20 calls/second + vehicleState = CAR_DRIVE; + powerDownSeconds = 9; } else { // Faulted state, or inverter blocks contactor closing // Shut down: 0x221 ACCESSORY state for 3 seconds, followed by GOING_DOWN, then OFF - if (powerDownTimer <= 180 && powerDownTimer > 120) { - vehicleState = 2; //ACCESSORY - powerDownTimer--; + if (powerDownSeconds <= 9 && powerDownSeconds > 6) { + vehicleState = ACCESSORY; + powerDownSeconds--; } - if (powerDownTimer <= 120 && powerDownTimer > 60) { - vehicleState = 3; //GOING_DOWN - powerDownTimer--; + if (powerDownSeconds <= 6 && powerDownSeconds > 3) { + vehicleState = GOING_DOWN; + powerDownSeconds--; } - if (powerDownTimer <= 60 && powerDownTimer > 0) { - vehicleState = 0; //OFF - powerDownTimer--; + if (powerDownSeconds <= 3 && powerDownSeconds > 0) { + vehicleState = CAR_OFF; + powerDownSeconds--; } } @@ -2059,7 +2059,7 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) { previousMillis50 = currentMillis; //0x221 VCFRONT_LVPowerState - if (vehicleState == 1) { // Drive + if (vehicleState == CAR_DRIVE) { switch (muxNumber_TESLA_221) { case 0: generateMuxFrameCounterChecksum(TESLA_221_DRIVE_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8); @@ -2077,7 +2077,7 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) { //Generate next new frame frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16; } - if (vehicleState == 2) { // Accessory + if (vehicleState == ACCESSORY) { switch (muxNumber_TESLA_221) { case 0: generateMuxFrameCounterChecksum(TESLA_221_ACCESSORY_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8); @@ -2095,7 +2095,7 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) { //Generate next new frame frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16; } - if (vehicleState == 3) { // Going down + if (vehicleState == GOING_DOWN) { switch (muxNumber_TESLA_221) { case 0: generateMuxFrameCounterChecksum(TESLA_221_GOING_DOWN_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8); @@ -2113,7 +2113,7 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) { //Generate next new frame frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16; } - if (vehicleState == 0) { // Off + if (vehicleState == CAR_OFF) { switch (muxNumber_TESLA_221) { case 0: generateMuxFrameCounterChecksum(TESLA_221_OFF_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8); diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 0bf4037f..91311b52 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -78,7 +78,11 @@ class TeslaBattery : public CanBattery { uint8_t muxNumber_TESLA_221 = 0; uint8_t frameCounter_TESLA_221 = 15; // Start at 15 for Mux 0 uint8_t vehicleState = 1; // "OFF": 0, "DRIVE": 1, "ACCESSORY": 2, "GOING_DOWN": 3 - uint16_t powerDownTimer = 180; // Car power down (i.e. contactor open) tracking timer, 3 seconds per sendingState + static const uint8_t CAR_OFF = 0; + static const uint8_t CAR_DRIVE = 1; + static const uint8_t ACCESSORY = 2; + static const uint8_t GOING_DOWN = 3; + uint8_t powerDownSeconds = 9; // Car power down (i.e. contactor open) tracking timer, 3 seconds per sendingState //0x2E1 VCFRONT_status, 6 mux tracker uint8_t muxNumber_TESLA_2E1 = 0; //0x334 UI From 15143d1384c5f3bae853c35dab1a6b4e4b505e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 17 Sep 2025 23:23:55 +0300 Subject: [PATCH 108/150] Add configurable option for estimated SOC --- Software/src/battery/BATTERIES.cpp | 2 ++ Software/src/battery/BATTERIES.h | 2 +- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 19 ++++++++++--------- Software/src/battery/KIA-E-GMP-BATTERY.h | 2 +- Software/src/communication/nvm/comm_nvm.cpp | 1 + .../src/devboard/webserver/settings_html.cpp | 14 ++++++++++++++ Software/src/devboard/webserver/webserver.cpp | 8 ++++---- 7 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index a444ed1a..1c954d13 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -296,6 +296,8 @@ bool user_selected_tesla_GTW_rightHandDrive = true; uint16_t user_selected_tesla_GTW_mapRegion = 2; uint16_t user_selected_tesla_GTW_chassisType = 2; uint16_t user_selected_tesla_GTW_packEnergy = 1; +/* User-selected EGMP+others settings */ +bool user_selected_use_estimated_SOC = false; // Use 0V for user selected cell/pack voltage defaults (On boot will be replaced with saved values from NVM) uint16_t user_selected_max_pack_voltage_dV = 0; diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 0324c189..cb24124e 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -62,7 +62,7 @@ extern uint16_t user_selected_max_pack_voltage_dV; extern uint16_t user_selected_min_pack_voltage_dV; extern uint16_t user_selected_max_cell_voltage_mV; extern uint16_t user_selected_min_cell_voltage_mV; - +extern bool user_selected_use_estimated_SOC; extern bool user_selected_LEAF_interlock_mandatory; extern bool user_selected_tesla_digital_HVIL; extern uint16_t user_selected_tesla_GTW_country; diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index 20f3cd8e..664d4867 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -114,16 +114,17 @@ uint8_t KiaEGmpBattery::calculateCRC(CAN_frame rx_frame, uint8_t length, uint8_t void KiaEGmpBattery::update_values() { -#ifdef ESTIMATE_SOC_FROM_CELLVOLTAGE - // Use the simplified pack-based SOC estimation with proper compensation - datalayer.battery.status.real_soc = estimateSOC(batteryVoltage, datalayer.battery.info.number_of_cells, batteryAmps); + if (user_selected_use_estimated_SOC) { + // Use the simplified pack-based SOC estimation with proper compensation + datalayer.battery.status.real_soc = + estimateSOC(batteryVoltage, datalayer.battery.info.number_of_cells, batteryAmps); - // For comparison or fallback, we can still calculate from min/max cell voltages - SOC_estimated_lowest = estimateSOCFromCell(CellVoltMin_mV); - SOC_estimated_highest = estimateSOCFromCell(CellVoltMax_mV); -#else - datalayer.battery.status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00 -#endif + // For comparison or fallback, we can still calculate from min/max cell voltages + SOC_estimated_lowest = estimateSOCFromCell(CellVoltMin_mV); + SOC_estimated_highest = estimateSOCFromCell(CellVoltMax_mV); + } else { + datalayer.battery.status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00 + } datalayer.battery.status.soh_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00% diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.h b/Software/src/battery/KIA-E-GMP-BATTERY.h index dfd0237c..f28b8529 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.h +++ b/Software/src/battery/KIA-E-GMP-BATTERY.h @@ -3,7 +3,7 @@ #include "CanBattery.h" #include "KIA-E-GMP-HTML.h" -#define ESTIMATE_SOC_FROM_CELLVOLTAGE +extern bool user_selected_use_estimated_SOC; class KiaEGmpBattery : public CanBattery { public: diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 58eba5c9..315c9fcc 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -104,6 +104,7 @@ void init_stored_settings() { user_selected_can_addon_crystal_frequency_mhz = settings.getUInt("CANFREQ", 8); user_selected_canfd_addon_crystal_frequency_mhz = settings.getUInt("CANFDFREQ", 40); user_selected_LEAF_interlock_mandatory = settings.getBool("INTERLOCKREQ", false); + user_selected_use_estimated_SOC = settings.getBool("SOCESTIMATED", false); user_selected_tesla_digital_HVIL = settings.getBool("DIGITALHVIL", false); user_selected_tesla_GTW_country = settings.getUInt("GTWCOUNTRY", 0); user_selected_tesla_GTW_rightHandDrive = settings.getBool("GTWRHD", false); diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 6c91561c..8184bea4 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -251,6 +251,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return settings.getBool("DBLBTR") ? "checked" : ""; } + if (var == "SOCESTIMATED") { + return settings.getBool("SOCESTIMATED") ? "checked" : ""; + } + if (var == "CNTCTRL") { return settings.getBool("CNTCTRL") ? "checked" : ""; } @@ -912,6 +916,11 @@ const char* getCANInterfaceName(CAN_Interface interface) { display: contents; } + form .if-socestimated { display: none; } /* Integrations where you can turn on SOC estimation */ + form[data-battery="16"] .if-socestimated { + display: contents; + } + form .if-dblbtr { display: none; } form[data-dblbtr="true"] .if-dblbtr { display: contents; @@ -1022,6 +1031,11 @@ const char* getCANInterfaceName(CAN_Interface interface) {
+
+ + +
+
+ + + diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 9933da74..9350652d 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -506,6 +506,8 @@ void init_webserver() { } else if (p->name() == "SUBNET4") { auto type = atoi(p->value().c_str()); settings.saveUInt("SUBNET4", type); + } else if (p->name() == "APNAME") { + settings.saveString("APNAME", p->value().c_str()); } else if (p->name() == "APPASSWORD") { settings.saveString("APPASSWORD", p->value().c_str()); } else if (p->name() == "HOSTNAME") { diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index ab9831ee..9179f0e2 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -54,7 +54,7 @@ static uint16_t current_check_interval = WIFI_CHECK_INTERVAL; static bool connected_once = false; void init_WiFi() { - DEBUG_PRINTF("init_Wifi enabled=%d, apå=%d, ssid=%s, password=%s\n", wifi_enabled, wifiap_enabled, ssid.c_str(), + DEBUG_PRINTF("init_Wifi enabled=%d, ap=%d, ssid=%s, password=%s\n", wifi_enabled, wifiap_enabled, ssid.c_str(), password.c_str()); if (!custom_hostname.empty()) { From 983105ab6a079156ffbf963d3fdc963a52c015a0 Mon Sep 17 00:00:00 2001 From: Jonny Date: Tue, 23 Sep 2025 07:15:11 +0100 Subject: [PATCH 121/150] Enable QIO and 80mhz flash on Lilygo T-CAN485 build (50-80% perf improvement) --- platformio.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platformio.ini b/platformio.ini index f4a37b8f..ba16969a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -26,6 +26,9 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/ board = esp32dev monitor_speed = 115200 monitor_filters = default, time, log2file +board_build.flash_mode = qio +board_build.f_flash = 80000000 +board_build.arduino.memory_type = qio_qspi board_build.partitions = min_spiffs.csv framework = arduino build_flags = -I include -DHW_LILYGO From a0de6b092b2034ff512f653d7683c1e8829f6ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 23 Sep 2025 09:38:28 +0300 Subject: [PATCH 122/150] Enable QIO and 80MHZ flash on Stark CMR --- platformio.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platformio.ini b/platformio.ini index ba16969a..1afd6624 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,6 +39,9 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/ board = esp32dev monitor_speed = 115200 monitor_filters = default, time, log2file, esp32_exception_decoder +board_build.flash_mode = qio +board_build.f_flash = 80000000 +board_build.arduino.memory_type = qio_qspi board_build.partitions = min_spiffs.csv framework = arduino build_flags = -I include -DHW_STARK From ed2ebb00fd5a4b541b2f68e0fad3a1656a8675af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 23 Sep 2025 10:01:21 +0300 Subject: [PATCH 123/150] Update Software.cpp --- Software/Software.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 63f2026b..96ee0487 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.0.dev"; +const char* version_number = "9.1.0"; // Interval timers volatile unsigned long currentMillis = 0; From 48d416b5c4a964a3b6949f587fd8aabf4bb1b3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 23 Sep 2025 10:28:46 +0300 Subject: [PATCH 124/150] Update Software.cpp --- Software/Software.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.cpp b/Software/Software.cpp index 96ee0487..387a5dbe 100644 --- a/Software/Software.cpp +++ b/Software/Software.cpp @@ -34,7 +34,7 @@ #endif // The current software version, shown on webserver -const char* version_number = "9.1.0"; +const char* version_number = "9.1.dev"; // Interval timers volatile unsigned long currentMillis = 0; From 2ba937bd328378727e6c3b88fe3bcc9e61766c5a Mon Sep 17 00:00:00 2001 From: James Brookes Date: Tue, 23 Sep 2025 18:10:24 +0100 Subject: [PATCH 125/150] Fix incorrect user_selected_tesla_GTW_country value written to 7FF user_selected_tesla_GTW_rightHandDrive bit --- Software/src/battery/TESLA-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index ff4208be..08bd341f 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -2601,7 +2601,7 @@ void TeslaModel3YBattery::setup(void) { // Performs one time setup at startup //0x7FF GTW CAN frame values //Mux1 write_signal_value(&TESLA_7FF_Mux1, 16, 16, user_selected_tesla_GTW_country, false); - write_signal_value(&TESLA_7FF_Mux1, 11, 1, user_selected_tesla_GTW_country, false); + write_signal_value(&TESLA_7FF_Mux1, 11, 1, user_selected_tesla_GTW_rightHandDrive, false); //Mux3 write_signal_value(&TESLA_7FF_Mux3, 8, 4, user_selected_tesla_GTW_mapRegion, false); write_signal_value(&TESLA_7FF_Mux3, 18, 3, user_selected_tesla_GTW_chassisType, false); From d336b75f56f84ce5fb826f05c06b6bbb62d559d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 24 Sep 2025 22:54:53 +0300 Subject: [PATCH 126/150] Update valid cellvoltage filter --- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index 664d4867..47e6de23 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -72,7 +72,7 @@ uint16_t KiaEGmpBattery::selectSOC(uint16_t SOC_low, uint16_t SOC_high) { void KiaEGmpBattery::set_cell_voltages(CAN_frame rx_frame, int start, int length, int startCell) { for (size_t i = 0; i < length; i++) { - if ((rx_frame.data.u8[start + i] * 20) > 1000) { + if ((rx_frame.data.u8[start + i] * 20) > 1800) { datalayer.battery.status.cell_voltages_mV[startCell + i] = (rx_frame.data.u8[start + i] * 20); } } From 397e8d03a1023c2c474133b56d9badd6c95304ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 25 Sep 2025 00:00:35 +0300 Subject: [PATCH 127/150] Remove/shorten periodically logged items --- Software/src/battery/TESLA-BATTERY.cpp | 51 ++++---------------------- Software/src/devboard/wifi/wifi.cpp | 2 +- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 08bd341f..17021812 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -996,18 +996,18 @@ void TeslaBattery:: } printFaultCodesIfActive(); - logging.printf("BMS Contactors State: "); + logging.printf("Contactor State: "); logging.printf(getBMSContactorState(battery_contactor)); // Display what state the BMS thinks the contactors are in - logging.printf(", HVIL: "); + logging.printf(" HVIL: "); logging.printf(getHvilStatusState(battery_hvil_status)); - logging.printf(", NegativeState: "); + logging.printf(" NegState: "); logging.printf(getContactorState(battery_packContNegativeState)); - logging.printf(", PositiveState: "); + logging.printf(" PosState: "); logging.println(getContactorState(battery_packContPositiveState)); - logging.printf("HVP Contactors setState: "); + logging.printf("Cont. setState: "); logging.printf( getContactorText(battery_packContactorSetState)); // Display what state the HVP has set the contactors to be in - logging.printf(", Closing blocked: "); + logging.printf(" Closing blocked: "); logging.printf(getNoYes(battery_packCtrsClosingBlocked)); if (battery_packContactorSetState == 5) { logging.printf(" (already CLOSED)"); @@ -1015,43 +1015,8 @@ void TeslaBattery:: logging.printf(", Pyrotest: "); logging.println(getNoYes(battery_pyroTestInProgress)); - logging.printf("Battery values: "); - logging.printf("Real SOC: "); - logging.print(battery_soc_ui / 10.0, 1); - logging.printf(", Battery voltage: "); - logging.print(battery_volts / 10.0, 1); - logging.printf("V"); - logging.printf(", Battery HV current: "); - logging.print(battery_amps / 10.0, 1); - logging.printf("A"); - logging.printf(", Fully charged?: "); - if (battery_full_charge_complete) - logging.printf("YES, "); - else - logging.printf("NO, "); - if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { - logging.printf("LFP chemistry detected!"); - } - logging.println(""); - logging.printf("Cellstats, Max: "); - logging.print(battery_cell_max_v); - logging.printf("mV (cell "); - logging.print(battery_BrickVoltageMaxNum); - logging.printf("), Min: "); - logging.print(battery_cell_min_v); - logging.printf("mV (cell "); - logging.print(battery_BrickVoltageMinNum); - logging.printf("), Imbalance: "); - logging.print(battery_cell_deviation_mV); - logging.println("mV."); - - logging.printf("High Voltage Output Pins: %.2f V, Low Voltage: %.2f V, DC/DC 12V current: %.2f A.\n", - (battery_dcdcHvBusVolt * 0.146484), (battery_dcdcLvBusVolt * 0.0390625), - (battery_dcdcLvOutputCurrent * 0.1)); - - logging.printf("PCS_ambientTemp: %.2f°C, DCDC_Temp: %.2f°C, ChgPhA: %.2f°C, ChgPhB: %.2f°C, ChgPhC: %.2f°C.\n", - PCS_ambientTemp * 0.1 + 40, PCS_dcdcTemp * 0.1 + 40, PCS_chgPhATemp * 0.1 + 40, - PCS_chgPhBTemp * 0.1 + 40, PCS_chgPhCTemp * 0.1 + 40); + logging.printf("HV: %.2f V, 12V: %.2f V, 12V current: %.2f A.\n", (battery_dcdcHvBusVolt * 0.146484), + (battery_dcdcLvBusVolt * 0.0390625), (battery_dcdcLvOutputCurrent * 0.1)); } void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) { diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 9179f0e2..7d612fb0 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -108,7 +108,7 @@ void wifi_monitor() { if ((hasConnectedBefore && (currentMillis - lastWiFiCheck > current_check_interval)) || (!hasConnectedBefore && (currentMillis - lastWiFiCheck > INIT_WIFI_FULL_RECONNECT_INTERVAL))) { - DEBUG_PRINTF("Time to monitor Wi-Fi status: %d, %d, %d, %d, %d\n", hasConnectedBefore, currentMillis, lastWiFiCheck, + DEBUG_PRINTF("Wi-Fi status: %d, %d, %d, %d, %d\n", hasConnectedBefore, currentMillis, lastWiFiCheck, current_check_interval, INIT_WIFI_FULL_RECONNECT_INTERVAL); lastWiFiCheck = currentMillis; From 483d4300b13743d83d3966e34d23e5cf4ff83bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 25 Sep 2025 00:00:59 +0300 Subject: [PATCH 128/150] Make sure user only enables one general logging method at once --- .../src/devboard/webserver/settings_html.cpp | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index b5e6f813..eef9f425 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -1309,11 +1309,30 @@ const char* getCANInterfaceName(CAN_Interface interface) { + + - + - + From 132029169dadf8dc46a42199c22e29faac132081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 25 Sep 2025 11:09:56 +0300 Subject: [PATCH 129/150] Raise limit to 2500 for filtering --- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index 47e6de23..2da329ed 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -72,7 +72,7 @@ uint16_t KiaEGmpBattery::selectSOC(uint16_t SOC_low, uint16_t SOC_high) { void KiaEGmpBattery::set_cell_voltages(CAN_frame rx_frame, int start, int length, int startCell) { for (size_t i = 0; i < length; i++) { - if ((rx_frame.data.u8[start + i] * 20) > 1800) { + if ((rx_frame.data.u8[start + i] * 20) > 2500) { datalayer.battery.status.cell_voltages_mV[startCell + i] = (rx_frame.data.u8[start + i] * 20); } } From 48411680c66637a69a9d53e2474f77a0863ce2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 25 Sep 2025 12:04:36 +0300 Subject: [PATCH 130/150] Raise limit further --- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index 2da329ed..516dfa43 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -72,7 +72,7 @@ uint16_t KiaEGmpBattery::selectSOC(uint16_t SOC_low, uint16_t SOC_high) { void KiaEGmpBattery::set_cell_voltages(CAN_frame rx_frame, int start, int length, int startCell) { for (size_t i = 0; i < length; i++) { - if ((rx_frame.data.u8[start + i] * 20) > 2500) { + if ((rx_frame.data.u8[start + i] * 20) > 2600) { datalayer.battery.status.cell_voltages_mV[startCell + i] = (rx_frame.data.u8[start + i] * 20); } } From f48b4235c1438dbc664ec8a0cb065b2f3c81f729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 25 Sep 2025 15:30:52 +0300 Subject: [PATCH 131/150] Simplify DigitalHVIL sending to increase performance --- Software/src/battery/TESLA-BATTERY.cpp | 49 +++++++++----------------- Software/src/battery/TESLA-BATTERY.h | 3 +- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 17021812..7c5042c0 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1870,7 +1870,7 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) { stateMachineBMSQuery = 1; break; } - if (memcmp(&rx_frame.data.u8[0], "\x10", 1) == 0) { + if (rx_frame.data.u8[0] == 0x10) { //Received first data frame battery_partNumber[0] = rx_frame.data.u8[5]; battery_partNumber[1] = rx_frame.data.u8[6]; @@ -1879,7 +1879,7 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) { stateMachineBMSQuery = 2; break; } - if (memcmp(&rx_frame.data.u8[0], "\x21", 1) == 0) { + if (rx_frame.data.u8[0] == 0x21) { //Second part of part number after flow control battery_partNumber[3] = rx_frame.data.u8[1]; battery_partNumber[4] = rx_frame.data.u8[2]; @@ -1891,7 +1891,7 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) { logging.println("CAN UDS: Received BMS query second data frame"); break; } - if (memcmp(&rx_frame.data.u8[0], "\x22", 1) == 0) { + if (rx_frame.data.u8[0] == 0x22) { //Final part of part number battery_partNumber[10] = rx_frame.data.u8[1]; battery_partNumber[11] = rx_frame.data.u8[2]; @@ -1950,41 +1950,26 @@ CAN_frame can_msg_118[] = { {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x6F, 0x8E, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}}, {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x70, 0x8F, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}}}; -unsigned long lastSend1CF = 0; -unsigned long lastSend118 = 0; - -int index_1CF = 0; -int index_118 = 0; - void TeslaBattery::transmit_can(unsigned long currentMillis) { - if (user_selected_tesla_digital_HVIL) { //Special S/X? mode for 2024+ batteries - if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { - if (currentMillis - lastSend1CF >= 10) { - transmit_can_frame(&can_msg_1CF[index_1CF]); - - index_1CF = (index_1CF + 1) % 8; - lastSend1CF = currentMillis; - } - - if (currentMillis - lastSend118 >= 10) { - transmit_can_frame(&can_msg_118[index_118]); - - index_118 = (index_118 + 1) % 16; - lastSend118 = currentMillis; - } - } else { - index_1CF = 0; - index_118 = 0; - } - } - //Send 10ms messages if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { previousMillis10 = currentMillis; - //0x118 DI_systemStatus - transmit_can_frame(&TESLA_118); + if (user_selected_tesla_digital_HVIL) { //Special Digital HVIL mode for S/X 2024+ batteries + if ((datalayer.system.status.inverter_allows_contactor_closing) && + (datalayer.battery.status.bms_status != FAULT)) { + transmit_can_frame(&can_msg_1CF[index_1CF]); + index_1CF = (index_1CF + 1) % 8; + transmit_can_frame(&can_msg_118[index_118]); + index_118 = (index_118 + 1) % 16; + } + } else { //Normal handling of 118 message (Non digital HVIL version) + //0x118 DI_systemStatus + transmit_can_frame(&TESLA_118); + index_1CF = 0; //Stop broadcasting Digital HVIL 1CF and 118 to keep contactors open + index_118 = 0; + } //0x2E1 VCFRONT_status switch (muxNumber_TESLA_2E1) { diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 91311b52..49dc11f2 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -461,7 +461,8 @@ class TeslaBattery : public CanBattery { .DLC = 8, .ID = 0x610, .data = {0x02, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Define initial UDS request - + uint8_t index_1CF = 0; + uint8_t index_118 = 0; uint8_t stateMachineClearIsolationFault = 0xFF; uint8_t stateMachineBMSReset = 0xFF; uint8_t stateMachineSOCReset = 0xFF; From 3ef32795274acecc0c826171ffcaf3b899bb7673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 25 Sep 2025 15:49:50 +0300 Subject: [PATCH 132/150] Remove unused codeblocks --- Software/src/battery/TESLA-BATTERY.cpp | 217 +------------------------ Software/src/battery/TESLA-BATTERY.h | 2 - 2 files changed, 4 insertions(+), 215 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 7c5042c0..7700e685 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -113,33 +113,6 @@ inline const char* getHvilStatusState(int index) { } } -inline const char* getBMSState(int index) { - switch (index) { - case 0: - return "STANDBY"; - case 1: - return "DRIVE"; - case 2: - return "SUPPORT"; - case 3: - return "CHARGE"; - case 4: - return "FEIM"; - case 5: - return "CLEAR_FAULT"; - case 6: - return "FAULT"; - case 7: - return "WELD"; - case 8: - return "TEST"; - case 9: - return "SNA"; - default: - return "UNKNOWN"; - } -} - inline const char* getBMSContactorState(int index) { switch (index) { case 0: @@ -161,174 +134,10 @@ inline const char* getBMSContactorState(int index) { } } -inline const char* getBMSHvState(int index) { - switch (index) { - case 0: - return "DOWN"; - case 1: - return "COMING_UP"; - case 2: - return "GOING_DOWN"; - case 3: - return "UP_FOR_DRIVE"; - case 4: - return "UP_FOR_CHARGE"; - case 5: - return "UP_FOR_DC_CHARGE"; - case 6: - return "UP"; - default: - return "UNKNOWN"; - } -} - -inline const char* getBMSUiChargeStatus(int index) { - switch (index) { - case 0: - return "DISCONNECTED"; - case 1: - return "NO_POWER"; - case 2: - return "ABOUT_TO_CHARGE"; - case 3: - return "CHARGING"; - case 4: - return "CHARGE_COMPLETE"; - case 5: - return "CHARGE_STOPPED"; - default: - return "UNKNOWN"; - } -} - -inline const char* getPCS_DcdcStatus(int index) { - switch (index) { - case 0: - return "IDLE"; - case 1: - return "ACTIVE"; - case 2: - return "FAULTED"; - default: - return "UNKNOWN"; - } -} - -inline const char* getPCS_DcdcMainState(int index) { - switch (index) { - case 0: - return "STANDBY"; - case 1: - return "12V_SUPPORT_ACTIVE"; - case 2: - return "PRECHARGE_STARTUP"; - case 3: - return "PRECHARGE_ACTIVE"; - case 4: - return "DIS_HVBUS_ACTIVE"; - case 5: - return "SHUTDOWN"; - case 6: - return "FAULTED"; - default: - return "UNKNOWN"; - } -} - -inline const char* getPCS_DcdcSubState(int index) { - switch (index) { - case 0: - return "PWR_UP_INIT"; - case 1: - return "STANDBY"; - case 2: - return "12V_SUPPORT_ACTIVE"; - case 3: - return "DIS_HVBUS"; - case 4: - return "PCHG_FAST_DIS_HVBUS"; - case 5: - return "PCHG_SLOW_DIS_HVBUS"; - case 6: - return "PCHG_DWELL_CHARGE"; - case 7: - return "PCHG_DWELL_WAIT"; - case 8: - return "PCHG_DI_RECOVERY_WAIT"; - case 9: - return "PCHG_ACTIVE"; - case 10: - return "PCHG_FLT_FAST_DIS_HVBUS"; - case 11: - return "SHUTDOWN"; - case 12: - return "12V_SUPPORT_FAULTED"; - case 13: - return "DIS_HVBUS_FAULTED"; - case 14: - return "PCHG_FAULTED"; - case 15: - return "CLEAR_FAULTS"; - case 16: - return "FAULTED"; - case 17: - return "NUM"; - default: - return "UNKNOWN"; - } -} - -inline const char* getBMSPowerLimitState(int index) { - switch (index) { - case 0: - return "NOT_CALCULATED_FOR_DRIVE"; - case 1: - return "CALCULATED_FOR_DRIVE"; - default: - return "UNKNOWN"; - } -} - -inline const char* getHVPStatus(int index) { - switch (index) { - case 0: - return "INVALID"; - case 1: - return "NOT_AVAILABLE"; - case 2: - return "STALE"; - case 3: - return "VALID"; - default: - return "UNKNOWN"; - } -} - -inline const char* getHVPContactor(int index) { - switch (index) { - case 0: - return "NOT_ACTIVE"; - case 1: - return "ACTIVE"; - case 2: - return "COMPLETED"; - default: - return "UNKNOWN"; - } -} - -inline const char* getFalseTrue(bool value) { - return value ? "True" : "False"; -} - inline const char* getNoYes(bool value) { return value ? "Yes" : "No"; } -inline const char* getFault(bool value) { - return value ? "ACTIVE" : "NOT_ACTIVE"; -} - // Clamp DLC to 0–8 bytes for classic CAN inline int getDataLen(uint8_t dlc) { return std::min(dlc, 8); @@ -660,8 +469,6 @@ void TeslaBattery:: datalayer.battery.status.cell_min_voltage_mV = battery_cell_min_v; - battery_cell_deviation_mV = (battery_cell_max_v - battery_cell_min_v); - /* Value mapping is completed. Start to check all safeties */ //INTERNAL_OPEN_FAULT - Someone disconnected a high voltage cable while battery was in use @@ -2024,8 +1831,6 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) { default: break; } - //Generate next new frame - frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16; } if (vehicleState == ACCESSORY) { switch (muxNumber_TESLA_221) { @@ -2042,8 +1847,6 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) { default: break; } - //Generate next new frame - frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16; } if (vehicleState == GOING_DOWN) { switch (muxNumber_TESLA_221) { @@ -2060,8 +1863,6 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) { default: break; } - //Generate next new frame - frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16; } if (vehicleState == CAR_OFF) { switch (muxNumber_TESLA_221) { @@ -2078,23 +1879,13 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) { default: break; } - //Generate next new frame - frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16; } + //Generate next new frame + frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16; //0x3C2 VCLEFT_switchStatus - switch (muxNumber_TESLA_3C2) { - case 0: - transmit_can_frame(&TESLA_3C2_Mux0); - muxNumber_TESLA_3C2++; - break; - case 1: - transmit_can_frame(&TESLA_3C2_Mux1); - muxNumber_TESLA_3C2 = 0; - break; - default: - break; - } + transmit_can_frame(muxNumber_TESLA_3C2 == 0 ? &TESLA_3C2_Mux0 : &TESLA_3C2_Mux1); + muxNumber_TESLA_3C2 = !muxNumber_TESLA_3C2; // Flip between sending Mux0 and Mux1 on each pass //0x39D IBST_status transmit_can_frame(&TESLA_39D); diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 49dc11f2..9d599eba 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -467,10 +467,8 @@ class TeslaBattery : public CanBattery { uint8_t stateMachineBMSReset = 0xFF; uint8_t stateMachineSOCReset = 0xFF; uint8_t stateMachineBMSQuery = 0xFF; - uint16_t sendContactorClosingMessagesStill = 300; uint16_t battery_cell_max_v = 3300; uint16_t battery_cell_min_v = 3300; - uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV bool cellvoltagesRead = false; //0x3d2: 978 BMS_kwhCounter uint32_t battery_total_discharge = 0; From 95ee6ff9ae6f6db0dd9c6ed73a7633c02c1ded4c Mon Sep 17 00:00:00 2001 From: James Brookes Date: Thu, 25 Sep 2025 19:03:54 +0100 Subject: [PATCH 133/150] Add events for BMS_a145_SW_SOC_Change, BMS reset and SOC reset --- Software/src/battery/TESLA-BATTERY.cpp | 64 ++++++++++++++++++-------- Software/src/devboard/utils/events.cpp | 13 +++++- Software/src/devboard/utils/events.h | 5 ++ 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 7700e685..bc7b3761 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -483,11 +483,17 @@ void TeslaBattery:: } else { clear_event(EVENT_BATTERY_FUSE); } + // Raise any informational Tesla BMS events in BE + if (BMS_a145_SW_SOC_Change == true) { // BMS has recalibrated pack SOC + set_event(EVENT_BATTERY_SOC_RECALIBRATION, 0); + } else { + clear_event(EVENT_BATTERY_SOC_RECALIBRATION); + } if (user_selected_tesla_GTW_chassisType > 1) { //{{0, "Model S"}, {1, "Model X"}, {2, "Model 3"}, {3, "Model Y"}}; - // Autodetect algoritm for chemistry on 3/Y packs. + // Autodetect algorithm for chemistry on 3/Y packs. // NCM/A batteries have 96s, LFP has 102-108s - // Drawback with this check is that it takes 3-5minutes before all cells have been counted! + // Drawback with this check is that it takes 3-5 minutes before all cells have been counted! if (datalayer.battery.info.number_of_cells > 101) { datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; } @@ -528,23 +534,28 @@ void TeslaBattery:: //Start the BMS ECU reset statemachine, only if contactors are OPEN and BMS ECU allows it stateMachineBMSReset = 0; datalayer.battery.settings.user_requests_tesla_bms_reset = false; - logging.println("BMS reset requested"); + logging.println("INFO: BMS reset requested"); } else { logging.println("ERROR: BMS reset failed due to contactors not being open, or BMS ECU not allowing it"); stateMachineBMSReset = 0xFF; datalayer.battery.settings.user_requests_tesla_bms_reset = false; + set_event(EVENT_BMS_RESET_REQ_FAIL, 0); + clear_event(EVENT_BMS_RESET_REQ_FAIL); } } if (datalayer.battery.settings.user_requests_tesla_soc_reset) { - if (datalayer.battery.status.real_soc < 1500 || datalayer.battery.status.real_soc > 9000) { - //Start the SOC reset statemachine, only if SOC < 15% or > 90% + if ((datalayer.battery.status.real_soc < 1500 || datalayer.battery.status.real_soc > 9000) && + battery_contactor == 1) { + //Start the SOC reset statemachine, only if SOC less than 15% or greater than 90%, and contactors open stateMachineSOCReset = 0; datalayer.battery.settings.user_requests_tesla_soc_reset = false; - logging.println("SOC reset requested"); + logging.println("INFO: SOC reset requested"); } else { - logging.println("ERROR: SOC reset failed due to SOC not being less than 15 or greater than 90"); + logging.println("ERROR: SOC reset failed, SOC not < 15 or > 90"); stateMachineSOCReset = 0xFF; datalayer.battery.settings.user_requests_tesla_soc_reset = false; + set_event(EVENT_BATTERY_SOC_RESET_FAIL, 0); + clear_event(EVENT_BATTERY_SOC_RESET_FAIL); } } @@ -779,7 +790,7 @@ void TeslaBattery:: datalayer_extended.tesla.HVP_shuntBarTempStatus = HVP_shuntBarTempStatus; datalayer_extended.tesla.HVP_shuntAsicTempStatus = HVP_shuntAsicTempStatus; - //Safety checks for CAN message sesnding + //Safety checks for CAN message sending if ((datalayer.system.status.inverter_allows_contactor_closing == true) && (datalayer.battery.status.bms_status != FAULT) && (!datalayer.system.settings.equipment_stop_active)) { // Carry on: 0x221 DRIVE state & reset power down timer @@ -1667,10 +1678,10 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) { } */ break; - case 0x612: // CAN UDSs for BMS + case 0x612: // CAN UDS responses for BMS datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //BMS Query - if (stateMachineBMSQuery != 0xFF && stateMachineBMSReset == 0xFF) { + if (stateMachineBMSQuery != 0xFF && stateMachineBMSReset == 0xFF && stateMachineSOCReset == 0xFF) { if (memcmp(rx_frame.data.u8, "\x02\x50\x03\xAA\xAA\xAA\xAA\xAA", 8) == 0) { //Received initial response, proceed to actual query logging.println("CAN UDS: Received BMS query initial handshake reply"); @@ -1713,15 +1724,28 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) { break; } } - //BMS Reset - if (stateMachineBMSQuery == 0xFF) { // Make sure this is reset request not query - if (memcmp(rx_frame.data.u8, "\x02\x67\x06\xAA\xAA\xAA\xAA\xAA", 8) == 0) { - logging.println("CAN UDS: ECU unlocked"); - } else if (memcmp(rx_frame.data.u8, "\x03\x7F\x11\x78\xAA\xAA\xAA\xAA", 8) == 0) { - logging.println("CAN UDS: ECU reset request successful but ECU busy, response pending"); - } else if (memcmp(rx_frame.data.u8, "\x02\x51\x01\xAA\xAA\xAA\xAA\xAA", 8) == 0) { - logging.println("CAN UDS: ECU reset positive response, 1 second downtime"); - } + //BMS ECU responses + if (memcmp(rx_frame.data.u8, "\x02\x67\x06\xAA\xAA\xAA\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS ECU unlocked"); + } + if (memcmp(rx_frame.data.u8, "\x03\x7F\x11\x78\xAA\xAA\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS ECU reset request successful but ECU busy, response pending"); + } + if (memcmp(rx_frame.data.u8, "\x02\x51\x01\xAA\xAA\xAA\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS ECU reset positive response, 1 second downtime"); + set_event(EVENT_BMS_RESET_REQ_SUCCESS, 0); + clear_event(EVENT_BMS_RESET_REQ_SUCCESS); + } + if (memcmp(rx_frame.data.u8, "\x05\x71\x01\x04\x07\x01\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS SOC reset accepted, resetting BMS ECU"); + set_event(EVENT_BATTERY_SOC_RESET_SUCCESS, 0); + clear_event(EVENT_BATTERY_SOC_RESET_SUCCESS); + stateMachineBMSReset = 6; // BMS ECU already unlocked etc. so we jump straight to reset + } + if (memcmp(rx_frame.data.u8, "\x05\x71\x01\x04\x07\x00\xAA\xAA", 8) == 0) { + logging.println("CAN UDS: BMS SOC reset failed"); + set_event(EVENT_BATTERY_SOC_RESET_FAIL, 0); + clear_event(EVENT_BATTERY_SOC_RESET_FAIL); } break; default: @@ -2308,7 +2332,7 @@ void TeslaBattery::printFaultCodesIfActive() { printDebugIfActive(BMS_a139_SW_DC_Link_V_Irrational, "ERROR: BMS_a139_SW_DC_Link_V_Irrational"); printDebugIfActive(BMS_a141_SW_BMB_Status_Warning, "ERROR: BMS_a141_SW_BMB_Status_Warning"); printDebugIfActive(BMS_a144_Hvp_Config_Mismatch, "ERROR: BMS_a144_Hvp_Config_Mismatch"); - printDebugIfActive(BMS_a145_SW_SOC_Change, "ERROR: BMS_a145_SW_SOC_Change"); + printDebugIfActive(BMS_a145_SW_SOC_Change, "INFO: BMS_a145_SW_SOC_Change"); printDebugIfActive(BMS_a146_SW_Brick_Overdischarged, "ERROR: BMS_a146_SW_Brick_Overdischarged"); printDebugIfActive(BMS_a149_SW_Missing_Config_Block, "ERROR: BMS_a149_SW_Missing_Config_Block"); printDebugIfActive(BMS_a151_SW_external_isolation, "ERROR: BMS_a151_SW_external_isolation"); diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index d6875aab..6af46dcf 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -67,6 +67,9 @@ void init_events(void) { events.entries[EVENT_BATTERY_UNDERVOLTAGE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_BATTERY_VALUE_UNAVAILABLE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_BATTERY_ISOLATION].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_BATTERY_SOC_RECALIBRATION].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BATTERY_SOC_RESET_SUCCESS].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BATTERY_SOC_RESET_FAIL].level = EVENT_LEVEL_INFO; events.entries[EVENT_VOLTAGE_DIFFERENCE].level = EVENT_LEVEL_INFO; events.entries[EVENT_SOH_DIFFERENCE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_SOH_LOW].level = EVENT_LEVEL_ERROR; @@ -124,6 +127,8 @@ void init_events(void) { events.entries[EVENT_EQUIPMENT_STOP].level = EVENT_LEVEL_ERROR; events.entries[EVENT_SD_INIT_FAILED].level = EVENT_LEVEL_WARNING; events.entries[EVENT_PERIODIC_BMS_RESET].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BMS_RESET_REQ_SUCCESS].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BMS_RESET_REQ_FAIL].level = EVENT_LEVEL_INFO; events.entries[EVENT_BATTERY_TEMP_DEVIATION_HIGH].level = EVENT_LEVEL_WARNING; events.entries[EVENT_GPIO_CONFLICT].level = EVENT_LEVEL_ERROR; events.entries[EVENT_GPIO_NOT_DEFINED].level = EVENT_LEVEL_ERROR; @@ -244,6 +249,8 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { return "Battery measurement unavailable. Check 12V power supply and battery wiring!"; case EVENT_BATTERY_ISOLATION: return "Battery reports isolation error. High voltage might be leaking to ground. Check battery!"; + case EVENT_BATTERY_SOC_RECALIBRATION: + return "The BMS updated the HV battery State of Charge (SOC) by more than 3% based on SocByOcv."; case EVENT_VOLTAGE_DIFFERENCE: return "Too large voltage diff between the batteries. Second battery cannot join the DC-link"; case EVENT_SOH_DIFFERENCE: @@ -361,7 +368,11 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { case EVENT_SD_INIT_FAILED: return "SD card initialization failed, check hardware. Power must be removed to reset the SD card."; case EVENT_PERIODIC_BMS_RESET: - return "BMS Reset Event Completed."; + return "BMS reset event completed."; + case EVENT_BMS_RESET_REQ_SUCCESS: + return "BMS reset request completed successfully."; + case EVENT_BMS_RESET_REQ_FAIL: + return "BMS reset request failed - check contactors are open."; case EVENT_GPIO_CONFLICT: return "GPIO Pin Conflict: The pin used by '" + esp32hal->failed_allocator() + "' is already allocated by '" + esp32hal->conflicting_allocator() + "'. Please check your configuration and assign different pins."; diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 8f85b13b..3f4090be 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -49,6 +49,9 @@ XX(EVENT_BATTERY_ISOLATION) \ XX(EVENT_BATTERY_REQUESTS_HEAT) \ XX(EVENT_BATTERY_WARMED_UP) \ + XX(EVENT_BATTERY_SOC_RECALIBRATION) \ + XX(EVENT_BATTERY_SOC_RESET_SUCCESS) \ + XX(EVENT_BATTERY_SOC_RESET_FAIL) \ XX(EVENT_VOLTAGE_DIFFERENCE) \ XX(EVENT_SOH_DIFFERENCE) \ XX(EVENT_SOH_LOW) \ @@ -107,6 +110,8 @@ XX(EVENT_AUTOMATIC_PRECHARGE_FAILURE) \ XX(EVENT_SD_INIT_FAILED) \ XX(EVENT_PERIODIC_BMS_RESET) \ + XX(EVENT_BMS_RESET_REQ_SUCCESS) \ + XX(EVENT_BMS_RESET_REQ_FAIL) \ XX(EVENT_BATTERY_TEMP_DEVIATION_HIGH) \ XX(EVENT_GPIO_NOT_DEFINED) \ XX(EVENT_GPIO_CONFLICT) \ From c6b7ff82c06fec675fd40aed516643d83ee26d37 Mon Sep 17 00:00:00 2001 From: James Brookes Date: Thu, 25 Sep 2025 19:09:46 +0100 Subject: [PATCH 134/150] Alter BMS_a145_SW_SOC_Change event to once only --- Software/src/battery/TESLA-BATTERY.cpp | 6 ++++-- Software/src/battery/TESLA-BATTERY.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index bc7b3761..56a152b1 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -484,10 +484,12 @@ void TeslaBattery:: clear_event(EVENT_BATTERY_FUSE); } // Raise any informational Tesla BMS events in BE - if (BMS_a145_SW_SOC_Change == true) { // BMS has recalibrated pack SOC + if (BMS_a145_SW_SOC_Change == true && !BMS_SW_SOC_Change_Latch) { // BMS has newly recalibrated pack SOC + BMS_SW_SOC_Change_Latch = true; // Only set event once, BMS_a145 can be active for a while set_event(EVENT_BATTERY_SOC_RECALIBRATION, 0); - } else { clear_event(EVENT_BATTERY_SOC_RECALIBRATION); + } else if (BMS_a145_SW_SOC_Change == false) { + BMS_SW_SOC_Change_Latch = false; } if (user_selected_tesla_GTW_chassisType > 1) { //{{0, "Model S"}, {1, "Model X"}, {2, "Model 3"}, {3, "Model Y"}}; diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 9d599eba..8abc15db 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -877,6 +877,7 @@ class TeslaBattery : public CanBattery { bool BMS_a141_SW_BMB_Status_Warning = false; bool BMS_a144_Hvp_Config_Mismatch = false; bool BMS_a145_SW_SOC_Change = false; + bool BMS_SW_SOC_Change_Latch = false; bool BMS_a146_SW_Brick_Overdischarged = false; bool BMS_a149_SW_Missing_Config_Block = false; bool BMS_a151_SW_external_isolation = false; From 29129037b08f65f6437f4c505468985acb667b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 25 Sep 2025 23:44:46 +0300 Subject: [PATCH 135/150] Add more input field validation on Settings page --- .../src/devboard/webserver/settings_html.cpp | 63 ++++++++++++++----- Software/src/devboard/webserver/webserver.cpp | 3 +- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index eef9f425..fc59267b 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -1029,10 +1029,14 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- + - +
@@ -1163,10 +1167,14 @@ const char* getCANInterfaceName(CAN_Interface interface) { - + - + +
- + - - + +
@@ -1226,16 +1240,26 @@ const char* getCANInterfaceName(CAN_Interface interface) { - + - + - + - + @@ -1271,11 +1295,20 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- - + + + + - + + diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 9350652d..8bf9e71b 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -524,7 +524,8 @@ void init_webserver() { } else if (p->name() == "MQTTTOPIC") { settings.saveString("MQTTTOPIC", p->value().c_str()); } else if (p->name() == "MQTTTIMEOUT") { - settings.saveString("MQTTTIMEOUT", p->value().c_str()); + auto port = atoi(p->value().c_str()); + settings.saveUInt("MQTTTIMEOUT", port); } else if (p->name() == "MQTTOBJIDPREFIX") { settings.saveString("MQTTOBJIDPREFIX", p->value().c_str()); } else if (p->name() == "MQTTDEVICENAME") { From 04d9a362925eb51cf4b2cd15459bd91e725b25d0 Mon Sep 17 00:00:00 2001 From: James Brookes Date: Fri, 26 Sep 2025 10:38:56 +0100 Subject: [PATCH 136/150] Add event and logging text for SOC Reset --- Software/src/devboard/utils/events.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 6af46dcf..57882def 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -251,6 +251,10 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { return "Battery reports isolation error. High voltage might be leaking to ground. Check battery!"; case EVENT_BATTERY_SOC_RECALIBRATION: return "The BMS updated the HV battery State of Charge (SOC) by more than 3% based on SocByOcv."; + case EVENT_BATTERY_SOC_RESET_SUCCESS: + return "SOC reset routine was successful."; + case EVENT_BATTERY_SOC_RESET_FAIL: + return "SOC reset routine failed - check SOC is < 15 or > 90, and contactors are open."; case EVENT_VOLTAGE_DIFFERENCE: return "Too large voltage diff between the batteries. Second battery cannot join the DC-link"; case EVENT_SOH_DIFFERENCE: From 4058050423c1081b502c4da0f00660afeab940a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 26 Sep 2025 13:45:39 +0300 Subject: [PATCH 137/150] Add more tooltips --- .../src/devboard/webserver/settings_html.cpp | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index fc59267b..7f24b588 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -750,7 +750,7 @@ const char* getCANInterfaceName(CAN_Interface interface) { function editError(){alert('Invalid input');} - function editSSID(){var value=prompt('Enter new SSID:');if(value!==null){var xhr=new + function editSSID(){var value=prompt('Which SSID to connect to. Enter new SSID:');if(value!==null){var xhr=new XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/updateSSID?value='+encodeURIComponent(value),true);xhr.send();}} function editPassword(){var value=prompt('Enter new password:');if(value!==null){var xhr=new @@ -1041,7 +1041,8 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- +
@@ -1056,20 +1057,25 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- + - + - + - +
- +
@@ -1164,7 +1170,8 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- + Date: Fri, 26 Sep 2025 19:29:50 +0300 Subject: [PATCH 138/150] Improve password/username entering --- .../src/devboard/webserver/settings_html.cpp | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 7f24b588..f3f12f73 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -1248,14 +1248,14 @@ const char* getCANInterfaceName(CAN_Interface interface) { @@ -1304,14 +1304,18 @@ const char* getCANInterfaceName(CAN_Interface interface) {
- - + + - + - - +