From a4c075e3565d288e6ef0158b6944457a76acd0f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 16 Sep 2024 16:26:13 +0300 Subject: [PATCH 001/225] Add skeleton for eCMP --- Software/USER_SETTINGS.h | 1 + Software/src/battery/BATTERIES.h | 4 ++ Software/src/battery/ECMP-BATTERY.cpp | 74 +++++++++++++++++++++++++++ Software/src/battery/ECMP-BATTERY.h | 12 +++++ 4 files changed, 91 insertions(+) create mode 100644 Software/src/battery/ECMP-BATTERY.cpp create mode 100644 Software/src/battery/ECMP-BATTERY.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index b43581f16..811596297 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -18,6 +18,7 @@ //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MG_5_BATTERY //#define NISSAN_LEAF_BATTERY +//#define ECMP_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RENAULT_KANGOO_BATTERY diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 4cb112c18..d8136f757 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -14,6 +14,10 @@ #include "CHADEMO-BATTERY.h" #endif +#ifdef ECMP_BATTERY +#include "ECMP-BATTERY.h" +#endif + #ifdef IMIEV_CZERO_ION_BATTERY #include "IMIEV-CZERO-ION-BATTERY.h" #endif diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp new file mode 100644 index 000000000..82b027452 --- /dev/null +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -0,0 +1,74 @@ +#include "../include.h" +#ifdef ECMP_BATTERY +#include "../datalayer/datalayer.h" +#include "../devboard/utils/events.h" +#include "ECMP-BATTERY.h" + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent + +//Actual content messages +CAN_frame PSA_XXX = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x301, + .data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +void update_values_battery() { + + datalayer.battery.status.real_soc; + + datalayer.battery.status.soh_pptt; + + datalayer.battery.status.voltage_dV; + + datalayer.battery.status.current_dA; + + datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt + ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); + + datalayer.battery.status.max_charge_power_W; + + datalayer.battery.status.max_discharge_power_W; + + datalayer.battery.status.cell_max_voltage_mV; + + datalayer.battery.status.cell_min_voltage_mV; + + datalayer.battery.status.temperature_min_dC; + + datalayer.battery.status.temperature_max_dC; + + datalayer.battery.info.max_design_voltage_dV; + + datalayer.battery.info.min_design_voltage_dV; +} + +void receive_can_battery(CAN_frame rx_frame) { + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + switch (rx_frame.ID) { + case 0x123: + break; + default: + break; + } +} + +void send_can_battery() { + unsigned long currentMillis = millis(); + // Send 1s CAN Message + if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { + previousMillis1000 = currentMillis; + } +} + +void setup_battery(void) { // Performs one time setup at startup +#ifdef DEBUG_VIA_USB + Serial.println("PSA battery selected"); +#endif + + datalayer.battery.info.max_design_voltage_dV = 4040; // 404.0V, charging over this is not possible + datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V, under this, discharging further is disabled +} + +#endif diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h new file mode 100644 index 000000000..ef4232f9a --- /dev/null +++ b/Software/src/battery/ECMP-BATTERY.h @@ -0,0 +1,12 @@ +#ifndef ECMP_BATTERY_H +#define ECMP_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED +#define MAX_CELL_DEVIATION_MV 250 + +void setup_battery(void); +void transmit_can(CAN_frame* tx_frame, int interface); + +#endif From 8ac0aecb108e6a1e73cea2ce43fffe975f4d2f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 16 Sep 2024 21:40:04 +0300 Subject: [PATCH 002/225] Add all CAN messages sent by BMS. Map voltage --- Software/src/battery/ECMP-BATTERY.cpp | 109 ++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 7 deletions(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 82b027452..bb25309f3 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -8,11 +8,13 @@ static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent //Actual content messages -CAN_frame PSA_XXX = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x301, - .data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame ECMP_XXX = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x301, + .data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +static uint16_t battery_voltage = 37000; void update_values_battery() { @@ -20,7 +22,7 @@ void update_values_battery() { datalayer.battery.status.soh_pptt; - datalayer.battery.status.voltage_dV; + datalayer.battery.status.voltage_dV = (battery_voltage / 10); datalayer.battery.status.current_dA; @@ -47,7 +49,100 @@ void update_values_battery() { void receive_can_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { - case 0x123: + case 0x125: + break; + case 0x127: + break; + case 0x129: + break; + case 0x31B: + break; + case 0x358: + break; + case 0x359: + break; + case 0x361: + battery_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case 0x362: + break; + case 0x454: + break; + case 0x494: + break; + case 0x594: + break; + case 0x6D0: + break; + case 0x6D1: + break; + case 0x6D2: + break; + case 0x6D3: + break; + case 0x6D4: + break; + case 0x6E0: + break; + case 0x6E1: + break; + case 0x6E2: + break; + case 0x6E3: + break; + case 0x6E4: + break; + case 0x6E5: + break; + case 0x6E6: + break; + case 0x6E7: + break; + case 0x6E8: + break; + case 0x6E9: + break; + case 0x6EB: + break; + case 0x6ED: + break; + case 0x6EE: + break; + case 0x6EF: + break; + case 0x6F0: + break; + case 0x6F1: + break; + case 0x6F2: + break; + case 0x6F3: + break; + case 0x6F4: + break; + case 0x6F5: + break; + case 0x6F6: + break; + case 0x6F7: + break; + case 0x6F8: + break; + case 0x6F9: + break; + case 0x6FA: + break; + case 0x6FB: + break; + case 0x6FC: + break; + case 0x6FD: + break; + case 0x6FE: + break; + case 0x6FF: + break; + case 0x794: break; default: break; From a6adefdf3d11f6e48dc115381a9cc543cb82df3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 17 Sep 2024 21:44:53 +0300 Subject: [PATCH 003/225] Add SOC% candidate --- Software/src/battery/ECMP-BATTERY.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index bb25309f3..ae0ce9a8d 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -15,10 +15,11 @@ CAN_frame ECMP_XXX = {.FD = false, .data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; static uint16_t battery_voltage = 37000; +static uint16_t battery_soc = 0; void update_values_battery() { - datalayer.battery.status.real_soc; + datalayer.battery.status.real_soc = battery_soc * 100; datalayer.battery.status.soh_pptt; @@ -73,6 +74,7 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x594: break; case 0x6D0: + battery_soc = (100 - rx_frame.data.u8[0]); break; case 0x6D1: break; From 285d2798e1b5ea29b2e0813950c008f5529eadec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 19 Sep 2024 14:25:52 +0300 Subject: [PATCH 004/225] Add all 108 cellvoltages --- Software/src/battery/ECMP-BATTERY.cpp | 146 ++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 10 deletions(-) diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index ae0ce9a8d..f1ef2ea51 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -1,5 +1,6 @@ #include "../include.h" #ifdef ECMP_BATTERY +#include // For std::min and std::max #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" #include "ECMP-BATTERY.h" @@ -16,6 +17,7 @@ CAN_frame ECMP_XXX = {.FD = false, static uint16_t battery_voltage = 37000; static uint16_t battery_soc = 0; +static uint16_t cellvoltages[108]; void update_values_battery() { @@ -34,17 +36,29 @@ void update_values_battery() { datalayer.battery.status.max_discharge_power_W; - datalayer.battery.status.cell_max_voltage_mV; - - datalayer.battery.status.cell_min_voltage_mV; - datalayer.battery.status.temperature_min_dC; datalayer.battery.status.temperature_max_dC; - datalayer.battery.info.max_design_voltage_dV; + // 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.info.min_design_voltage_dV; + datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value; + datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value; } void receive_can_battery(CAN_frame rx_frame) { @@ -81,14 +95,30 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x6D2: break; case 0x6D3: + 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]; + cellvoltages[3] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6D4: + cellvoltages[4] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[5] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[6] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[7] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6E0: break; case 0x6E1: + cellvoltages[8] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[9] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[10] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[11] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6E2: + cellvoltages[12] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[13] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[14] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[15] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6E3: break; @@ -99,50 +129,146 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x6E6: break; case 0x6E7: + cellvoltages[16] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[17] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[18] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[19] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6E8: + cellvoltages[20] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[21] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[22] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[23] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6E9: + cellvoltages[24] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[25] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[26] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[27] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6EB: + cellvoltages[28] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[29] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[30] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[31] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6EC: + //Not available on e-C4 break; case 0x6ED: + cellvoltages[32] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[33] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[34] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[35] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6EE: + cellvoltages[36] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[37] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[38] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[39] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6EF: + cellvoltages[40] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[41] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[42] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[43] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F0: + cellvoltages[44] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[45] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[46] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[47] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F1: + cellvoltages[48] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[49] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[50] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[51] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F2: + cellvoltages[52] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[53] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[54] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[55] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F3: + cellvoltages[56] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[57] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[58] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[59] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F4: + cellvoltages[60] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[61] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[62] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[63] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F5: + cellvoltages[64] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[65] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[66] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[67] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F6: + cellvoltages[68] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[69] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[70] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[71] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F7: + cellvoltages[72] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[73] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[74] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[75] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F8: + cellvoltages[76] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[77] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[78] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[79] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6F9: + cellvoltages[80] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[81] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[82] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[83] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6FA: + cellvoltages[84] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[85] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[86] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[87] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6FB: + cellvoltages[88] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[89] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[90] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[91] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6FC: + cellvoltages[92] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[93] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[94] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[95] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6FD: + cellvoltages[96] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[97] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[98] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[99] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6FE: + cellvoltages[100] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[101] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[102] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[103] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; break; case 0x6FF: + cellvoltages[104] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[105] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[106] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[107] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages, 108 * sizeof(uint16_t)); break; case 0x794: break; @@ -161,11 +287,11 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup #ifdef DEBUG_VIA_USB - Serial.println("PSA battery selected"); + Serial.println("ECMP battery selected"); #endif - - datalayer.battery.info.max_design_voltage_dV = 4040; // 404.0V, charging over this is not possible - datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V, under this, discharging further is disabled + datalayer.battery.info.number_of_cells = 108; + datalayer.battery.info.max_design_voltage_dV = 4546; // 454.6V, charging over this is not possible + datalayer.battery.info.min_design_voltage_dV = 3210; // 321.0V, under this, discharging further is disabled } #endif From e45d1bb931fdb530be9ece9fc43e798e52599d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 17 Nov 2024 19:15:51 +0200 Subject: [PATCH 005/225] Add SMA skeleton --- Software/src/inverter/SMA-48V-CAN.cpp | 184 ++++++++++++++++++++++++++ Software/src/inverter/SMA-48V-CAN.h | 13 ++ 2 files changed, 197 insertions(+) create mode 100644 Software/src/inverter/SMA-48V-CAN.cpp create mode 100644 Software/src/inverter/SMA-48V-CAN.h diff --git a/Software/src/inverter/SMA-48V-CAN.cpp b/Software/src/inverter/SMA-48V-CAN.cpp new file mode 100644 index 000000000..4c9a37ce8 --- /dev/null +++ b/Software/src/inverter/SMA-48V-CAN.cpp @@ -0,0 +1,184 @@ +#include "../include.h" +#ifdef SMA_CAN +#include "../datalayer/datalayer.h" +#include "SMA-CAN.h" + +/* SMA 48V CAN protocol: +CAN 2.0A +500kBit/sec +11-Bit Identifiers */ + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis100ms = 0; + +//Actual content messages +CAN_frame SMA_558 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x558, + .data = {0x03, 0x12, 0x00, 0x04, 0x00, 0x59, 0x07, 0x07}}; //7x BYD modules, Vendor ID 7 BYD +CAN_frame SMA_598 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x598, + .data = {0x00, 0x00, 0x12, 0x34, 0x5A, 0xDE, 0x07, 0x4F}}; //B0-4 Serial, rest unknown +CAN_frame SMA_5D8 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x5D8, + .data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //B Y D +CAN_frame SMA_618_1 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //0 B A T T E R Y +CAN_frame SMA_618_2 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x48, 0x39}}; //1 - B O X H +CAN_frame SMA_618_3 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x02, 0x2E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}}; //2 - 0 +CAN_frame SMA_358 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x358, + .data = {0x0F, 0x6C, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_3D8 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x3D8, + .data = {0x04, 0x10, 0x27, 0x10, 0x00, 0x18, 0xF9, 0x00}}; +CAN_frame SMA_458 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x458, + .data = {0x00, 0x00, 0x06, 0x75, 0x00, 0x00, 0x05, 0xD6}}; +CAN_frame SMA_518 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x518, + .data = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}}; +CAN_frame SMA_4D8 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x4D8, + .data = {0x09, 0xFD, 0x00, 0x00, 0x00, 0xA8, 0x02, 0x08}}; +CAN_frame SMA_158 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x158, + .data = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA}}; + +static int16_t temperature_average = 0; +static uint16_t ampere_hours_remaining = 0; + +void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages + //Calculate values + + temperature_average = + ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); + + if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0 + ampere_hours_remaining = + ((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) * + 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) + } + + //Map values to CAN messages + //Battery charge voltage (eg 400.0V = 4000 , 16bits long) + SMA_351.data.u8[0] = ((datalayer.battery.info.max_design_voltage_dV - 20) >> 8); + SMA_351.data.u8[1] = ((datalayer.battery.info.max_design_voltage_dV - 20) & 0x00FF); + //Discharge limited current, 500 = 50A, (0.1, A) + SMA_351.data.u8[2] = (datalayer.battery.status.max_discharge_current_dA >> 8); + SMA_351.data.u8[3] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); + //Charge limited current, 125 =12.5A (0.1, A) + SMA_351.data.u8[4] = (datalayer.battery.status.max_charge_current_dA >> 8); + SMA_351.data.u8[5] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); + //Discharge voltage (eg 300.0V = 3000 , 16bits long) + SMA_351.data.u8[6] = ((datalayer.battery.info.min_design_voltage_dV + 20) >> 8); + SMA_351.data.u8[7] = ((datalayer.battery.info.min_design_voltage_dV + 20) & 0x00FF); + + //SOC (100.00%) + SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); + SMA_3D8.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF); + //StateOfHealth (100.00%) + SMA_3D8.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8); + SMA_3D8.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF); + //State of charge (AH, 0.1) + SMA_3D8.data.u8[4] = (ampere_hours_remaining >> 8); + SMA_3D8.data.u8[5] = (ampere_hours_remaining & 0x00FF); + + //Voltage (370.0) + SMA_4D8.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8); + SMA_4D8.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF); + //Current (TODO: signed OK?) + SMA_4D8.data.u8[2] = (datalayer.battery.status.current_dA >> 8); + SMA_4D8.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF); + //Temperature average + SMA_4D8.data.u8[4] = (temperature_average >> 8); + SMA_4D8.data.u8[5] = (temperature_average & 0x00FF); + //Battery ready + if (datalayer.battery.status.bms_status == ACTIVE) { + SMA_4D8.data.u8[6] = READY_STATE; + } else { + SMA_4D8.data.u8[6] = STOP_STATE; + } +} + +void receive_can_inverter(CAN_frame rx_frame) { + switch (rx_frame.ID) { + case 0x305: + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + //Frame0-1 Battery Voltage + //Frame2-3 Battery Current + //Frame4-5 Battery Temperature + //Frame6-7 SOC Battery + break; + case 0x306: + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + //Frame0-1 SOH Battery + //Frame2 Charging procedure + //Frame3 Operating state + //Frame4-5 Active error message + //Frame6-7 Battery charge voltage setpoint + break; + default: + break; + } +} + +void send_can_inverter() { + unsigned long currentMillis = millis(); + + // Send CAN Message every 100ms if Enable line is HIGH + if (datalayer.system.status.inverter_allows_contactor_closing) { + if (currentMillis - previousMillis100ms >= 100) { + previousMillis100ms = currentMillis; + + transmit_can(&SMA_351, can_config.inverter); + transmit_can(&SMA_355, can_config.inverter); + transmit_can(&SMA_356, can_config.inverter); + transmit_can(&SMA_35A, can_config.inverter); + transmit_can(&SMA_35B, can_config.inverter); + transmit_can(&SMA_35E, can_config.inverter); + transmit_can(&SMA_35F, can_config.inverter); + + //Remote quick stop (optional) + if (datalayer.battery.status.bms_status == FAULT) { + transmit_can(&SMA_00F, can_config.inverter); + //After receiving this message, Sunny Island will immediately go into standby. + //Please send start command, to start again. Manual start is also possible. + } + } + } +} + +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "SMA 48V CAN", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} +#endif diff --git a/Software/src/inverter/SMA-48V-CAN.h b/Software/src/inverter/SMA-48V-CAN.h new file mode 100644 index 000000000..111044a46 --- /dev/null +++ b/Software/src/inverter/SMA-48V-CAN.h @@ -0,0 +1,13 @@ +#ifndef SMA_CAN_H +#define SMA_CAN_H +#include "../include.h" + +#define CAN_INVERTER_SELECTED + +#define READY_STATE 0x03 +#define STOP_STATE 0x02 + +void transmit_can(CAN_frame* tx_frame, int interface); +void setup_inverter(void); + +#endif From 7eaeb7e15e157151c77bdeb91d7deece2d110053 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Mon, 18 Nov 2024 22:28:33 +1300 Subject: [PATCH 006/225] Tesla webserver Add multiplex messages to Tesla Battery, update datalayer exptended and add lines for advanced battery. --- Software/src/battery/TESLA-BATTERY.cpp | 314 ++++++++++++------ Software/src/datalayer/datalayer_extended.h | 28 +- .../webserver/advanced_battery_html.cpp | 53 +++ 3 files changed, 296 insertions(+), 99 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 6e4ea6b1d..c914fc89f 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -25,20 +25,21 @@ CAN_frame TESLA_221_2 = { static uint16_t sendContactorClosingMessagesStill = 300; static uint32_t battery_total_discharge = 0; static uint32_t battery_total_charge = 0; -static uint16_t battery_volts = 0; // V -static int16_t battery_amps = 0; // A -static uint16_t battery_raw_amps = 0; // A -static int16_t battery_max_temp = 0; // C* -static int16_t battery_min_temp = 0; // C* -static uint16_t battery_energy_buffer = 0; -static uint16_t battery_energy_to_charge_complete = 0; -static uint16_t battery_expected_energy_remaining = 0; -static uint8_t battery_full_charge_complete = 0; -static uint16_t battery_ideal_energy_remaining = 0; -static uint16_t battery_nominal_energy_remaining = 0; -static uint16_t battery_nominal_full_pack_energy = 600; -static uint16_t battery_beginning_of_life = 600; -static uint16_t battery_charge_time_remaining = 0; // Minutes +static uint16_t battery_volts = 0; // V +static int16_t battery_amps = 0; // A +static uint16_t battery_raw_amps = 0; // A +static int16_t battery_max_temp = 0; // C* +static int16_t battery_min_temp = 0; // C* +static uint16_t battery_energy_buffer = 0; // kWh +static uint16_t battery_energy_to_charge_complete = 0; // kWh +static uint16_t battery_expected_energy_remaining = 0; // kWh +static uint8_t battery_full_charge_complete = 0; // kWh +static uint8_t battery_fully_charged = 0; // kWh +static uint16_t battery_ideal_energy_remaining = 0; // kWh +static uint16_t battery_nominal_energy_remaining = 0; // kWh +static uint16_t battery_nominal_full_pack_energy = 600; // Kwh +static uint16_t battery_beginning_of_life = 600; // kWh +static uint16_t battery_charge_time_remaining = 0; // Minutes static uint16_t battery_regenerative_limit = 0; static uint16_t battery_discharge_limit = 0; static uint16_t battery_max_heat_park = 0; @@ -47,12 +48,13 @@ static uint16_t battery_max_discharge_current = 0; static uint16_t battery_max_charge_current = 0; static uint16_t battery_bms_max_voltage = 0; static uint16_t battery_bms_min_voltage = 0; -static uint16_t battery_high_voltage = 0; -static uint16_t battery_low_voltage = 0; -static uint16_t battery_output_current = 0; +static uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt +static uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt +static uint16_t battery_dcdcLvOutputCurrent = + 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent static uint16_t battery_soc_min = 0; static uint16_t battery_soc_max = 0; -static uint16_t battery_soc_vi = 0; +static uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui static uint16_t battery_soc_ave = 0; static uint16_t battery_cell_max_v = 3700; static uint16_t battery_cell_min_v = 3700; @@ -66,6 +68,12 @@ static uint8_t battery_packContPositiveState = 0; static uint8_t battery_packContactorSetState = 0; static uint8_t battery_packCtrsClosingAllowed = 0; static uint8_t battery_pyroTestInProgress = 0; +static uint8_t battery_battTempPct = 0; +static uint32_t battery_packMass = 0; +static uint32_t battery_platformMaxBusVoltage = 0; +static uint32_t battery_packConfigMultiplexer = 0; +static uint32_t battery_moduleType = 0; +static uint32_t battery_reservedConfig = 0; //Fault codes static uint8_t battery_WatchdogReset = 0; //Warns if the processor has experienced a reset due to watchdog reset. static uint8_t battery_PowerLossReset = 0; //Warns if the processor has experienced a reset due to power loss. @@ -138,6 +146,7 @@ static uint16_t battery2_energy_buffer = 0; static uint16_t battery2_energy_to_charge_complete = 0; static uint16_t battery2_expected_energy_remaining = 0; static uint8_t battery2_full_charge_complete = 0; +static uint8_t battery2_fully_charged = 0; static uint16_t battery2_ideal_energy_remaining = 0; static uint16_t battery2_nominal_energy_remaining = 0; static uint16_t battery2_nominal_full_pack_energy = 600; @@ -151,12 +160,12 @@ static uint16_t battery2_max_discharge_current = 0; static uint16_t battery2_max_charge_current = 0; static uint16_t battery2_bms_max_voltage = 0; static uint16_t battery2_bms_min_voltage = 0; -static uint16_t battery2_high_voltage = 0; -static uint16_t battery2_low_voltage = 0; -static uint16_t battery2_output_current = 0; +static uint16_t battery2_dcdcHvBusVolt = 0; //update name +static uint16_t battery2_dcdcLvBusVolt = 0; //update name +static uint16_t battery2_dcdcLvOutputCurrent = 0; //update name static uint16_t battery2_soc_min = 0; static uint16_t battery2_soc_max = 0; -static uint16_t battery2_soc_vi = 0; +static uint16_t battery2_soc_ui = 0; static uint16_t battery2_soc_ave = 0; static uint16_t battery2_cell_max_v = 3700; static uint16_t battery2_cell_min_v = 3700; @@ -170,6 +179,12 @@ static uint8_t battery2_packContPositiveState = 0; static uint8_t battery2_packContactorSetState = 0; static uint8_t battery2_packCtrsClosingAllowed = 0; static uint8_t battery2_pyroTestInProgress = 0; +static uint8_t battery2_battTempPct = 0; +static uint32_t battery2_packMass = 0; +static uint32_t battery2_platformMaxBusVoltage = 0; +static uint32_t battery2_packConfigMultiplexer = 0; +static uint32_t battery2_moduleType = 0; +static uint32_t battery2_reservedConfig = 0; //Fault codes static uint8_t battery2_WatchdogReset = 0; //Warns if the processor has experienced a reset due to watchdog reset. static uint8_t battery2_PowerLossReset = 0; //Warns if the processor has experienced a reset due to power loss. @@ -259,7 +274,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.soh_pptt = 9900; //Tesla batteries do not send a SOH% value on bus. Hardcode to 99% - datalayer.battery.status.real_soc = (battery_soc_vi * 10); //increase SOC range from 0-100.0 -> 100.00 + datalayer.battery.status.real_soc = (battery_soc_ui * 10); //increase SOC range from 0-100.0 -> 100.00 datalayer.battery.status.voltage_dV = (battery_volts * 10); //One more decimal needed (370 -> 3700) @@ -277,12 +292,12 @@ void update_values_battery() { //This function maps all the values fetched via } //The allowed charge power behaves strangely. We instead estimate this value - if (battery_soc_vi > 990) { + if (battery_soc_ui > 990) { datalayer.battery.status.max_charge_power_W = FLOAT_MAX_POWER_W; - } else if (battery_soc_vi > + } else if (battery_soc_ui > RAMPDOWN_SOC) { // When real SOC is between RAMPDOWN_SOC-99%, ramp the value between Max<->0 datalayer.battery.status.max_charge_power_W = - RAMPDOWNPOWERALLOWED * (1 - (battery_soc_vi - RAMPDOWN_SOC) / (1000.0 - RAMPDOWN_SOC)); + RAMPDOWNPOWERALLOWED * (1 - (battery_soc_ui - RAMPDOWN_SOC) / (1000.0 - RAMPDOWN_SOC)); //If the cellvoltages start to reach overvoltage, only allow a small amount of power in if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { if (battery_cell_max_v > (MAX_CELL_VOLTAGE_LFP - FLOAT_START_MV)) { @@ -348,6 +363,33 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.packContactorSetState = battery_packContactorSetState; datalayer_extended.tesla.packCtrsClosingAllowed = battery_packCtrsClosingAllowed; datalayer_extended.tesla.pyroTestInProgress = battery_pyroTestInProgress; + datalayer_extended.tesla.battery_beginning_of_life = battery_beginning_of_life; //add from her down + datalayer_extended.tesla.battery_battTempPct = battery_battTempPct; + datalayer_extended.tesla.battery_dcdcLvBusVolt = battery_dcdcLvBusVolt; + datalayer_extended.tesla.battery_dcdcHvBusVolt = battery_dcdcHvBusVolt; + datalayer_extended.tesla.battery_dcdcLvOutputCurrent = battery_dcdcLvOutputCurrent; + datalayer_extended.tesla.battery_nominal_full_pack_energy = battery_nominal_full_pack_energy; + datalayer_extended.tesla.battery_nominal_energy_remaining = battery_nominal_energy_remaining; + datalayer_extended.tesla.battery_ideal_energy_remaining = battery_ideal_energy_remaining; + datalayer_extended.tesla.battery_energy_to_charge_complete = battery_energy_to_charge_complete; + datalayer_extended.tesla.battery_energy_buffer = battery_energy_buffer; + datalayer_extended.tesla.battery_full_charge_complete = battery_full_charge_complete; + datalayer_extended.tesla.battery_total_discharge = battery_total_discharge; + datalayer_extended.tesla.battery_total_charge = battery_total_charge; + datalayer_extended.tesla.battery_fully_charged = battery_fully_charged; + datalayer_extended.tesla.battery_packConfigMultiplexer = battery_packConfigMultiplexer; + datalayer_extended.tesla.battery_moduleType = battery_moduleType; + datalayer_extended.tesla.battery_reservedConfig = battery_reservedConfig; + datalayer_extended.tesla.battery_packMass = battery_packMass; + datalayer_extended.tesla.battery_platformMaxBusVoltage = battery_platformMaxBusVoltage; + datalayer_extended.tesla.battery_bms_min_voltage = battery_bms_min_voltage; + datalayer_extended.tesla.battery_bms_max_voltage = battery_bms_max_voltage; + datalayer_extended.tesla.battery_max_charge_current = battery_max_charge_current; + datalayer_extended.tesla.battery_max_discharge_current = battery_max_discharge_current; + datalayer_extended.tesla.battery_soc_ave = battery_soc_ave; + datalayer_extended.tesla.battery_soc_max = battery_soc_max; + datalayer_extended.tesla.battery_soc_min = battery_soc_min; + datalayer_extended.tesla.battery_soc_ui = battery_soc_ui; #ifdef DEBUG_VIA_USB @@ -370,7 +412,7 @@ void update_values_battery() { //This function maps all the values fetched via Serial.print("Battery values: "); Serial.print("Real SOC: "); - Serial.print(battery_soc_vi / 10.0, 1); + Serial.print(battery_soc_ui / 10.0, 1); print_int_with_units(", Battery voltage: ", battery_volts, "V"); print_int_with_units(", Battery HV current: ", (battery_amps * 0.1), "A"); Serial.print(", Fully charged?: "); @@ -394,11 +436,11 @@ void update_values_battery() { //This function maps all the values fetched via Serial.print(battery_cell_deviation_mV); Serial.println("mV."); - print_int_with_units("High Voltage Output Pins: ", battery_high_voltage, "V"); + print_int_with_units("High Voltage Output Pins: ", battery_dcdcHvBusVolt, "V"); Serial.print(", "); - print_int_with_units("Low Voltage: ", battery_low_voltage, "V"); + print_int_with_units("Low Voltage: ", battery_dcdcLvBusVolt, "V"); Serial.println(""); - print_int_with_units("DC/DC 12V current: ", battery_output_current, "A"); + print_int_with_units("DC/DC 12V current: ", battery_dcdcLvOutputCurrent, "A"); Serial.println(""); Serial.println("Values passed to the inverter: "); @@ -420,20 +462,47 @@ void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x352: - //SOC - battery_nominal_full_pack_energy = - (((rx_frame.data.u8[1] & 0x0F) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) - battery_nominal_energy_remaining = (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0xF8) >> 3)) * - 0.1; //Example 1247 * 0.1 = 124.7kWh - battery_expected_energy_remaining = (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | - ((rx_frame.data.u8[2] & 0xC0) >> 6)); //Example 622 (62.2kWh) - battery_ideal_energy_remaining = (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0xFE) >> 1)) * - 0.1; //Example 311 * 0.1 = 31.1kWh - battery_energy_to_charge_complete = (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * - 0.1; //Example 147 * 0.1 = 14.7kWh - battery_energy_buffer = - (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x80) >> 7)) * 0.1; //Example 1 * 0.1 = 0 - battery_full_charge_complete = ((rx_frame.data.u8[7] & 0x80) >> 7); + mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X + if (mux == 3) { + battery_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); + (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) + battery_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); + (((rx_frame.data.u8[2] & 0x3F) << 5) | + ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh + battery_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); + (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | + ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) + battery_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); + (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh + battery_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); + (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh + battery_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); + (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 + battery_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); + ((rx_frame.data.u8[7] & 0x01) >> 7); + } + if (mux == 0) { + battery_nominal_full_pack_energy = + (rx_frame.data.u8[3] | + rx_frame.data.u8[2]); //SG_ BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X + battery_nominal_energy_remaining = + (rx_frame.data.u8[5] | + rx_frame.data.u8[4]); //SG_ BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X + battery_ideal_energy_remaining = + (rx_frame.data.u8[7] | + rx_frame.data.u8[6]); //SG_ BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X + } + if (mux == 1) { + battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //SG_ BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X + battery_energy_buffer = + (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //SG_ BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X + battery_expected_energy_remaining = + (rx_frame.data.u8[5] | + rx_frame.data.u8[4]); //SG_ BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X + battery_energy_to_charge_complete = + (rx_frame.data.u8[7] | + rx_frame.data.u8[6]); //SG_ BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + } break; case 0x20A: //Contactor state @@ -471,11 +540,9 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x3D2: // total charge/discharge kwh battery_total_discharge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | - (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * - 0.001; + (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); battery_total_charge = ((rx_frame.data.u8[7] << 24) | (rx_frame.data.u8[6] << 16) | (rx_frame.data.u8[5] << 8) | - rx_frame.data.u8[4]) * - 0.001; + rx_frame.data.u8[4]); break; case 0x332: //min/max hist values @@ -531,28 +598,41 @@ void receive_can_battery(CAN_frame rx_frame) { } break; case 0x2d2: - //Min / max limits - battery_bms_min_voltage = - ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.01 * 2; //Example 24148mv * 0.01 = 241.48 V - battery_bms_max_voltage = - ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * 0.01 * 2; //Example 40282mv * 0.01 = 402.82 V + //Min / max limits //BMSVAlimits: //move factoring to datalayer? + battery_bms_min_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); //Example 24148mv * 0.01 = 241.48 V + battery_bms_max_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //Example 40282mv * 0.01 = 402.82 V battery_max_charge_current = - (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]) * 0.1; //Example 1301? * 0.1 = 130.1? + (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]); //Example 1301? * 0.1 = 130.1? battery_max_discharge_current = - (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]) * 0.128; //Example 430? * 0.128 = 55.4? + (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]); //Example 430? * 0.128 = 55.4? break; - case 0x2b4: - battery_low_voltage = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]) * 0.0390625; - battery_high_voltage = ((((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2))) * 0.146484; - battery_output_current = (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]) / 100; + case 0x2b4: //PCS_dcdcRailStatus: + battery_dcdcLvBusVolt = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); //update name move factoring + battery_dcdcHvBusVolt = + ((((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2))); //update name move factoring + battery_dcdcLvOutputCurrent = + (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]); //update name move factoring break; - case 0x292: + case 0x292: //BMS_socStatus datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //We are getting CAN messages from the BMS battery_beginning_of_life = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]); battery_soc_min = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); - battery_soc_vi = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); + battery_soc_ui = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); battery_soc_max = (((rx_frame.data.u8[3] & 0x3F) << 4) | ((rx_frame.data.u8[2] & 0xF0) >> 4)); battery_soc_ave = ((rx_frame.data.u8[4] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6)); + battery_battTempPct = ((rx_frame.data.u8[7] & 0x03) << 6) | (rx_frame.data.u8[6] & (0x3F) >> 2); + break; + case 0x392: //BMS_packConfig + mux = (rx_frame.data.u8[0] & (0xFF)); + if (mux == 1) { + battery_packConfigMultiplexer = (rx_frame.data.u8[0] & (0xff)); + battery_moduleType = (rx_frame.data.u8[1] & (0x07)); + battery_packMass = (rx_frame.data.u8[2]); + battery_platformMaxBusVoltage = ((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3]); + } + if (mux == 0) { + battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); + } break; case 0x3aa: //HVP_alertMatrix1 battery_WatchdogReset = (rx_frame.data.u8[0] & 0x01); @@ -620,20 +700,47 @@ void receive_can_battery2(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x352: - //SOC - battery2_nominal_full_pack_energy = - (((rx_frame.data.u8[1] & 0x0F) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) - battery2_nominal_energy_remaining = (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0xF8) >> 3)) * - 0.1; //Example 1247 * 0.1 = 124.7kWh - battery2_expected_energy_remaining = (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | - ((rx_frame.data.u8[2] & 0xC0) >> 6)); //Example 622 (62.2kWh) - battery2_ideal_energy_remaining = (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0xFE) >> 1)) * - 0.1; //Example 311 * 0.1 = 31.1kWh - battery2_energy_to_charge_complete = (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * - 0.1; //Example 147 * 0.1 = 14.7kWh - battery2_energy_buffer = - (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x80) >> 7)) * 0.1; //Example 1 * 0.1 = 0 - battery2_full_charge_complete = ((rx_frame.data.u8[7] & 0x80) >> 7); + mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X + if (mux == 3) { + battery2_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); + (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) + battery2_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); + (((rx_frame.data.u8[2] & 0x3F) << 5) | + ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh + battery2_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); + (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | + ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) + battery2_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); + (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh + battery2_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); + (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh + battery2_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); + (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 + battery2_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); + ((rx_frame.data.u8[7] & 0x01) >> 7); + } + if (mux == 0) { + battery2_nominal_full_pack_energy = + (rx_frame.data.u8[3] | + rx_frame.data.u8[2]); //SG_ BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X + battery2_nominal_energy_remaining = + (rx_frame.data.u8[5] | + rx_frame.data.u8[4]); //SG_ BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X + battery2_ideal_energy_remaining = + (rx_frame.data.u8[7] | + rx_frame.data.u8[6]); //SG_ BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X + } + if (mux == 1) { + battery2_fully_charged = (rx_frame.data.u8[1] & 0x01); //SG_ BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X + battery2_energy_buffer = + (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //SG_ BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X + battery2_expected_energy_remaining = + (rx_frame.data.u8[5] | + rx_frame.data.u8[4]); //SG_ BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X + battery2_energy_to_charge_complete = + (rx_frame.data.u8[7] | + rx_frame.data.u8[6]); //SG_ BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + } break; case 0x20A: //Contactor state @@ -671,11 +778,9 @@ void receive_can_battery2(CAN_frame rx_frame) { case 0x3D2: // total charge/discharge kwh battery2_total_discharge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | - (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * - 0.001; + (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); battery2_total_charge = ((rx_frame.data.u8[7] << 24) | (rx_frame.data.u8[6] << 16) | (rx_frame.data.u8[5] << 8) | - rx_frame.data.u8[4]) * - 0.001; + rx_frame.data.u8[4]); break; case 0x332: //min/max hist values @@ -730,29 +835,42 @@ void receive_can_battery2(CAN_frame rx_frame) { } } break; - case 0x2d2: + case 0x2d2: //BMSVAlimits: //Min / max limits battery2_bms_min_voltage = - ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.01 * 2; //Example 24148mv * 0.01 = 241.48 V + ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); //Example 24148mv * 0.01 = 241.48 V battery2_bms_max_voltage = - ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * 0.01 * 2; //Example 40282mv * 0.01 = 402.82 V + ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //Example 40282mv * 0.01 = 402.82 V battery2_max_charge_current = - (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]) * 0.1; //Example 1301? * 0.1 = 130.1? + (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]); //Example 1301? * 0.1 = 130.1? battery2_max_discharge_current = - (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]) * 0.128; //Example 430? * 0.128 = 55.4? + (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]); //Example 430? * 0.128 = 55.4? break; - case 0x2b4: - battery2_low_voltage = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]) * 0.0390625; - battery2_high_voltage = ((((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2))) * 0.146484; - battery2_output_current = (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]) / 100; + case 0x2b4: //PCS_dcdcRailStatus: + battery2_dcdcLvBusVolt = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); + battery2_dcdcHvBusVolt = ((((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2))); + battery2_dcdcLvOutputCurrent = (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]); break; - case 0x292: + case 0x292: //BMS_socStatus datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //We are getting CAN messages from the BMS battery2_beginning_of_life = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]); battery2_soc_min = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); - battery2_soc_vi = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); + battery2_soc_ui = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); battery2_soc_max = (((rx_frame.data.u8[3] & 0x3F) << 4) | ((rx_frame.data.u8[2] & 0xF0) >> 4)); battery2_soc_ave = ((rx_frame.data.u8[4] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6)); + battery2_battTempPct = ((rx_frame.data.u8[7] & 0x03) << 6) | (rx_frame.data.u8[6] & (0x3F) >> 2); + break; + case 0x392: //BMS_packConfig + mux = (rx_frame.data.u8[0] & (0xFF)); + if (mux == 1) { + battery2_packConfigMultiplexer = (rx_frame.data.u8[0] & (0xff)); + battery2_moduleType = (rx_frame.data.u8[1] & (0x07)); + battery2_packMass = (rx_frame.data.u8[2]); + battery2_platformMaxBusVoltage = ((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3]); + } + if (mux == 0) { + battery2_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); + } break; case 0x3aa: //HVP_alertMatrix1 battery2_WatchdogReset = (rx_frame.data.u8[0] & 0x01); @@ -817,7 +935,7 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.soh_pptt = 9900; //Tesla batteries do not send a SOH% value on bus. Hardcode to 99% - datalayer.battery2.status.real_soc = (battery2_soc_vi * 10); //increase SOC range from 0-100.0 -> 100.00 + datalayer.battery2.status.real_soc = (battery2_soc_ui * 10); //increase SOC range from 0-100.0 -> 100.00 datalayer.battery2.status.voltage_dV = (battery2_volts * 10); //One more decimal needed (370 -> 3700) @@ -835,12 +953,12 @@ void update_values_battery2() { //This function maps all the values fetched via } //The allowed charge power behaves strangely. We instead estimate this value - if (battery2_soc_vi > 990) { + if (battery2_soc_ui > 990) { datalayer.battery2.status.max_charge_power_W = FLOAT_MAX_POWER_W; - } else if (battery2_soc_vi > + } else if (battery2_soc_ui > RAMPDOWN_SOC) { // When real SOC is between RAMPDOWN_SOC-99%, ramp the value between Max<->0 datalayer.battery2.status.max_charge_power_W = - MAXCHARGEPOWERALLOWED * (1 - (battery2_soc_vi - RAMPDOWN_SOC) / (1000.0 - RAMPDOWN_SOC)); + MAXCHARGEPOWERALLOWED * (1 - (battery2_soc_ui - RAMPDOWN_SOC) / (1000.0 - RAMPDOWN_SOC)); //If the cellvoltages start to reach overvoltage, only allow a small amount of power in if (datalayer.battery2.info.chemistry == battery_chemistry_enum::LFP) { if (battery2_cell_max_v > (MAX_CELL_VOLTAGE_LFP - FLOAT_START_MV)) { @@ -919,7 +1037,7 @@ void update_values_battery2() { //This function maps all the values fetched via Serial.print("Battery2 values: "); Serial.print("Real SOC: "); - Serial.print(battery2_soc_vi / 10.0, 1); + Serial.print(battery2_soc_ui / 10.0, 1); print_int_with_units(", Battery2 voltage: ", battery2_volts, "V"); print_int_with_units(", Battery2 HV current: ", (battery2_amps * 0.1), "A"); Serial.print(", Fully charged?: "); @@ -943,11 +1061,11 @@ void update_values_battery2() { //This function maps all the values fetched via Serial.print(battery2_cell_deviation_mV); Serial.println("mV."); - print_int_with_units("High Voltage Output Pins: ", battery2_high_voltage, "V"); + print_int_with_units("High Voltage Output Pins: ", battery2_dcdcHvBusVolt, "V"); Serial.print(", "); - print_int_with_units("Low Voltage: ", battery2_low_voltage, "V"); + print_int_with_units("Low Voltage: ", battery2_dcdcLvBusVolt, "V"); Serial.println(""); - print_int_with_units("DC/DC 12V current: ", battery2_output_current, "A"); + print_int_with_units("DC/DC 12V current: ", battery2_dcdcLvOutputCurrent, "A"); Serial.println(""); Serial.println("Values passed to the inverter: "); diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 5370637c2..f80c143e0 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -177,7 +177,33 @@ typedef struct { /** uint8_t */ /** Pyro test in progress */ uint8_t pyroTestInProgress = 0; - + uint8_t battery_beginning_of_life = 0; + uint8_t battery_battTempPct = 0; + uint16_t battery_dcdcLvBusVolt = 0; + uint16_t battery_dcdcHvBusVolt = 0; + uint16_t battery_dcdcLvOutputCurrent = 0; + uint16_t battery_nominal_full_pack_energy = 0; + uint16_t battery_nominal_energy_remaining = 0; + uint16_t battery_ideal_energy_remaining = 0; + uint16_t battery_energy_to_charge_complete = 0; + uint16_t battery_energy_buffer = 0; + uint16_t battery_full_charge_complete = 0; + uint8_t battery_fully_charged = 0; + uint16_t battery_total_discharge = 0; + uint16_t battery_total_charge = 0; + uint16_t battery_packConfigMultiplexer = 0; + uint16_t battery_moduleType = 0; + uint16_t battery_reservedConfig = 0; + uint32_t battery_packMass = 0; + uint32_t battery_platformMaxBusVoltage = 0; + uint32_t battery_bms_min_voltage = 0; + uint32_t battery_bms_max_voltage = 0; + uint32_t battery_max_charge_current = 0; + uint32_t battery_max_discharge_current = 0; + uint32_t battery_soc_min = 0; + uint32_t battery_soc_max = 0; + uint32_t battery_soc_ave = 0; + uint32_t battery_soc_ui = 0; } DATALAYER_INFO_TESLA; typedef struct { diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 2a301a07d..c26b6aeb5 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -283,6 +283,59 @@ String advanced_battery_processor(const String& var) { #endif //BYD_ATTO_3_BATTERY #ifdef TESLA_BATTERY + float beginning_of_life = static_cast(datalayer_extended.tesla.battery_beginning_of_life) * 0.1; + content += "

Battery Beginning of Life: " + String(beginning_of_life) + " kWh

"; + float battTempPct = static_cast(datalayer_extended.tesla.battery_battTempPct) * 0.4; + content += "

BattTempPct: " + String(battTempPct) + "

"; + float dcdcLvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcLvBusVolt) * 0.0390625; + content += "

PCS Lv Bus: " + String(dcdcLvBusVolt) + " V

"; + float dcdcHvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcHvBusVolt) * 0.146484; + content += "

PCS Hv Bus: " + String(dcdcHvBusVolt) + " V

"; + float dcdcLvOutputCurrent = static_cast(datalayer_extended.tesla.battery_dcdcLvOutputCurrent) * 0.1; + content += "

PCS Lv Output: " + String(dcdcLvOutputCurrent) + " A

"; + float nominal_full_pack_energy = + static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy) * 0.1; + content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " kWh

"; + float nominal_energy_remaining = + static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining) * 0.1; + content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " kWh

"; + float ideal_energy_remaining = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining) * 0.1; + content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " kWh

"; + float energy_to_charge_complete = + static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete) * 0.1; + content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " kWh

"; + float energy_buffer = static_cast(datalayer_extended.tesla.battery_energy_buffer) * 0.1; + content += "

Energy Buffer: " + String(energy_buffer) + " kWh

"; + content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; + content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; + content += "

reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "

"; + content += "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + + "

"; // no float needed + float total_discharge = static_cast(datalayer_extended.tesla.battery_total_discharge) * 0.001; + content += "

Total Discharge: " + String(total_discharge) + " kWh

"; + float total_charge = static_cast(datalayer_extended.tesla.battery_total_charge) * 0.001; + content += "

Total Charge: " + String(total_charge) + " kWh

"; + float packMass = static_cast(datalayer_extended.tesla.battery_packMass) + 300; + content += "

Battery Pack Mass: " + String(packMass) + " KG

"; + float platformMaxBusVoltage = + static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage) * 0.1 + 375; + content += "

Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V

"; + float bms_min_voltage = static_cast(datalayer_extended.tesla.battery_bms_min_voltage) * 0.01 * 2; + content += "

BMS Min Voltage: " + String(bms_min_voltage) + " V

"; + float bms_max_voltage = static_cast(datalayer_extended.tesla.battery_bms_max_voltage) * 0.01 * 2; + content += "

BMS Max Voltage: " + String(bms_max_voltage) + " V

"; + float max_charge_current = static_cast(datalayer_extended.tesla.battery_max_charge_current) * 0.1; + content += "

Max Charge Current: " + String(max_charge_current) + " A

"; + float max_discharge_current = static_cast(datalayer_extended.tesla.battery_max_discharge_current) * 0.128; + content += "

Max Discharge Current: " + String(max_discharge_current) + " A

"; + float soc_ave = static_cast(datalayer_extended.tesla.battery_soc_ave) * 0.1; + content += "

Battery SOC Ave: " + String(soc_ave) + "

"; + float soc_max = static_cast(datalayer_extended.tesla.battery_soc_max) * 0.1; + content += "

Battery SOC Max: " + String(soc_max) + "

"; + float soc_min = static_cast(datalayer_extended.tesla.battery_soc_min) * 0.1; + content += "

Battery SOC Min: " + String(soc_min) + "

"; + float soc_ui = static_cast(datalayer_extended.tesla.battery_soc_ui) * 0.1; + content += "

Battery SOC UI: " + String(soc_ui) + "

"; static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"}; From 992defca33fca54253df3745f2de902ecc26e97b Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Tue, 19 Nov 2024 22:40:57 +1300 Subject: [PATCH 007/225] Factor correction Change factoring back to battery .cpp Add DBC info for reference --- Software/src/battery/TESLA-BATTERY.cpp | 232 ++++++++++-------- .../webserver/advanced_battery_html.cpp | 48 ++-- 2 files changed, 158 insertions(+), 122 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index c914fc89f..16e795594 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -463,90 +463,107 @@ void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x352: mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X - if (mux == 3) { - battery_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); - (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) - battery_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); - (((rx_frame.data.u8[2] & 0x3F) << 5) | - ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh - battery_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); - (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | - ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) - battery_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); - (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh - battery_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); - (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh - battery_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); - (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 - battery_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); - ((rx_frame.data.u8[7] & 0x01) >> 7); - } + + battery_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); + (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])) * 0.1; //Example 752 (75.2kWh) + battery_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); + (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)) * + 0.1; //Example 1247 * 0.1 = 124.7kWh + battery_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); + (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | ((rx_frame.data.u8[2] & 0x03) >> 6)) * + 0.1; //Example 622 (62.2kWh) + battery_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); + (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)) * + 0.1; //Example 311 * 0.1 = 31.1kWh + battery_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); + (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)) * + 0.1; //Example 147 * 0.1 = 14.7kWh + battery_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); + (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)) * 0.1; //Example 1 * 0.1 = 0 + battery_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); + ((rx_frame.data.u8[7] & 0x01) >> 7); + if (mux == 0) { - battery_nominal_full_pack_energy = - (rx_frame.data.u8[3] | - rx_frame.data.u8[2]); //SG_ BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X - battery_nominal_energy_remaining = - (rx_frame.data.u8[5] | - rx_frame.data.u8[4]); //SG_ BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X - battery_ideal_energy_remaining = - (rx_frame.data.u8[7] | - rx_frame.data.u8[6]); //SG_ BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X + battery_nominal_full_pack_energy = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * + 0.02; //BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X + battery_nominal_energy_remaining = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * + 0.02; //BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X + battery_ideal_energy_remaining = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) * + 0.02; //BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X } if (mux == 1) { - battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //SG_ BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X - battery_energy_buffer = - (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //SG_ BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X - battery_expected_energy_remaining = - (rx_frame.data.u8[5] | - rx_frame.data.u8[4]); //SG_ BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X - battery_energy_to_charge_complete = - (rx_frame.data.u8[7] | - rx_frame.data.u8[6]); //SG_ BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X + battery_energy_buffer = (rx_frame.data.u8[3] | rx_frame.data.u8[2]) * + 0.01; //BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X + battery_expected_energy_remaining = (rx_frame.data.u8[5] | rx_frame.data.u8[4]) * + 0.02; //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X + battery_energy_to_charge_complete = (rx_frame.data.u8[7] | rx_frame.data.u8[6]) * + 0.02; //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X } break; - case 0x20A: - //Contactor state - battery_packContNegativeState = (rx_frame.data.u8[0] & 0x07); - battery_packContPositiveState = (rx_frame.data.u8[0] & 0x38) >> 3; - battery_contactor = (rx_frame.data.u8[1] & 0x0F); - battery_packContactorSetState = (rx_frame.data.u8[1] & 0x0F); - battery_packCtrsClosingAllowed = (rx_frame.data.u8[4] & 0x08) >> 3; - battery_pyroTestInProgress = (rx_frame.data.u8[4] & 0x20) >> 5; - battery_hvil_status = (rx_frame.data.u8[5] & 0x0F); + case 0x20A: //Contactor state //HVP_contactorState: + battery_packContNegativeState = (rx_frame.data.u8[0] & 0x07); //0|3@1+ (1,0) [0|7] "" + battery_packContPositiveState = (rx_frame.data.u8[0] & 0x38) >> 3; //3|3@1+ (1,0) [0|7] "" + battery_contactor = (rx_frame.data.u8[1] & 0x0F); //HVP_packContactorSetState : 8|4@1+ (1,0) [0|9] "" + battery_packContactorSetState = (rx_frame.data.u8[1] & 0x0F); //HVP_packContactorSetState : 8|4@1+ (1,0) [0|9] "" + battery_packCtrsClosingAllowed = (rx_frame.data.u8[4] & 0x08) >> 3; //35|1@1+ (1,0) [0|1] "" + battery_pyroTestInProgress = (rx_frame.data.u8[4] & 0x20) >> 5; //37|1@1+ (1,0) [0|1] "" + battery_hvil_status = (rx_frame.data.u8[5] & 0x0F); //40|4@1+ (1,0) [0|9] "" + //HVP_packCtrsOpenNowRequested : 33|1@1+ (1,0) [0|1] "" + //HVP_packCtrsOpenRequested : 34|1@1+ (1,0) [0|1] "" + //HVP_packCtrsRequestStatus : 30|2@1+ (1,0) [0|2] "" + //HVP_packCtrsResetRequestRequired : 32|1@1+ (1,0) [0|1] "" + //HVP_dcLinkAllowedToEnergize : 36|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcContNegativeAuxOpen : 7|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcContNegativeState : 12|3@1+ (1,0) [0|7] "" Receiver + //HVP_fcContPositiveAuxOpen : 6|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcContPositiveState : 16|3@1+ (1,0) [0|7] "" Receiver + //HVP_fcContactorSetState : 19|4@1+ (1,0) [0|9] "" Receiver + //HVP_fcCtrsClosingAllowed : 29|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcCtrsOpenNowRequested : 27|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcCtrsOpenRequested : 28|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcCtrsRequestStatus : 24|2@1+ (1,0) [0|2] "" Receiver + //HVP_fcCtrsResetRequestRequired : 26|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcLinkAllowedToEnergize : 44|2@1+ (1,0) [0|2] "" Receiver break; - case 0x252: - //Limits - battery_regenerative_limit = - ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.01; //Example 4715 * 0.01 = 47.15kW - battery_discharge_limit = - ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * 0.013; //Example 2009 * 0.013 = 26.117??? - battery_max_heat_park = - (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]) * 0.01; //Example 500 * 0.01 = 5kW - battery_hvac_max_power = - (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))) * 0.02; //Example 1000 * 0.02 = 20kW? + case 0x252: //Limit //BMS_powerAvailable252: + battery_regenerative_limit = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * + 0.01; //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW + battery_discharge_limit = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * + 0.013; //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? + battery_max_heat_park = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]) * + 0.01; //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW + battery_hvac_max_power = (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))) * + 0.02; //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? + //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver + //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] "" Receiver break; - case 0x132: - //battery amps/volts - battery_volts = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.01; //Example 37030mv * 0.01 = 370V - battery_amps = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //Example 65492 (-4.3A) OR 225 (22.5A) - battery_raw_amps = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * -0.05; //Example 10425 * -0.05 = ? + case 0x132: //battery amps/volts //HVBattAmpVolt + battery_volts = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * + 0.01; //0|16@1+ (0.01,0) [0|655.35] "V" //Example 37030mv * 0.01 = 370V + battery_amps = + ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * + -0.1; //SmoothBattCurrent : 16|16@1- (-0.1,0) [-3276.7|3276.7] "A" //Example 65492 (-4.3A) OR 225 (22.5A) + battery_raw_amps = + ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * -0.05 + + 822; //RawBattCurrent : 32|16@1- (-0.05,822) [-1138.35|2138.4] "A" //Example 10425 * -0.05 = ? battery_charge_time_remaining = - (((rx_frame.data.u8[7] & 0x0F) << 8) | rx_frame.data.u8[6]) * 0.1; //Example 228 * 0.1 = 22.8min + (((rx_frame.data.u8[7] & 0x0F) << 8) | + rx_frame.data.u8[6]); //ChargeHoursRemaining : 48|12@1+ (1,0) [0|4095] "Min" //Example 228 * 0.1 = 22.8min if (battery_charge_time_remaining == 4095) { battery_charge_time_remaining = 0; } - break; - case 0x3D2: - // total charge/discharge kwh + case 0x3D2: //TotalChargeDischarge: battery_total_discharge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | - (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * + 0.001; //0|32@1+ (0.001,0) [0|4294970] "kWh" battery_total_charge = ((rx_frame.data.u8[7] << 24) | (rx_frame.data.u8[6] << 16) | (rx_frame.data.u8[5] << 8) | - rx_frame.data.u8[4]); + rx_frame.data.u8[4]) * + 0.001; //32|32@1+ (0.001,0) [0|4294970] "kWh" break; - case 0x332: - //min/max hist values - mux = (rx_frame.data.u8[0] & 0x03); + case 0x332: //min/max hist values //BattBrickMinMax: + mux = (rx_frame.data.u8[0] & 0x03); //BattBrickMultiplexer M : 0|2@1+ (1,0) [0|0] "" if (mux == 1) //Cell voltages { @@ -565,10 +582,24 @@ void receive_can_battery(CAN_frame rx_frame) { battery_min_temp = (rx_frame.data.u8[3] * 5) - 400; //Multiply by 5 and remove offset to get C+1 (0x61*5=485-400=8.5*C) } + //BattBrickMultiplexer M : 0|2@1+ (1,0) [0|0] "" Receiver + //BattBrickTempMaxNum m0 : 2|4@1+ (1,0) [0|0] "" Receiver + //BattBrickTempMinNum m0 : 8|4@1+ (1,0) [0|0] "" Receiver + //BattBrickTempMax m0 : 16|8@1+ (0.5,-40) [0|0] "C" Receiver + //BattBrickTempMin m0 : 24|8@1+ (0.5,-40) [0|0] "C" Receiver + //BattBrickModelTMax m0 : 32|8@1+ (0.5,-40) [0|0] "C" Receiver + //BattBrickModelTMin m0 : 40|8@1+ (0.5,-40) [0|0] "C" Receiver + //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver + //BattBrickVoltageMin m1 : 16|12@1+ (0.002,0) [0|0] "V" Receiver + //BattBrickVoltageMaxNum m1 : 32|7@1+ (1,1) [0|0] "" Receiver + //BattBrickVoltageMinNum m1 : 40|7@1+ (1,1) [0|0] "" Receiver break; - case 0x401: // Cell stats - mux = (rx_frame.data.u8[0]); - + case 0x401: // Cell stats //BrickVoltages + mux = (rx_frame.data.u8[0]); //MultiplexSelector M : 0|8@1+ (1,0) [0|0] "" + //StatusFlags : 8|8@1+ (1,0) [0|0] "" + //Brick0 m0 : 16|16@1+ (0.0001,0) [0|0] "V" + //Brick1 m0 : 32|16@1+ (0.0001,0) [0|0] "V" + //Brick2 m0 : 48|16@1+ (0.0001,0) [0|0] "V" static uint16_t volts; static uint8_t mux_zero_counter = 0u; static uint8_t mux_max = 0u; @@ -597,41 +628,50 @@ void receive_can_battery(CAN_frame rx_frame) { } } break; - case 0x2d2: - //Min / max limits //BMSVAlimits: //move factoring to datalayer? - battery_bms_min_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); //Example 24148mv * 0.01 = 241.48 V - battery_bms_max_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //Example 40282mv * 0.01 = 402.82 V - battery_max_charge_current = - (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]); //Example 1301? * 0.1 = 130.1? - battery_max_discharge_current = - (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]); //Example 430? * 0.128 = 55.4? + case 0x2d2: //BMSVAlimits: + battery_bms_min_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * + 0.1; //0|16@1+ (0.01,0) [0|430] "V" //Example 24148mv * 0.01 = 241.48 V + battery_bms_max_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * + 0.1; //16|16@1+ (0.01,0) [0|430] "V" //Example 40282mv * 0.01 = 402.82 V + battery_max_charge_current = (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]) * + 0.1; //32|14@1+ (0.1,0) [0|1638.2] "A" //Example 1301? * 0.1 = 130.1? + battery_max_discharge_current = (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]) * + 0.128; //48|14@1+ (0.128,0) [0|2096.9] "A" //Example 430? * 0.128 = 55.4? break; - case 0x2b4: //PCS_dcdcRailStatus: - battery_dcdcLvBusVolt = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); //update name move factoring - battery_dcdcHvBusVolt = - ((((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2))); //update name move factoring + case 0x2b4: //PCS_dcdcRailStatus: + battery_dcdcLvBusVolt = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]) * + 0.0390625; //0|10@1+ (0.0390625,0) [0|39.9609] "V" + battery_dcdcHvBusVolt = ((((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2))) * + 0.146484; //10|12@1+ (0.146484,0) [0|599.854] "V" battery_dcdcLvOutputCurrent = - (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]); //update name move factoring + (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]) * 0.1; //24|12@1+ (0.1,0) [0|400] "A" break; case 0x292: //BMS_socStatus datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //We are getting CAN messages from the BMS - battery_beginning_of_life = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]); - battery_soc_min = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); - battery_soc_ui = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); - battery_soc_max = (((rx_frame.data.u8[3] & 0x3F) << 4) | ((rx_frame.data.u8[2] & 0xF0) >> 4)); - battery_soc_ave = ((rx_frame.data.u8[4] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6)); - battery_battTempPct = ((rx_frame.data.u8[7] & 0x03) << 6) | (rx_frame.data.u8[6] & (0x3F) >> 2); + battery_beginning_of_life = + (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]) * 0.1; //40|10@1+ (0.1,0) [0|102.3] "kWh" + battery_soc_min = + (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]) * 0.1; //0|10@1+ (0.1,0) [0|102.3] "%" + battery_soc_ui = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)) * + 0.1; //10|10@1+ (0.1,0) [0|102.3] "%" + battery_soc_max = (((rx_frame.data.u8[3] & 0x3F) << 4) | ((rx_frame.data.u8[2] & 0xF0) >> 4)) * + 0.1; //20|10@1+ (0.1,0) [0|102.3] "%" + battery_soc_ave = + ((rx_frame.data.u8[4] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6)) * 0.1; //30|10@1+ (0.1,0) [0|102.3] "%" + battery_battTempPct = ((rx_frame.data.u8[7] & 0x03) << 6) | + (rx_frame.data.u8[6] & (0x3F) >> 2) * 0.4; //50|8@1+ (0.4,0) [0|100] "%" break; case 0x392: //BMS_packConfig mux = (rx_frame.data.u8[0] & (0xFF)); if (mux == 1) { - battery_packConfigMultiplexer = (rx_frame.data.u8[0] & (0xff)); - battery_moduleType = (rx_frame.data.u8[1] & (0x07)); - battery_packMass = (rx_frame.data.u8[2]); - battery_platformMaxBusVoltage = ((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3]); + battery_packConfigMultiplexer = (rx_frame.data.u8[0] & (0xff)); //0|8@1+ (1,0) [0|1] "" + battery_moduleType = (rx_frame.data.u8[1] & (0x07)); //8|3@1+ (1,0) [0|4] "" + battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg" + battery_platformMaxBusVoltage = + ((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3]) * 0.1 + 375; //24|10@1+ (0.1,375) [0|0] "V" } if (mux == 0) { - battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); + battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); //8|5@1+ (1,0) [0|31] "" } break; case 0x3aa: //HVP_alertMatrix1 diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 2cd7917c9..1efa3530f 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -285,58 +285,54 @@ String advanced_battery_processor(const String& var) { #endif //BYD_ATTO_3_BATTERY #ifdef TESLA_BATTERY - float beginning_of_life = static_cast(datalayer_extended.tesla.battery_beginning_of_life) * 0.1; + float beginning_of_life = static_cast(datalayer_extended.tesla.battery_beginning_of_life); content += "

Battery Beginning of Life: " + String(beginning_of_life) + " kWh

"; - float battTempPct = static_cast(datalayer_extended.tesla.battery_battTempPct) * 0.4; + float battTempPct = static_cast(datalayer_extended.tesla.battery_battTempPct); content += "

BattTempPct: " + String(battTempPct) + "

"; - float dcdcLvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcLvBusVolt) * 0.0390625; + float dcdcLvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcLvBusVolt); content += "

PCS Lv Bus: " + String(dcdcLvBusVolt) + " V

"; - float dcdcHvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcHvBusVolt) * 0.146484; + float dcdcHvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcHvBusVolt); content += "

PCS Hv Bus: " + String(dcdcHvBusVolt) + " V

"; - float dcdcLvOutputCurrent = static_cast(datalayer_extended.tesla.battery_dcdcLvOutputCurrent) * 0.1; + float dcdcLvOutputCurrent = static_cast(datalayer_extended.tesla.battery_dcdcLvOutputCurrent); content += "

PCS Lv Output: " + String(dcdcLvOutputCurrent) + " A

"; - float nominal_full_pack_energy = - static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy) * 0.1; + float nominal_full_pack_energy = static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy); content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " kWh

"; - float nominal_energy_remaining = - static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining) * 0.1; + float nominal_energy_remaining = static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining); content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " kWh

"; - float ideal_energy_remaining = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining) * 0.1; + float ideal_energy_remaining = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining); content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " kWh

"; - float energy_to_charge_complete = - static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete) * 0.1; + float energy_to_charge_complete = static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete); content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " kWh

"; - float energy_buffer = static_cast(datalayer_extended.tesla.battery_energy_buffer) * 0.1; + float energy_buffer = static_cast(datalayer_extended.tesla.battery_energy_buffer); content += "

Energy Buffer: " + String(energy_buffer) + " kWh

"; content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; content += "

reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "

"; content += "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "

"; // no float needed - float total_discharge = static_cast(datalayer_extended.tesla.battery_total_discharge) * 0.001; + float total_discharge = static_cast(datalayer_extended.tesla.battery_total_discharge); content += "

Total Discharge: " + String(total_discharge) + " kWh

"; - float total_charge = static_cast(datalayer_extended.tesla.battery_total_charge) * 0.001; + float total_charge = static_cast(datalayer_extended.tesla.battery_total_charge); content += "

Total Charge: " + String(total_charge) + " kWh

"; - float packMass = static_cast(datalayer_extended.tesla.battery_packMass) + 300; + float packMass = static_cast(datalayer_extended.tesla.battery_packMass); content += "

Battery Pack Mass: " + String(packMass) + " KG

"; - float platformMaxBusVoltage = - static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage) * 0.1 + 375; + float platformMaxBusVoltage = static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage); content += "

Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V

"; - float bms_min_voltage = static_cast(datalayer_extended.tesla.battery_bms_min_voltage) * 0.01 * 2; + float bms_min_voltage = static_cast(datalayer_extended.tesla.battery_bms_min_voltage); content += "

BMS Min Voltage: " + String(bms_min_voltage) + " V

"; - float bms_max_voltage = static_cast(datalayer_extended.tesla.battery_bms_max_voltage) * 0.01 * 2; + float bms_max_voltage = static_cast(datalayer_extended.tesla.battery_bms_max_voltage); content += "

BMS Max Voltage: " + String(bms_max_voltage) + " V

"; - float max_charge_current = static_cast(datalayer_extended.tesla.battery_max_charge_current) * 0.1; + float max_charge_current = static_cast(datalayer_extended.tesla.battery_max_charge_current); content += "

Max Charge Current: " + String(max_charge_current) + " A

"; - float max_discharge_current = static_cast(datalayer_extended.tesla.battery_max_discharge_current) * 0.128; + float max_discharge_current = static_cast(datalayer_extended.tesla.battery_max_discharge_current); content += "

Max Discharge Current: " + String(max_discharge_current) + " A

"; - float soc_ave = static_cast(datalayer_extended.tesla.battery_soc_ave) * 0.1; + float soc_ave = static_cast(datalayer_extended.tesla.battery_soc_ave); content += "

Battery SOC Ave: " + String(soc_ave) + "

"; - float soc_max = static_cast(datalayer_extended.tesla.battery_soc_max) * 0.1; + float soc_max = static_cast(datalayer_extended.tesla.battery_soc_max); content += "

Battery SOC Max: " + String(soc_max) + "

"; - float soc_min = static_cast(datalayer_extended.tesla.battery_soc_min) * 0.1; + float soc_min = static_cast(datalayer_extended.tesla.battery_soc_min); content += "

Battery SOC Min: " + String(soc_min) + "

"; - float soc_ui = static_cast(datalayer_extended.tesla.battery_soc_ui) * 0.1; + float soc_ui = static_cast(datalayer_extended.tesla.battery_soc_ui); content += "

Battery SOC UI: " + String(soc_ui) + "

"; static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", From 7249d6d646eeca97058d282b1f3ed1f6a1088998 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 20 Nov 2024 08:35:24 +1300 Subject: [PATCH 008/225] Update TESLA-BATTERY.cpp Fix compile issues, missed a few () --- Software/src/battery/TESLA-BATTERY.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 16e795594..7b1a269f8 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -641,7 +641,7 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x2b4: //PCS_dcdcRailStatus: battery_dcdcLvBusVolt = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]) * 0.0390625; //0|10@1+ (0.0390625,0) [0|39.9609] "V" - battery_dcdcHvBusVolt = ((((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2))) * + battery_dcdcHvBusVolt = (((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)) * 0.146484; //10|12@1+ (0.146484,0) [0|599.854] "V" battery_dcdcLvOutputCurrent = (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]) * 0.1; //24|12@1+ (0.1,0) [0|400] "A" @@ -658,8 +658,8 @@ void receive_can_battery(CAN_frame rx_frame) { 0.1; //20|10@1+ (0.1,0) [0|102.3] "%" battery_soc_ave = ((rx_frame.data.u8[4] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6)) * 0.1; //30|10@1+ (0.1,0) [0|102.3] "%" - battery_battTempPct = ((rx_frame.data.u8[7] & 0x03) << 6) | - (rx_frame.data.u8[6] & (0x3F) >> 2) * 0.4; //50|8@1+ (0.4,0) [0|100] "%" + battery_battTempPct = (((rx_frame.data.u8[7] & 0x03) << 6) | (rx_frame.data.u8[6] & 0x3F) >> 2) * + 0.4; //50|8@1+ (0.4,0) [0|100] "%" break; case 0x392: //BMS_packConfig mux = (rx_frame.data.u8[0] & (0xFF)); @@ -668,7 +668,7 @@ void receive_can_battery(CAN_frame rx_frame) { battery_moduleType = (rx_frame.data.u8[1] & (0x07)); //8|3@1+ (1,0) [0|4] "" battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg" battery_platformMaxBusVoltage = - ((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3]) * 0.1 + 375; //24|10@1+ (0.1,375) [0|0] "V" + (((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3])) * 0.1 + 375; //24|10@1+ (0.1,375) [0|0] "V" } if (mux == 0) { battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); //8|5@1+ (1,0) [0|31] "" From 10a75d7d8da05ec45e0b223c4476344fb194a0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 22 Nov 2024 23:25:33 +0200 Subject: [PATCH 009/225] Add SMA LV protocol --- Software/USER_SETTINGS.h | 1 + Software/src/inverter/INVERTERS.h | 4 + Software/src/inverter/SMA-48V-CAN.cpp | 184 ------------------ Software/src/inverter/SMA-LV-CAN.cpp | 166 ++++++++++++++++ .../inverter/{SMA-48V-CAN.h => SMA-LV-CAN.h} | 4 +- 5 files changed, 173 insertions(+), 186 deletions(-) delete mode 100644 Software/src/inverter/SMA-48V-CAN.cpp create mode 100644 Software/src/inverter/SMA-LV-CAN.cpp rename Software/src/inverter/{SMA-48V-CAN.h => SMA-LV-CAN.h} (82%) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index cbd51f4c2..f7d39463e 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -45,6 +45,7 @@ //#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_CAN //Enable this line to emulate a "BYD Battery-Box H 8.9kWh, 7 mod" 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 diff --git a/Software/src/inverter/INVERTERS.h b/Software/src/inverter/INVERTERS.h index 18089fe8f..83d286b4d 100644 --- a/Software/src/inverter/INVERTERS.h +++ b/Software/src/inverter/INVERTERS.h @@ -39,6 +39,10 @@ #include "SMA-CAN.h" #endif +#ifdef SMA_LV_CAN +#include "SMA-LV-CAN.h" +#endif + #ifdef SMA_TRIPOWER_CAN #include "SMA-TRIPOWER-CAN.h" #endif diff --git a/Software/src/inverter/SMA-48V-CAN.cpp b/Software/src/inverter/SMA-48V-CAN.cpp deleted file mode 100644 index 4c9a37ce8..000000000 --- a/Software/src/inverter/SMA-48V-CAN.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include "../include.h" -#ifdef SMA_CAN -#include "../datalayer/datalayer.h" -#include "SMA-CAN.h" - -/* SMA 48V CAN protocol: -CAN 2.0A -500kBit/sec -11-Bit Identifiers */ - -/* Do not change code below unless you are sure what you are doing */ -static unsigned long previousMillis100ms = 0; - -//Actual content messages -CAN_frame SMA_558 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x558, - .data = {0x03, 0x12, 0x00, 0x04, 0x00, 0x59, 0x07, 0x07}}; //7x BYD modules, Vendor ID 7 BYD -CAN_frame SMA_598 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x598, - .data = {0x00, 0x00, 0x12, 0x34, 0x5A, 0xDE, 0x07, 0x4F}}; //B0-4 Serial, rest unknown -CAN_frame SMA_5D8 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x5D8, - .data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //B Y D -CAN_frame SMA_618_1 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x618, - .data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //0 B A T T E R Y -CAN_frame SMA_618_2 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x618, - .data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x48, 0x39}}; //1 - B O X H -CAN_frame SMA_618_3 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x618, - .data = {0x02, 0x2E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}}; //2 - 0 -CAN_frame SMA_358 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x358, - .data = {0x0F, 0x6C, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_3D8 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x3D8, - .data = {0x04, 0x10, 0x27, 0x10, 0x00, 0x18, 0xF9, 0x00}}; -CAN_frame SMA_458 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x458, - .data = {0x00, 0x00, 0x06, 0x75, 0x00, 0x00, 0x05, 0xD6}}; -CAN_frame SMA_518 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x518, - .data = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}}; -CAN_frame SMA_4D8 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x4D8, - .data = {0x09, 0xFD, 0x00, 0x00, 0x00, 0xA8, 0x02, 0x08}}; -CAN_frame SMA_158 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x158, - .data = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA}}; - -static int16_t temperature_average = 0; -static uint16_t ampere_hours_remaining = 0; - -void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages - //Calculate values - - temperature_average = - ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); - - if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0 - ampere_hours_remaining = - ((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) * - 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) - } - - //Map values to CAN messages - //Battery charge voltage (eg 400.0V = 4000 , 16bits long) - SMA_351.data.u8[0] = ((datalayer.battery.info.max_design_voltage_dV - 20) >> 8); - SMA_351.data.u8[1] = ((datalayer.battery.info.max_design_voltage_dV - 20) & 0x00FF); - //Discharge limited current, 500 = 50A, (0.1, A) - SMA_351.data.u8[2] = (datalayer.battery.status.max_discharge_current_dA >> 8); - SMA_351.data.u8[3] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); - //Charge limited current, 125 =12.5A (0.1, A) - SMA_351.data.u8[4] = (datalayer.battery.status.max_charge_current_dA >> 8); - SMA_351.data.u8[5] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); - //Discharge voltage (eg 300.0V = 3000 , 16bits long) - SMA_351.data.u8[6] = ((datalayer.battery.info.min_design_voltage_dV + 20) >> 8); - SMA_351.data.u8[7] = ((datalayer.battery.info.min_design_voltage_dV + 20) & 0x00FF); - - //SOC (100.00%) - SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); - SMA_3D8.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF); - //StateOfHealth (100.00%) - SMA_3D8.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8); - SMA_3D8.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF); - //State of charge (AH, 0.1) - SMA_3D8.data.u8[4] = (ampere_hours_remaining >> 8); - SMA_3D8.data.u8[5] = (ampere_hours_remaining & 0x00FF); - - //Voltage (370.0) - SMA_4D8.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8); - SMA_4D8.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF); - //Current (TODO: signed OK?) - SMA_4D8.data.u8[2] = (datalayer.battery.status.current_dA >> 8); - SMA_4D8.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF); - //Temperature average - SMA_4D8.data.u8[4] = (temperature_average >> 8); - SMA_4D8.data.u8[5] = (temperature_average & 0x00FF); - //Battery ready - if (datalayer.battery.status.bms_status == ACTIVE) { - SMA_4D8.data.u8[6] = READY_STATE; - } else { - SMA_4D8.data.u8[6] = STOP_STATE; - } -} - -void receive_can_inverter(CAN_frame rx_frame) { - switch (rx_frame.ID) { - case 0x305: - datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - //Frame0-1 Battery Voltage - //Frame2-3 Battery Current - //Frame4-5 Battery Temperature - //Frame6-7 SOC Battery - break; - case 0x306: - datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - //Frame0-1 SOH Battery - //Frame2 Charging procedure - //Frame3 Operating state - //Frame4-5 Active error message - //Frame6-7 Battery charge voltage setpoint - break; - default: - break; - } -} - -void send_can_inverter() { - unsigned long currentMillis = millis(); - - // Send CAN Message every 100ms if Enable line is HIGH - if (datalayer.system.status.inverter_allows_contactor_closing) { - if (currentMillis - previousMillis100ms >= 100) { - previousMillis100ms = currentMillis; - - transmit_can(&SMA_351, can_config.inverter); - transmit_can(&SMA_355, can_config.inverter); - transmit_can(&SMA_356, can_config.inverter); - transmit_can(&SMA_35A, can_config.inverter); - transmit_can(&SMA_35B, can_config.inverter); - transmit_can(&SMA_35E, can_config.inverter); - transmit_can(&SMA_35F, can_config.inverter); - - //Remote quick stop (optional) - if (datalayer.battery.status.bms_status == FAULT) { - transmit_can(&SMA_00F, can_config.inverter); - //After receiving this message, Sunny Island will immediately go into standby. - //Please send start command, to start again. Manual start is also possible. - } - } - } -} - -void setup_inverter(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "SMA 48V CAN", 63); - datalayer.system.info.inverter_protocol[63] = '\0'; -} -#endif diff --git a/Software/src/inverter/SMA-LV-CAN.cpp b/Software/src/inverter/SMA-LV-CAN.cpp new file mode 100644 index 000000000..77d3c429b --- /dev/null +++ b/Software/src/inverter/SMA-LV-CAN.cpp @@ -0,0 +1,166 @@ +#include "../include.h" +#ifdef SMA_LV_CAN +#include "../datalayer/datalayer.h" +#include "SMA-LV-CAN.h" + +/* SMA Sunny Island Low Voltage (48V) CAN protocol: +CAN 2.0A +500kBit/sec +11-Bit Identifiers */ + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis100ms = 0; + +#define VOLTAGE_OFFSET_DV 40 //Offset in deciVolt from max charge voltage and min discharge voltage +#define MAX_VOLTAGE_DV 630 +#define MIN_VOLTAGE_DV 41 + +//Actual content messages +CAN_frame SMA_351 = {.FD = false, // Battery charge voltage, charge/discharge limit, min discharge voltage + .ext_ID = false, + .DLC = 8, + .ID = 0x351, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_355 = {.FD = false, // SOC, SOH, HiResSOC + .ext_ID = false, + .DLC = 8, + .ID = 0x355, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_356 = {.FD = false, // Battery voltage, current, temperature + .ext_ID = false, + .DLC = 8, + .ID = 0x356, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_35A = {.FD = false, // Alarms & Warnings + .ext_ID = false, + .DLC = 8, + .ID = 0x35A, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_35B = {.FD = false, // Events + .ext_ID = false, + .DLC = 8, + .ID = 0x35B, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_35E = {.FD = false, // Manufacturer ASCII + .ext_ID = false, + .DLC = 8, + .ID = 0x35E, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_35F = {.FD = false, // Battery Type, version, capacity, ID + .ext_ID = false, + .DLC = 8, + .ID = 0x35F, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_00F = {.FD = false, // Emergency stop message + .ext_ID = false, + .DLC = 8, //Documentation unclear, should message even have any content? + .ID = 0x00F, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +static int16_t temperature_average = 0; + +void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages + //Calculate values + + temperature_average = + ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); + + //Map values to CAN messages + //Battery charge voltage (eg 400.0V = 4000 , 16bits long) (MIN 41V, MAX 63V, default 54V) + SMA_351.data.u8[0] = ((datalayer.battery.info.max_design_voltage_dV - VOLTAGE_OFFSET_DV) >> 8); + SMA_351.data.u8[1] = ((datalayer.battery.info.max_design_voltage_dV - VOLTAGE_OFFSET_DV) & 0x00FF); + if (datalayer.battery.info.max_design_voltage_dV > MAX_VOLTAGE_DV) { + //If the battery is designed for more than 63.0V, cap the value + SMA_351.data.u8[0] = (MAX_VOLTAGE_DV >> 8); + SMA_351.data.u8[1] = (MAX_VOLTAGE_DV & 0x00FF); + //TODO; raise event? + } + //Discharge limited current, 500 = 50A, (0.1, A) (MIN 0, MAX 1200) + SMA_351.data.u8[2] = (datalayer.battery.status.max_discharge_current_dA >> 8); + SMA_351.data.u8[3] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); + //Charge limited current, 125 =12.5A (0.1, A) (MIN 0, MAX 1200) + SMA_351.data.u8[4] = (datalayer.battery.status.max_charge_current_dA >> 8); + SMA_351.data.u8[5] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); + //Discharge voltage (eg 300.0V = 3000 , 16bits long) (MIN 41V, MAX 48V, default 41V) + SMA_351.data.u8[6] = ((datalayer.battery.info.min_design_voltage_dV + VOLTAGE_OFFSET_DV) >> 8); + SMA_351.data.u8[7] = ((datalayer.battery.info.min_design_voltage_dV + VOLTAGE_OFFSET_DV) & 0x00FF); + if (datalayer.battery.info.min_design_voltage_dV < MIN_VOLTAGE_DV) { + //If the battery is designed for discharge voltage below 41.0V, cap the value + SMA_351.data.u8[6] = (MIN_VOLTAGE_DV >> 8); + SMA_351.data.u8[7] = (MIN_VOLTAGE_DV & 0x00FF); + //TODO; raise event? + } + + //SOC (100%) + SMA_355.data.u8[0] = ((datalayer.battery.status.reported_soc / 100) >> 8); + SMA_355.data.u8[1] = ((datalayer.battery.status.reported_soc / 100) & 0x00FF); + //StateOfHealth (100%) + SMA_355.data.u8[2] = ((datalayer.battery.status.soh_pptt / 100) >> 8); + SMA_355.data.u8[3] = ((datalayer.battery.status.soh_pptt / 100) & 0x00FF); + //State of charge High Precision (100.00%) + SMA_355.data.u8[4] = (datalayer.battery.status.reported_soc >> 8); + SMA_355.data.u8[5] = (datalayer.battery.status.reported_soc & 0x00FF); + + //Voltage (370.0) + SMA_356.data.u8[0] = ((datalayer.battery.status.voltage_dV * 10) >> 8); + SMA_356.data.u8[1] = ((datalayer.battery.status.voltage_dV * 10) & 0x00FF); + //Current (S16 dA) + SMA_356.data.u8[2] = (datalayer.battery.status.current_dA >> 8); + SMA_356.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF); + //Temperature (s16 degC) + SMA_356.data.u8[4] = (temperature_average >> 8); + SMA_356.data.u8[5] = (temperature_average & 0x00FF); + + //TODO: Map error/warnings in 0x35A +} + +void receive_can_inverter(CAN_frame rx_frame) { + switch (rx_frame.ID) { + case 0x305: + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + //Frame0-1 Battery Voltage + //Frame2-3 Battery Current + //Frame4-5 Battery Temperature + //Frame6-7 SOC Battery + break; + case 0x306: + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + //Frame0-1 SOH Battery + //Frame2 Charging procedure + //Frame3 Operating state + //Frame4-5 Active error message + //Frame6-7 Battery charge voltage setpoint + break; + default: + break; + } +} + +void send_can_inverter() { + unsigned long currentMillis = millis(); + + if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) { + previousMillis100ms = currentMillis; + + transmit_can(&SMA_351, can_config.inverter); + transmit_can(&SMA_355, can_config.inverter); + transmit_can(&SMA_356, can_config.inverter); + transmit_can(&SMA_35A, can_config.inverter); + transmit_can(&SMA_35B, can_config.inverter); + transmit_can(&SMA_35E, can_config.inverter); + transmit_can(&SMA_35F, can_config.inverter); + + //Remote quick stop (optional) + if (datalayer.battery.status.bms_status == FAULT) { + transmit_can(&SMA_00F, can_config.inverter); + //After receiving this message, Sunny Island will immediately go into standby. + //Please send start command, to start again. Manual start is also possible. + } + } +} + +void setup_inverter(void) { // Performs one time setup at startup over CAN bus + strncpy(datalayer.system.info.inverter_protocol, "SMA Low Voltage (48V) protocol via CAN", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; +} +#endif diff --git a/Software/src/inverter/SMA-48V-CAN.h b/Software/src/inverter/SMA-LV-CAN.h similarity index 82% rename from Software/src/inverter/SMA-48V-CAN.h rename to Software/src/inverter/SMA-LV-CAN.h index 111044a46..a1c6e7e94 100644 --- a/Software/src/inverter/SMA-48V-CAN.h +++ b/Software/src/inverter/SMA-LV-CAN.h @@ -1,5 +1,5 @@ -#ifndef SMA_CAN_H -#define SMA_CAN_H +#ifndef SMA_LV_CAN_H +#define SMA_LV_CAN_H #include "../include.h" #define CAN_INVERTER_SELECTED From 2338d8c87cad864d58d1cc978b2e544203af9b77 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sat, 23 Nov 2024 17:02:47 +1300 Subject: [PATCH 010/225] added mux for 0x352 and webserver updated --- Software/src/battery/TESLA-BATTERY.cpp | 242 ++++++++++-------- Software/src/datalayer/datalayer_extended.h | 5 + .../webserver/advanced_battery_html.cpp | 81 ++++-- 3 files changed, 194 insertions(+), 134 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 7b1a269f8..41914455c 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -25,21 +25,27 @@ CAN_frame TESLA_221_2 = { static uint16_t sendContactorClosingMessagesStill = 300; static uint32_t battery_total_discharge = 0; static uint32_t battery_total_charge = 0; -static uint16_t battery_volts = 0; // V -static int16_t battery_amps = 0; // A -static uint16_t battery_raw_amps = 0; // A -static int16_t battery_max_temp = 0; // C* -static int16_t battery_min_temp = 0; // C* -static uint16_t battery_energy_buffer = 0; // kWh -static uint16_t battery_energy_to_charge_complete = 0; // kWh -static uint16_t battery_expected_energy_remaining = 0; // kWh -static uint8_t battery_full_charge_complete = 0; // kWh -static uint8_t battery_fully_charged = 0; // kWh -static uint16_t battery_ideal_energy_remaining = 0; // kWh -static uint16_t battery_nominal_energy_remaining = 0; // kWh -static uint16_t battery_nominal_full_pack_energy = 600; // Kwh -static uint16_t battery_beginning_of_life = 600; // kWh -static uint16_t battery_charge_time_remaining = 0; // Minutes +static uint16_t battery_volts = 0; // V +static int16_t battery_amps = 0; // A +static uint16_t battery_raw_amps = 0; // A +static int16_t battery_max_temp = 0; // C* +static int16_t battery_min_temp = 0; // C* +static uint16_t battery_energy_buffer = 0; // kWh +static uint16_t battery_energy_buffer_m1 = 0; // kWh +static uint16_t battery_energy_to_charge_complete = 0; // kWh +static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh +static uint16_t battery_expected_energy_remaining = 0; // kWh +static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh +static uint8_t battery_full_charge_complete = 0; // kWh +static uint8_t battery_fully_charged = 0; // kWh +static uint16_t battery_ideal_energy_remaining = 0; // kWh +static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh +static uint16_t battery_nominal_energy_remaining = 0; // kWh +static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh +static uint16_t battery_nominal_full_pack_energy = 600; // Kwh +static uint16_t battery_nominal_full_pack_energy_m0 = 600; // Kwh +static uint16_t battery_beginning_of_life = 600; // kWh +static uint16_t battery_charge_time_remaining = 0; // Minutes static uint16_t battery_regenerative_limit = 0; static uint16_t battery_discharge_limit = 0; static uint16_t battery_max_heat_park = 0; @@ -143,13 +149,19 @@ static uint16_t battery2_raw_amps = 0; // A static int16_t battery2_max_temp = 0; // C* static int16_t battery2_min_temp = 0; // C* static uint16_t battery2_energy_buffer = 0; +static uint16_t battery2_energy_buffer_m1 = 0; // kWh static uint16_t battery2_energy_to_charge_complete = 0; +static uint16_t battery2_energy_to_charge_complete_m1 = 0; // kWh static uint16_t battery2_expected_energy_remaining = 0; +static uint16_t battery2_expected_energy_remaining_m1 = 0; // kWh static uint8_t battery2_full_charge_complete = 0; static uint8_t battery2_fully_charged = 0; static uint16_t battery2_ideal_energy_remaining = 0; +static uint16_t battery2_ideal_energy_remaining_m0 = 0; // kWh static uint16_t battery2_nominal_energy_remaining = 0; +static uint16_t battery2_nominal_energy_remaining_m0 = 0; // kWh static uint16_t battery2_nominal_full_pack_energy = 600; +static uint16_t battery2_nominal_full_pack_energy_m0 = 600; // Kwh static uint16_t battery2_beginning_of_life = 600; static uint16_t battery2_charge_time_remaining = 0; // Minutes static uint16_t battery2_regenerative_limit = 0; @@ -369,10 +381,15 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.battery_dcdcHvBusVolt = battery_dcdcHvBusVolt; datalayer_extended.tesla.battery_dcdcLvOutputCurrent = battery_dcdcLvOutputCurrent; datalayer_extended.tesla.battery_nominal_full_pack_energy = battery_nominal_full_pack_energy; + datalayer_extended.tesla.battery_nominal_full_pack_energy_m0 = battery_nominal_full_pack_energy_m0; datalayer_extended.tesla.battery_nominal_energy_remaining = battery_nominal_energy_remaining; + datalayer_extended.tesla.battery_nominal_energy_remaining_m0 = battery_nominal_energy_remaining_m0; datalayer_extended.tesla.battery_ideal_energy_remaining = battery_ideal_energy_remaining; + datalayer_extended.tesla.battery_ideal_energy_remaining_m0 = battery_ideal_energy_remaining_m0; datalayer_extended.tesla.battery_energy_to_charge_complete = battery_energy_to_charge_complete; + datalayer_extended.tesla.battery_energy_to_charge_complete_m1 = battery_energy_to_charge_complete_m1; datalayer_extended.tesla.battery_energy_buffer = battery_energy_buffer; + datalayer_extended.tesla.battery_energy_buffer_m1 = battery_energy_buffer_m1; datalayer_extended.tesla.battery_full_charge_complete = battery_full_charge_complete; datalayer_extended.tesla.battery_total_discharge = battery_total_discharge; datalayer_extended.tesla.battery_total_charge = battery_total_charge; @@ -414,7 +431,7 @@ void update_values_battery() { //This function maps all the values fetched via Serial.print("Real SOC: "); Serial.print(battery_soc_ui / 10.0, 1); print_int_with_units(", Battery voltage: ", battery_volts, "V"); - print_int_with_units(", Battery HV current: ", (battery_amps * 0.1), "A"); + print_int_with_units(", Battery HV current: ", (battery_amps), "A"); // (battery_amps * 0.1) Serial.print(", Fully charged?: "); if (battery_full_charge_complete) Serial.print("YES, "); @@ -461,45 +478,38 @@ void receive_can_battery(CAN_frame rx_frame) { static uint16_t temp = 0; switch (rx_frame.ID) { - case 0x352: + case 0x352: // BMS_energyStatus // newer BMS >2021 mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X + if (mux == 0) { + //battery_nominal_full_pack_energy_m0 = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X + //battery_nominal_energy_remaining_m0 = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]); //BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X + //battery_ideal_energy_remaining_m0 = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); //BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X + } + if (mux == 1) { + //battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X + //battery_energy_buffer_m1 = (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X + //battery_expected_energy_remaining_m1 = (rx_frame.data.u8[5] | rx_frame.data.u8[4]); //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X + //battery_energy_to_charge_complete_m1 = (rx_frame.data.u8[7] | rx_frame.data.u8[6]); //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + } + if (mux == 2) {} + // Additional information needed on this mux, example frame: 02 26 02 20 02 80 00 00 doesn't change + // older BMS <2021 without mux battery_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); - (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])) * 0.1; //Example 752 (75.2kWh) + (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) battery_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); - (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)) * - 0.1; //Example 1247 * 0.1 = 124.7kWh + (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh battery_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); - (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | ((rx_frame.data.u8[2] & 0x03) >> 6)) * - 0.1; //Example 622 (62.2kWh) + (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | + ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) battery_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); - (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)) * - 0.1; //Example 311 * 0.1 = 31.1kWh + (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh battery_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); - (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)) * - 0.1; //Example 147 * 0.1 = 14.7kWh + (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh battery_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); - (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)) * 0.1; //Example 1 * 0.1 = 0 + (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 battery_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); ((rx_frame.data.u8[7] & 0x01) >> 7); - - if (mux == 0) { - battery_nominal_full_pack_energy = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * - 0.02; //BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X - battery_nominal_energy_remaining = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * - 0.02; //BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X - battery_ideal_energy_remaining = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) * - 0.02; //BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X - } - if (mux == 1) { - battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X - battery_energy_buffer = (rx_frame.data.u8[3] | rx_frame.data.u8[2]) * - 0.01; //BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X - battery_expected_energy_remaining = (rx_frame.data.u8[5] | rx_frame.data.u8[4]) * - 0.02; //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X - battery_energy_to_charge_complete = (rx_frame.data.u8[7] | rx_frame.data.u8[6]) * - 0.02; //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X - } break; case 0x20A: //Contactor state //HVP_contactorState: battery_packContNegativeState = (rx_frame.data.u8[0] & 0x07); //0|3@1+ (1,0) [0|7] "" @@ -629,37 +639,38 @@ void receive_can_battery(CAN_frame rx_frame) { } break; case 0x2d2: //BMSVAlimits: - battery_bms_min_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * - 0.1; //0|16@1+ (0.01,0) [0|430] "V" //Example 24148mv * 0.01 = 241.48 V - battery_bms_max_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * - 0.1; //16|16@1+ (0.01,0) [0|430] "V" //Example 40282mv * 0.01 = 402.82 V + battery_bms_min_voltage = + ((rx_frame.data.u8[1] << 8) | + rx_frame.data.u8[0]); //0|16@1+ (0.01,0) [0|430] "V" //Example 24148mv * 0.01 = 241.48 V + battery_bms_max_voltage = + ((rx_frame.data.u8[3] << 8) | + rx_frame.data.u8[2]); //16|16@1+ (0.01,0) [0|430] "V" //Example 40282mv * 0.01 = 402.82 V battery_max_charge_current = (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]) * 0.1; //32|14@1+ (0.1,0) [0|1638.2] "A" //Example 1301? * 0.1 = 130.1? battery_max_discharge_current = (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]) * 0.128; //48|14@1+ (0.128,0) [0|2096.9] "A" //Example 430? * 0.128 = 55.4? break; case 0x2b4: //PCS_dcdcRailStatus: - battery_dcdcLvBusVolt = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]) * - 0.0390625; //0|10@1+ (0.0390625,0) [0|39.9609] "V" - battery_dcdcHvBusVolt = (((rx_frame.data.u8[2] & 0x3F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)) * - 0.146484; //10|12@1+ (0.146484,0) [0|599.854] "V" + battery_dcdcLvBusVolt = + (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); //0|10@1+ (0.0390625,0) [0|39.9609] "V" + battery_dcdcHvBusVolt = (((rx_frame.data.u8[2] & 0x3F) << 6) | + ((rx_frame.data.u8[1] & 0xFC) >> 2)); //10|12@1+ (0.146484,0) [0|599.854] "V" battery_dcdcLvOutputCurrent = - (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]) * 0.1; //24|12@1+ (0.1,0) [0|400] "A" + (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]); //24|12@1+ (0.1,0) [0|400] "A" break; case 0x292: //BMS_socStatus datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //We are getting CAN messages from the BMS battery_beginning_of_life = - (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]) * 0.1; //40|10@1+ (0.1,0) [0|102.3] "kWh" - battery_soc_min = - (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]) * 0.1; //0|10@1+ (0.1,0) [0|102.3] "%" - battery_soc_ui = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)) * - 0.1; //10|10@1+ (0.1,0) [0|102.3] "%" - battery_soc_max = (((rx_frame.data.u8[3] & 0x3F) << 4) | ((rx_frame.data.u8[2] & 0xF0) >> 4)) * - 0.1; //20|10@1+ (0.1,0) [0|102.3] "%" + (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]) * 0.1; //40|10@1+ (0.1,0) [0|102.3] "kWh" + battery_soc_min = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); //0|10@1+ (0.1,0) [0|102.3] "%" + battery_soc_ui = + (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); //10|10@1+ (0.1,0) [0|102.3] "%" + battery_soc_max = + (((rx_frame.data.u8[3] & 0x3F) << 4) | ((rx_frame.data.u8[2] & 0xF0) >> 4)); //20|10@1+ (0.1,0) [0|102.3] "%" battery_soc_ave = - ((rx_frame.data.u8[4] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6)) * 0.1; //30|10@1+ (0.1,0) [0|102.3] "%" - battery_battTempPct = (((rx_frame.data.u8[7] & 0x03) << 6) | (rx_frame.data.u8[6] & 0x3F) >> 2) * - 0.4; //50|8@1+ (0.4,0) [0|100] "%" + ((rx_frame.data.u8[4] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6)); //30|10@1+ (0.1,0) [0|102.3] "%" + battery_battTempPct = + (((rx_frame.data.u8[7] & 0x03) << 6) | (rx_frame.data.u8[6] & 0x3F) >> 2); //50|8@1+ (0.4,0) [0|100] "%" break; case 0x392: //BMS_packConfig mux = (rx_frame.data.u8[0] & (0xFF)); @@ -668,7 +679,7 @@ void receive_can_battery(CAN_frame rx_frame) { battery_moduleType = (rx_frame.data.u8[1] & (0x07)); //8|3@1+ (1,0) [0|4] "" battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg" battery_platformMaxBusVoltage = - (((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3])) * 0.1 + 375; //24|10@1+ (0.1,375) [0|0] "V" + (((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3])); //24|10@1+ (0.1,375) [0|0] "V" } if (mux == 0) { battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); //8|5@1+ (1,0) [0|31] "" @@ -739,48 +750,49 @@ void receive_can_battery2(CAN_frame rx_frame) { static uint16_t temp = 0; switch (rx_frame.ID) { - case 0x352: + case 0x352: // BMS_energyStatus // newer BMS >2021 mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X - if (mux == 3) { - battery2_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); - (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) - battery2_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); - (((rx_frame.data.u8[2] & 0x3F) << 5) | - ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh - battery2_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); - (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | - ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) - battery2_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); - (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh - battery2_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); - (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh - battery2_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); - (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 - battery2_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); - ((rx_frame.data.u8[7] & 0x01) >> 7); - } + if (mux == 0) { - battery2_nominal_full_pack_energy = - (rx_frame.data.u8[3] | - rx_frame.data.u8[2]); //SG_ BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X - battery2_nominal_energy_remaining = - (rx_frame.data.u8[5] | - rx_frame.data.u8[4]); //SG_ BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X - battery2_ideal_energy_remaining = - (rx_frame.data.u8[7] | - rx_frame.data.u8[6]); //SG_ BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X + battery2_nominal_full_pack_energy_m0 = + ((rx_frame.data.u8[3] << 8) | + rx_frame.data.u8[2]); //BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X + battery2_nominal_energy_remaining_m0 = + ((rx_frame.data.u8[5] << 8) | + rx_frame.data.u8[4]); //BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X + battery2_ideal_energy_remaining_m0 = + ((rx_frame.data.u8[7] << 8) | + rx_frame.data.u8[6]); //BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X } if (mux == 1) { - battery2_fully_charged = (rx_frame.data.u8[1] & 0x01); //SG_ BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X - battery2_energy_buffer = - (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //SG_ BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X - battery2_expected_energy_remaining = + battery2_fully_charged = (rx_frame.data.u8[1] & 0x01); //BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X + battery2_energy_buffer_m1 = + (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X + battery2_expected_energy_remaining_m1 = (rx_frame.data.u8[5] | - rx_frame.data.u8[4]); //SG_ BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X - battery2_energy_to_charge_complete = + rx_frame.data.u8[4]); //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X + battery2_energy_to_charge_complete_m1 = (rx_frame.data.u8[7] | - rx_frame.data.u8[6]); //SG_ BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + rx_frame.data.u8[6]); //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X } + if (mux == 2) {} + // Additional information needed on this mux, example frame: 02 26 02 20 02 80 00 00 doesn't change + // older BMS <2021 without mux + //battery2_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); + (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) + //battery2_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); + (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh + //battery2_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); + (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | + ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) + //battery2_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); + (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh + //battery2_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); + (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh + //battery2_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); + (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 + //battery2_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); + ((rx_frame.data.u8[7] & 0x01) >> 7); break; case 0x20A: //Contactor state @@ -791,6 +803,22 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_packCtrsClosingAllowed = (rx_frame.data.u8[4] & 0x08) >> 3; battery2_pyroTestInProgress = (rx_frame.data.u8[4] & 0x20) >> 5; battery2_hvil_status = (rx_frame.data.u8[5] & 0x0F); + //HVP_packCtrsOpenNowRequested : 33|1@1+ (1,0) [0|1] "" + //HVP_packCtrsOpenRequested : 34|1@1+ (1,0) [0|1] "" + //HVP_packCtrsRequestStatus : 30|2@1+ (1,0) [0|2] "" + //HVP_packCtrsResetRequestRequired : 32|1@1+ (1,0) [0|1] "" + //HVP_dcLinkAllowedToEnergize : 36|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcContNegativeAuxOpen : 7|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcContNegativeState : 12|3@1+ (1,0) [0|7] "" Receiver + //HVP_fcContPositiveAuxOpen : 6|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcContPositiveState : 16|3@1+ (1,0) [0|7] "" Receiver + //HVP_fcContactorSetState : 19|4@1+ (1,0) [0|9] "" Receiver + //HVP_fcCtrsClosingAllowed : 29|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcCtrsOpenNowRequested : 27|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcCtrsOpenRequested : 28|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcCtrsRequestStatus : 24|2@1+ (1,0) [0|2] "" Receiver + //HVP_fcCtrsResetRequestRequired : 26|1@1+ (1,0) [0|1] "" Receiver + //HVP_fcLinkAllowedToEnergize : 44|2@1+ (1,0) [0|2] "" Receiver break; case 0x252: //Limits @@ -809,7 +837,7 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_amps = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //Example 65492 (-4.3A) OR 225 (22.5A) battery2_raw_amps = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * -0.05; //Example 10425 * -0.05 = ? battery2_charge_time_remaining = - (((rx_frame.data.u8[7] & 0x0F) << 8) | rx_frame.data.u8[6]) * 0.1; //Example 228 * 0.1 = 22.8min + (((rx_frame.data.u8[7] & 0x0F) << 8) | rx_frame.data.u8[6]); //Example 228 * 0.1 = 22.8min if (battery2_charge_time_remaining == 4095) { battery2_charge_time_remaining = 0; } @@ -818,9 +846,11 @@ void receive_can_battery2(CAN_frame rx_frame) { case 0x3D2: // total charge/discharge kwh battery2_total_discharge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | - (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * + 0.001; battery2_total_charge = ((rx_frame.data.u8[7] << 24) | (rx_frame.data.u8[6] << 16) | (rx_frame.data.u8[5] << 8) | - rx_frame.data.u8[4]); + rx_frame.data.u8[4]) * + 0.001; break; case 0x332: //min/max hist values @@ -882,9 +912,9 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_bms_max_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //Example 40282mv * 0.01 = 402.82 V battery2_max_charge_current = - (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]); //Example 1301? * 0.1 = 130.1? + (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]) * 0.1; //Example 1301? * 0.1 = 130.1? battery2_max_discharge_current = - (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]); //Example 430? * 0.128 = 55.4? + (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]) * 0.128; //Example 430? * 0.128 = 55.4? break; case 0x2b4: //PCS_dcdcRailStatus: battery2_dcdcLvBusVolt = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); @@ -893,7 +923,7 @@ void receive_can_battery2(CAN_frame rx_frame) { break; case 0x292: //BMS_socStatus datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //We are getting CAN messages from the BMS - battery2_beginning_of_life = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]); + battery2_beginning_of_life = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]) * 0.1; battery2_soc_min = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); battery2_soc_ui = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); battery2_soc_max = (((rx_frame.data.u8[3] & 0x3F) << 4) | ((rx_frame.data.u8[2] & 0xF0) >> 4)); diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 46a69bdaf..cb673593d 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -186,10 +186,15 @@ typedef struct { uint16_t battery_dcdcHvBusVolt = 0; uint16_t battery_dcdcLvOutputCurrent = 0; uint16_t battery_nominal_full_pack_energy = 0; + uint16_t battery_nominal_full_pack_energy_m0 = 0; uint16_t battery_nominal_energy_remaining = 0; + uint16_t battery_nominal_energy_remaining_m0 = 0; uint16_t battery_ideal_energy_remaining = 0; + uint16_t battery_ideal_energy_remaining_m0 = 0; uint16_t battery_energy_to_charge_complete = 0; + uint16_t battery_energy_to_charge_complete_m1 = 0; uint16_t battery_energy_buffer = 0; + uint16_t battery_energy_buffer_m1 = 0; uint16_t battery_full_charge_complete = 0; uint8_t battery_fully_charged = 0; uint16_t battery_total_discharge = 0; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 1efa3530f..7645465de 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -286,54 +286,79 @@ String advanced_battery_processor(const String& var) { #ifdef TESLA_BATTERY float beginning_of_life = static_cast(datalayer_extended.tesla.battery_beginning_of_life); + float battTempPct = static_cast(datalayer_extended.tesla.battery_battTempPct) * 0.4; + float dcdcLvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcLvBusVolt) * 0.0390625; + float dcdcHvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcHvBusVolt) * 0.146484; + float dcdcLvOutputCurrent = static_cast(datalayer_extended.tesla.battery_dcdcLvOutputCurrent) * 0.1; + float nominal_full_pack_energy = + static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy) * 0.1; + float nominal_full_pack_energy_m0 = + static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy_m0) * 0.02; + float nominal_energy_remaining = + static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining) * 0.1; + float nominal_energy_remaining_m0 = + static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining_m0) * 0.02; + float ideal_energy_remaining = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining) * 0.1; + float ideal_energy_remaining_m0 = + static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining_m0) * 0.02; + float energy_to_charge_complete = + static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete) * 0.1; + float energy_to_charge_complete_m1 = + static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete_m1) * 0.02; + float energy_buffer = static_cast(datalayer_extended.tesla.battery_energy_buffer) * 0.1; + float energy_buffer_m1 = static_cast(datalayer_extended.tesla.battery_energy_buffer_m1) * 0.01; + float total_discharge = static_cast(datalayer_extended.tesla.battery_total_discharge); + float total_charge = static_cast(datalayer_extended.tesla.battery_total_charge); + float packMass = static_cast(datalayer_extended.tesla.battery_packMass); + float platformMaxBusVoltage = + static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage) * 0.1 + 375; + float bms_min_voltage = static_cast(datalayer_extended.tesla.battery_bms_min_voltage) * 0.01 * 2; + float bms_max_voltage = static_cast(datalayer_extended.tesla.battery_bms_max_voltage) * 0.01 * 2; + float max_charge_current = static_cast(datalayer_extended.tesla.battery_max_charge_current); + float max_discharge_current = static_cast(datalayer_extended.tesla.battery_max_discharge_current); + float soc_ave = static_cast(datalayer_extended.tesla.battery_soc_ave) * 0.1; + float soc_max = static_cast(datalayer_extended.tesla.battery_soc_max) * 0.1; + float soc_min = static_cast(datalayer_extended.tesla.battery_soc_min) * 0.1; + float soc_ui = static_cast(datalayer_extended.tesla.battery_soc_ui) * 0.1; + + // Comment what data you would like to dislay, order can be changed. content += "

Battery Beginning of Life: " + String(beginning_of_life) + " kWh

"; - float battTempPct = static_cast(datalayer_extended.tesla.battery_battTempPct); content += "

BattTempPct: " + String(battTempPct) + "

"; - float dcdcLvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcLvBusVolt); content += "

PCS Lv Bus: " + String(dcdcLvBusVolt) + " V

"; - float dcdcHvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcHvBusVolt); content += "

PCS Hv Bus: " + String(dcdcHvBusVolt) + " V

"; - float dcdcLvOutputCurrent = static_cast(datalayer_extended.tesla.battery_dcdcLvOutputCurrent); content += "

PCS Lv Output: " + String(dcdcLvOutputCurrent) + " A

"; - float nominal_full_pack_energy = static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy); - content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " kWh

"; - float nominal_energy_remaining = static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining); - content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " kWh

"; - float ideal_energy_remaining = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining); - content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " kWh

"; - float energy_to_charge_complete = static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete); - content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " kWh

"; - float energy_buffer = static_cast(datalayer_extended.tesla.battery_energy_buffer); - content += "

Energy Buffer: " + String(energy_buffer) + " kWh

"; + + //if using older BMS <2021 and comment 0x352 without MUX + //content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " kWh

"; + //content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " kWh

"; + //content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " kWh

"; + //content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " kWh

"; + //content += "

Energy Buffer: " + String(energy_buffer) + " kWh

"; + + //if using newer BMS >2021 and comment 0x352 with MUX + content += "

Nominal Full Pack Energy m0: " + String(nominal_full_pack_energy_m0) + " kWh

"; + content += "

Nominal Energy Remaining m0: " + String(nominal_energy_remaining_m0) + " kWh

"; + content += "

Ideal Energy Remaining m0: " + String(ideal_energy_remaining_m0) + " kWh

"; + content += "

Energy to Charge Complete m1: " + String(energy_to_charge_complete_m1) + " kWh

"; + content += "

Energy Buffer m1: " + String(energy_buffer_m1) + " kWh

"; + content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; content += "

reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "

"; - content += "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + - "

"; // no float needed - float total_discharge = static_cast(datalayer_extended.tesla.battery_total_discharge); + content += "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "

"; content += "

Total Discharge: " + String(total_discharge) + " kWh

"; - float total_charge = static_cast(datalayer_extended.tesla.battery_total_charge); content += "

Total Charge: " + String(total_charge) + " kWh

"; - float packMass = static_cast(datalayer_extended.tesla.battery_packMass); content += "

Battery Pack Mass: " + String(packMass) + " KG

"; - float platformMaxBusVoltage = static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage); content += "

Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V

"; - float bms_min_voltage = static_cast(datalayer_extended.tesla.battery_bms_min_voltage); content += "

BMS Min Voltage: " + String(bms_min_voltage) + " V

"; - float bms_max_voltage = static_cast(datalayer_extended.tesla.battery_bms_max_voltage); content += "

BMS Max Voltage: " + String(bms_max_voltage) + " V

"; - float max_charge_current = static_cast(datalayer_extended.tesla.battery_max_charge_current); content += "

Max Charge Current: " + String(max_charge_current) + " A

"; - float max_discharge_current = static_cast(datalayer_extended.tesla.battery_max_discharge_current); content += "

Max Discharge Current: " + String(max_discharge_current) + " A

"; - float soc_ave = static_cast(datalayer_extended.tesla.battery_soc_ave); content += "

Battery SOC Ave: " + String(soc_ave) + "

"; - float soc_max = static_cast(datalayer_extended.tesla.battery_soc_max); content += "

Battery SOC Max: " + String(soc_max) + "

"; - float soc_min = static_cast(datalayer_extended.tesla.battery_soc_min); content += "

Battery SOC Min: " + String(soc_min) + "

"; - float soc_ui = static_cast(datalayer_extended.tesla.battery_soc_ui); content += "

Battery SOC UI: " + String(soc_ui) + "

"; + static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"}; From eb7c3545777d1c27d5b43940ed3d2ebe9118c962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 25 Nov 2024 10:42:14 +0200 Subject: [PATCH 011/225] Add insulation reading + generation enum --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 1 + Software/src/datalayer/datalayer_extended.h | 3 +++ Software/src/devboard/webserver/advanced_battery_html.cpp | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 21267422c..9a9f347e9 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -331,6 +331,7 @@ void update_values_battery() { /* This function maps all the values fetched via datalayer_extended.nissanleaf.ChargePowerLimit = battery_Charge_Power_Limit; datalayer_extended.nissanleaf.MaxPowerForCharger = battery_MAX_POWER_FOR_CHARGER; datalayer_extended.nissanleaf.Interlock = battery_Interlock; + datalayer_extended.nissanleaf.Insulation = battery_insulation; datalayer_extended.nissanleaf.RelayCutRequest = battery_Relay_Cut_Request; datalayer_extended.nissanleaf.FailsafeStatus = battery_Failsafe_Status; datalayer_extended.nissanleaf.Full = battery_Full_CHARGE_flag; diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index d4fd2444a..7d31fcaa5 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -199,6 +199,9 @@ typedef struct { /** bool */ /** Interlock status */ bool Interlock = false; + /** int16_t */ + /** Insulation resistance, most likely kOhm */ + uint16_t Insulation = 0; /** uint8_t */ /** battery_FAIL status */ uint8_t RelayCutRequest = 0; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 659bcda89..054a12709 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -319,11 +319,13 @@ String advanced_battery_processor(const String& var) { #endif #ifdef NISSAN_LEAF_BATTERY - content += "

LEAF generation: " + String(datalayer_extended.nissanleaf.LEAF_gen) + "

"; + static const char* LEAFgen[] = {"ZE0", "AZE0", "ZE1"}; + content += "

LEAF generation: " + String(LEAFgen[datalayer_extended.nissanleaf.LEAF_gen]) + "

"; content += "

GIDS: " + String(datalayer_extended.nissanleaf.GIDS) + "

"; content += "

Regen kW: " + String(datalayer_extended.nissanleaf.ChargePowerLimit) + "

"; content += "

Charge kW: " + String(datalayer_extended.nissanleaf.MaxPowerForCharger) + "

"; content += "

Interlock: " + String(datalayer_extended.nissanleaf.Interlock) + "

"; + content += "

Insulation: " + String(datalayer_extended.nissanleaf.Insulation) + "

"; content += "

Relay cut request: " + String(datalayer_extended.nissanleaf.RelayCutRequest) + "

"; content += "

Failsafe status: " + String(datalayer_extended.nissanleaf.FailsafeStatus) + "

"; content += "

Fully charged: " + String(datalayer_extended.nissanleaf.Full) + "

"; From 2c54366b5776cc7f6c8e8206758a84f5ed835c57 Mon Sep 17 00:00:00 2001 From: amarofarinha <151563493+amarofarinha@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:03:23 +0000 Subject: [PATCH 012/225] bugfix - Scaled Remaining Capacity underflows --- Software/Software.ino | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 2074f1919..dcf0d7525 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -901,8 +901,13 @@ void update_calculated_values() { calc_max_capacity = (datalayer.battery.status.remaining_capacity_Wh * 10000 / datalayer.battery.status.real_soc); calc_reserved_capacity = calc_max_capacity * datalayer.battery.settings.min_percentage / 10000; // remove % capacity reserved in min_percentage to total_capacity_Wh - datalayer.battery.status.reported_remaining_capacity_Wh = - datalayer.battery.status.remaining_capacity_Wh - calc_reserved_capacity; + if (datalayer.battery.status.remaining_capacity_Wh > calc_reserved_capacity) { + datalayer.battery.status.reported_remaining_capacity_Wh = + datalayer.battery.status.remaining_capacity_Wh - calc_reserved_capacity; + } else { + datalayer.battery.status.reported_remaining_capacity_Wh = 0; + } + } else { datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh; } From 198c5a63f40cce94765b8b710f9b0ceb9791b241 Mon Sep 17 00:00:00 2001 From: amarofarinha <151563493+amarofarinha@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:13:05 +0000 Subject: [PATCH 013/225] include DOUBLE_BATTERY setup in the fix --- Software/Software.ino | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index dcf0d7525..dd0a545a3 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -923,8 +923,12 @@ void update_calculated_values() { (datalayer.battery2.status.remaining_capacity_Wh * 10000 / datalayer.battery2.status.real_soc); calc_reserved_capacity = calc_max_capacity * datalayer.battery2.settings.min_percentage / 10000; // remove % capacity reserved in min_percentage to total_capacity_Wh - datalayer.battery2.status.reported_remaining_capacity_Wh = - datalayer.battery2.status.remaining_capacity_Wh - calc_reserved_capacity; + if (datalayer.battery2.status.remaining_capacity_Wh > calc_reserved_capacity) { + datalayer.battery2.status.reported_remaining_capacity_Wh = + datalayer.battery2.status.remaining_capacity_Wh - calc_reserved_capacity; + } else { + datalayer.battery2.status.reported_remaining_capacity_Wh = 0; + } } else { datalayer.battery2.status.reported_remaining_capacity_Wh = datalayer.battery2.status.remaining_capacity_Wh; } From be257a1658227d8520de5077e19e7e12f5036c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 25 Nov 2024 12:47:52 +0200 Subject: [PATCH 014/225] Update version number for release --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index dd0a545a3..118d181bb 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -53,7 +53,7 @@ Preferences settings; // Store user settings // The current software version, shown on webserver -const char* version_number = "7.8.dev"; +const char* version_number = "7.8.0"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From 69664b902b87b2df5ddf3d96c436b802c25dad34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 25 Nov 2024 13:01:24 +0200 Subject: [PATCH 015/225] Update version number to signal dev --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index 118d181bb..d88ef46bf 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -53,7 +53,7 @@ Preferences settings; // Store user settings // The current software version, shown on webserver -const char* version_number = "7.8.0"; +const char* version_number = "7.9.dev"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From faf22e6a4c01b20cd7726018095a90879ab9d834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 25 Nov 2024 23:05:34 +0200 Subject: [PATCH 016/225] Update SMA Tripower based on logs --- Software/Software.ino | 9 + Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 371 +++++++-------------- Software/src/inverter/SMA-TRIPOWER-CAN.h | 3 + 3 files changed, 136 insertions(+), 247 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index d88ef46bf..cd09171aa 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -545,6 +545,10 @@ void init_contactors() { pinMode(BMS_POWER, OUTPUT); digitalWrite(BMS_POWER, HIGH); #endif //HW_STARK +#ifdef SMA_TRIPOWER_CAN + //pinMode(INVERTER_CONTACTOR_ENABLE_PIN, OUTPUT); //Incase this is an output + //digitalWrite(INVERTER_CONTACTOR_ENABLE_PIN, LOW); //Incase this is an output +#endif //SMA_TRIPOWER_CAN } void init_rs485() { @@ -742,6 +746,11 @@ void handle_contactors() { #ifdef BYD_SMA datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); #endif +#ifdef SMA_TRIPOWER_CAN + //set(INVERTER_CONTACTOR_ENABLE_PIN, ON); //TODO: is this an input, or an output? Figure out and make logic + datalayer.system.status.inverter_allows_contactor_closing = + digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); //Incase it is input +#endif #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY handle_contactors_battery2(); diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 7a242daee..f6c9ea054 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -13,276 +13,145 @@ /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis500ms = 0; // will store last time a 100ms CAN Message was send +static unsigned long previousMillis2s = 0; // will store last time a 2s CAN Message was send +static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send + +static uint32_t inverter_time = 0; +static uint16_t inverter_voltage = 0; +static int16_t inverter_current = 0; +static bool pairing_completed = false; //Actual content messages -CAN_frame SMA_00D = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x00D, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_00F = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x00F, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_011 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x011, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_013 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x013, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_014 = {.FD = false, +CAN_frame SMA_558 = {.FD = false, //Pairing first message .ext_ID = false, .DLC = 8, - .ID = 0x014, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_005 = {.FD = false, + .ID = 0x558, // BYD HVS 10.2 kWh (0x66 might be kWh) + .data = {0x03, 0x24, 0x00, 0x04, 0x00, 0x66, 0x04, 0x09}}; //Amount of modules? Vendor ID? +CAN_frame SMA_598 = {.FD = false, .ext_ID = false, .DLC = 8, - .ID = 0x005, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_007 = {.FD = false, + .ID = 0x598, + .data = {0x12, 0x30, 0x8A, 0x5B, 0x00, 0x00, 0x00, 0x00}}; //B0-4 Serial? +CAN_frame SMA_5D8 = {.FD = false, .ext_ID = false, .DLC = 8, - .ID = 0x007, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_006 = {.FD = false, + .ID = 0x5D8, + .data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //B Y D +CAN_frame SMA_618_0 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //BATTERY +CAN_frame SMA_618_1 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}}; //-Box Pr +CAN_frame SMA_618_2 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}}; //emium H +CAN_frame SMA_618_3 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VS +CAN_frame SMA_358 = {.FD = false, .ext_ID = false, .DLC = 8, - .ID = 0x006, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_008 = {.FD = false, + .ID = 0x358, + .data = {0x12, 0x40, 0x0C, 0x80, 0x01, 0x00, 0x01, 0x00}}; +CAN_frame SMA_3D8 = {.FD = false, .ext_ID = false, .DLC = 8, - .ID = 0x008, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_015 = {.FD = false, + .ID = 0x3D8, + .data = {0x04, 0x06, 0x27, 0x10, 0x00, 0x19, 0x00, 0xFA}}; +CAN_frame SMA_458 = {.FD = false, .ext_ID = false, .DLC = 8, - .ID = 0x015, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_016 = {.FD = false, + .ID = 0x458, + .data = {0x00, 0x00, 0x73, 0xAE, 0x00, 0x00, 0x64, 0x64}}; +CAN_frame SMA_4D8 = {.FD = false, .ext_ID = false, .DLC = 8, - .ID = 0x016, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_017 = {.FD = false, + .ID = 0x4D8, + .data = {0x10, 0x62, 0x00, 0x00, 0x00, 0x78, 0x02, 0x08}}; +CAN_frame SMA_518 = {.FD = false, .ext_ID = false, .DLC = 8, - .ID = 0x017, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_018 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x018, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - -static int16_t temperature_average = 0; -static uint16_t ampere_hours_remaining = 0; -static uint16_t ampere_hours_max = 0; -static bool batteryAlarm = false; -static bool BMSevent = false; - -enum BatteryState { NA, INIT, BAT_STANDBY, OPERATE, WARNING, FAULTED, UPDATE, BAT_UPDATE }; -BatteryState batteryState = OPERATE; -enum InverterControlFlags { - EMG_CHARGE_REQUEST, - EMG_DISCHARGE_REQUEST, - NOT_ENOUGH_ENERGY_FOR_START, - INVERTER_STAY_ON, - FORCED_BATTERY_SHUTDOWN, - RESERVED, - BATTERY_UPDATE_AVAILABLE, - NO_BATTERY_UPDATED_BY_INV -}; -InverterControlFlags inverterControlFlags = BATTERY_UPDATE_AVAILABLE; -enum Events0 { - START_SOC_CALIBRATE, - STOP_SOC_CALIBRATE, - START_POWERLIMIT, - STOP_POWERLIMIT, - PREVENTATIVE_BAT_SHUTDOWN, - THERMAL_MANAGEMENT, - START_BALANCING, - STOP_BALANCING -}; -Events0 events0 = START_BALANCING; -enum Events1 { START_BATTERY_SELFTEST, STOP_BATTERY_SELFTEST }; -Events1 events1 = START_BATTERY_SELFTEST; -enum Command2Battery { IDLE, RUN, NOT_USED1, NOT_USED2, SHUTDOWN, FIRMWARE_UPDATE, BATSELFUPDATE, NOT_USED3 }; -Command2Battery command2Battery = RUN; -enum InvInitState { SYSTEM_FREQUENCY, XPHASE_SYSTEM, BLACKSTART_OPERATION }; -InvInitState invInitState = SYSTEM_FREQUENCY; + .ID = 0x518, + .data = {0x00, 0x96, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00}}; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the inverter CAN - //Calculate values - - temperature_average = - ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); - - ampere_hours_remaining = - ((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) * - 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) - ampere_hours_max = ((datalayer.battery.info.total_capacity_Wh / datalayer.battery.status.voltage_dV) * - 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) - - batteryState = OPERATE; - inverterControlFlags = INVERTER_STAY_ON; //Map values to CAN messages - // Battery Limits - //Battery Max Charge Voltage (eg 400.0V = 4000 , 16bits long) - SMA_00D.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); - SMA_00D.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); - //Battery Min Discharge Voltage (eg 300.0V = 3000 , 16bits long) - SMA_00D.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); - SMA_00D.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); + + //Maxvoltage (eg 400.0V = 4000 , 16bits long) + SMA_358.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); + SMA_358.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); + //Minvoltage (eg 300.0V = 3000 , 16bits long) + SMA_358.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); + SMA_358.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); //Discharge limited current, 500 = 50A, (0.1, A) - SMA_00D.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); - SMA_00D.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); + SMA_358.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); + SMA_358.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); //Charge limited current, 125 =12.5A (0.1, A) - SMA_00D.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); - SMA_00D.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); + SMA_358.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); + SMA_358.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); - // Battery State //SOC (100.00%) - SMA_00F.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); - SMA_00F.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF); + SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); + SMA_3D8.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF); //StateOfHealth (100.00%) - SMA_00F.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8); - SMA_00F.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF); + SMA_3D8.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8); + SMA_3D8.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF); //State of charge (AH, 0.1) - SMA_00F.data.u8[4] = (ampere_hours_remaining >> 8); - SMA_00F.data.u8[5] = (ampere_hours_remaining & 0x00FF); - //Fully charged (AH, 0.1) - SMA_00F.data.u8[6] = (ampere_hours_max >> 8); - SMA_00F.data.u8[7] = (ampere_hours_max & 0x00FF); - - // Battery Energy - //Charged Energy Counter TODO: are these needed? - //SMA_011.data.u8[0] = (X >> 8); - //SMA_011.data.u8[1] = (X & 0x00FF); - //SMA_011.data.u8[2] = (X >> 8); - //SMA_011.data.u8[3] = (X & 0x00FF); - //Discharged Energy Counter TODO: are these needed? - //SMA_011.data.u8[4] = (X >> 8); - //SMA_011.data.u8[5] = (X & 0x00FF); - //SMA_011.data.u8[6] = (X >> 8); - //SMA_011.data.u8[7] = (X & 0x00FF); + SMA_3D8.data.u8[4] = (ampere_hours_remaining >> 8); + SMA_3D8.data.u8[5] = (ampere_hours_remaining & 0x00FF); - // Battery Measurements //Voltage (370.0) - SMA_013.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8); - SMA_013.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF); + SMA_4D8.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8); + SMA_4D8.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF); //Current (TODO: signed OK?) - SMA_013.data.u8[2] = (datalayer.battery.status.current_dA >> 8); - SMA_013.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF); + SMA_4D8.data.u8[2] = (datalayer.battery.status.current_dA >> 8); + SMA_4D8.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF); //Temperature average - SMA_013.data.u8[4] = (temperature_average >> 8); - SMA_013.data.u8[5] = (temperature_average & 0x00FF); - //Battery state - SMA_013.data.u8[6] = batteryState; - SMA_013.data.u8[6] = inverterControlFlags; - - // Battery Temperature and Cellvoltages - // Battery max temperature - SMA_014.data.u8[0] = (datalayer.battery.status.temperature_max_dC >> 8); - SMA_014.data.u8[1] = (datalayer.battery.status.temperature_max_dC & 0x00FF); - // Battery min temperature - SMA_014.data.u8[2] = (datalayer.battery.status.temperature_min_dC >> 8); - SMA_014.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF); - // Battery Cell Voltage (sum) - //SMA_014.data.u8[4] = (??? >> 8); //TODO scaling? - //SMA_014.data.u8[5] = (??? & 0x00FF); //TODO scaling? - // Cell voltage min - //SMA_014.data.u8[6] = (??? >> 8); //TODO scaling? 0-255 - // Cell voltage max - //SMA_014.data.u8[7] = (??? >> 8); //TODO scaling? 0-255 - - //SMA_006.data.u8[0] = (ErrorCode >> 8); - //SMA_006.data.u8[1] = (ErrorCode & 0x00FF); - //SMA_006.data.u8[2] = ModuleNumber; - //SMA_006.data.u8[3] = ErrorLevel; - //SMA_008.data.u8[0] = Events0; - //SMA_008.data.u8[1] = Events1; - - //SMA_005.data.u8[0] = BMSalarms0; - //SMA_005.data.u8[1] = BMSalarms1; - //SMA_005.data.u8[2] = BMSalarms2; - //SMA_005.data.u8[3] = BMSalarms3; - //SMA_005.data.u8[4] = BMSalarms4; - //SMA_005.data.u8[5] = BMSalarms5; - //SMA_005.data.u8[6] = BMSalarms6; - //SMA_005.data.u8[7] = BMSalarms7; - - //SMA_007.data.u8[0] = DCDCalarms0; - //SMA_007.data.u8[1] = DCDCalarms1; - //SMA_007.data.u8[2] = DCDCalarms2; - //SMA_007.data.u8[3] = DCDCalarms3; - //SMA_007.data.u8[4] = DCDCwarnings0; - //SMA_007.data.u8[5] = DCDCwarnings1; - //SMA_007.data.u8[6] = DCDCwarnings2; - //SMA_007.data.u8[7] = DCDCwarnings3; - - //SMA_015.data.u8[0] = BatterySystemVersion; - //SMA_015.data.u8[1] = BatterySystemVersion; - //SMA_015.data.u8[2] = BatterySystemVersion; - //SMA_015.data.u8[3] = BatterySystemVersion; - //SMA_015.data.u8[4] = BatteryCapacity; - //SMA_015.data.u8[5] = BatteryCapacity; - //SMA_015.data.u8[6] = NumberOfModules; - //SMA_015.data.u8[7] = BatteryManufacturerID; - - //SMA_016.data.u8[0] = SerialNumber; - //SMA_016.data.u8[1] = SerialNumber; - //SMA_016.data.u8[2] = SerialNumber; - //SMA_016.data.u8[3] = SerialNumber; - //SMA_016.data.u8[4] = ManufacturingDate; - //SMA_016.data.u8[5] = ManufacturingDate; - //SMA_016.data.u8[6] = ManufacturingDate; - //SMA_016.data.u8[7] = ManufacturingDate; - - //SMA_017.data.u8[0] = Multiplex; - //SMA_017.data.u8[1] = ManufacturerName; - //SMA_017.data.u8[2] = ManufacturerName; - //SMA_017.data.u8[3] = ManufacturerName; - //SMA_017.data.u8[4] = ManufacturerName; - //SMA_017.data.u8[5] = ManufacturerName; - //SMA_017.data.u8[6] = ManufacturerName; - //SMA_017.data.u8[7] = ManufacturerName; - - //SMA_018.data.u8[0] = Multiplex; - //SMA_018.data.u8[1] = BatteryName; - //SMA_018.data.u8[2] = BatteryName; - //SMA_018.data.u8[3] = BatteryName; - //SMA_018.data.u8[4] = BatteryName; - //SMA_018.data.u8[5] = BatteryName; - //SMA_018.data.u8[6] = BatteryName; - //SMA_018.data.u8[7] = BatteryName; + SMA_4D8.data.u8[4] = (temperature_average >> 8); + SMA_4D8.data.u8[5] = (temperature_average & 0x00FF); + //Battery ready + if (datalayer.battery.status.bms_status == FAULT) { + SMA_4D8.data.u8[6] = STOP_STATE; + } else { + SMA_4D8.data.u8[6] = READY_STATE; + } } void receive_can_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { - case 0x00D: //Inverter Measurements + case 0x360: //Message originating from SMA inverter - Voltage and current datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + inverter_voltage = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + inverter_current = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; break; - case 0x00F: //Inverter Feedback + case 0x3E0: //Message originating from SMA inverter - ? datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; break; - case 0x010: //Time from inverter + case 0x420: //Message originating from SMA inverter - Timestamp datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + inverter_time = + (rx_frame.data.u8[0] << 24) | (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; break; - case 0x015: //Initialization message from inverter + case 0x560: //Message originating from SMA inverter - Init datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - send_tripower_init(); break; - case 0x017: //Initialization message from inverter 2 + case 0x5E0: //Message originating from SMA inverter - String + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + //Inverter brand (frame1-3 = 0x53 0x4D 0x41) = SMA + break; + case 0x660: //Message originating from SMA inverter - Pairing request datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - //send_tripower_init(); + send_tripower_init(); break; default: break; @@ -292,33 +161,41 @@ void receive_can_inverter(CAN_frame rx_frame) { void send_can_inverter() { unsigned long currentMillis = millis(); - // Send CAN Message every 500ms - if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) { - previousMillis500ms = currentMillis; + //TODO, should we break before pairing_completed? Or rely on Enable line? - transmit_can(&SMA_00D, can_config.inverter); //Battery limits - transmit_can(&SMA_00F, can_config.inverter); // Battery state - transmit_can(&SMA_011, can_config.inverter); // Battery Energy - transmit_can(&SMA_013, can_config.inverter); // Battery Measurements - transmit_can(&SMA_014, can_config.inverter); // Battery Temperatures and cellvoltages + // Send CAN Message every 2s + if (currentMillis - previousMillis2s >= INTERVAL_2_S) { + previousMillis2s = currentMillis; + transmit_can(&SMA_358, can_config.inverter); } - - if (batteryAlarm) { //Non-cyclic - transmit_can(&SMA_005, can_config.inverter); // Battery Alarms 1 - transmit_can(&SMA_007, can_config.inverter); // Battery Alarms 2 - } - - if (BMSevent) { //Non-cyclic - transmit_can(&SMA_006, can_config.inverter); // Battery Errorcode - transmit_can(&SMA_008, can_config.inverter); // Battery Events + // Send CAN Message every 10s + if (currentMillis - previousMillis10s >= INTERVAL_10_S) { + previousMillis10s = currentMillis; + transmit_can(&SMA_518, can_config.inverter); + transmit_can(&SMA_4D8, can_config.inverter); + transmit_can(&SMA_3D8, can_config.inverter); + if (pairing_completed) { + transmit_can( + &SMA_458, + can_config + .inverter); //TODO; not confirmed if battery sends. Transmission starts only after battery is paired + } } } - void send_tripower_init() { - transmit_can(&SMA_015, can_config.inverter); // Battery Data 1 - transmit_can(&SMA_016, can_config.inverter); // Battery Data 2 - transmit_can(&SMA_017, can_config.inverter); // Battery Manufacturer - transmit_can(&SMA_018, can_config.inverter); // Battery Name + transmit_can(&SMA_558, can_config.inverter); //Pairing start - Vendor + transmit_can(&SMA_598, can_config.inverter); //Serial + transmit_can(&SMA_5D8, can_config.inverter); //BYD + transmit_can(&SMA_618_0, can_config.inverter); //BATTERY + transmit_can(&SMA_618_1, can_config.inverter); //-Box Pr + transmit_can(&SMA_618_2, can_config.inverter); //emium H + transmit_can(&SMA_618_3, can_config.inverter); //VS + transmit_can(&SMA_358, can_config.inverter); + transmit_can(&SMA_3D8, can_config.inverter); + transmit_can(&SMA_458, can_config.inverter); + transmit_can(&SMA_4D8, can_config.inverter); + transmit_can(&SMA_518, can_config.inverter); + pairing_completed = true; } void setup_inverter(void) { // Performs one time setup at startup over CAN bus diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index 90967001f..2645efce3 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -4,6 +4,9 @@ #define CAN_INVERTER_SELECTED +#define READY_STATE 0x03 +#define STOP_STATE 0x02 + void send_tripower_init(); void transmit_can(CAN_frame* tx_frame, int interface); void setup_inverter(void); From ab755aa9131f16dc5e7d718c89ed0443eb4231f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 25 Nov 2024 23:17:53 +0200 Subject: [PATCH 017/225] Add missing value mappings --- Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index f6c9ea054..777f1f3ed 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -20,6 +20,8 @@ static uint32_t inverter_time = 0; static uint16_t inverter_voltage = 0; static int16_t inverter_current = 0; static bool pairing_completed = false; +static int16_t temperature_average = 0; +static uint16_t ampere_hours_remaining = 0; //Actual content messages CAN_frame SMA_558 = {.FD = false, //Pairing first message @@ -84,7 +86,15 @@ CAN_frame SMA_518 = {.FD = false, .data = {0x00, 0x96, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00}}; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the inverter CAN + // Update values + temperature_average = + ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); + if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0 + ampere_hours_remaining = + ((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) * + 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) + } //Map values to CAN messages //Maxvoltage (eg 400.0V = 4000 , 16bits long) From b7bc1da2033364057c911b9b8d236edb9f7e9c27 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:41:38 +1300 Subject: [PATCH 018/225] Update TESLA-BATTERY.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 41914455c..f6db10a88 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -345,7 +345,7 @@ void update_values_battery() { //This function maps all the values fetched via #ifdef TESLA_MODEL_3Y_BATTERY // Autodetect algoritm for chemistry on 3/Y packs. - // NCM/A batteries have 96s, LFP has 102-106s + // 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! if (datalayer.battery.info.number_of_cells > 101) { datalayer.battery.info.chemistry = battery_chemistry_enum::LFP; @@ -431,7 +431,7 @@ void update_values_battery() { //This function maps all the values fetched via Serial.print("Real SOC: "); Serial.print(battery_soc_ui / 10.0, 1); print_int_with_units(", Battery voltage: ", battery_volts, "V"); - print_int_with_units(", Battery HV current: ", (battery_amps), "A"); // (battery_amps * 0.1) + print_int_with_units(", Battery HV current: ", (battery_amps * 0.1), "A"); Serial.print(", Fully charged?: "); if (battery_full_charge_complete) Serial.print("YES, "); @@ -552,8 +552,9 @@ void receive_can_battery(CAN_frame rx_frame) { battery_volts = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.01; //0|16@1+ (0.01,0) [0|655.35] "V" //Example 37030mv * 0.01 = 370V battery_amps = - ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * - -0.1; //SmoothBattCurrent : 16|16@1- (-0.1,0) [-3276.7|3276.7] "A" //Example 65492 (-4.3A) OR 225 (22.5A) + ((rx_frame.data.u8[3] << 8) | + rx_frame.data.u8 + [2]); //SmoothBattCurrent : 16|16@1- (-0.1,0) [-3276.7|3276.7] "A"//Example 65492 (-4.3A) OR 225 (22.5A) battery_raw_amps = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * -0.05 + 822; //RawBattCurrent : 32|16@1- (-0.05,822) [-1138.35|2138.4] "A" //Example 10425 * -0.05 = ? From eae05aea517114efb98185d3c06beaf66ea84e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 26 Nov 2024 22:42:17 +0200 Subject: [PATCH 019/225] Add skeleton for Bolt-Ampera battery --- Software/USER_SETTINGS.h | 1 + Software/src/battery/BATTERIES.h | 4 + Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 81 ++++++++++++++++++++ Software/src/battery/BOLT-AMPERA-BATTERY.h | 18 +++++ 4 files changed, 104 insertions(+) create mode 100644 Software/src/battery/BOLT-AMPERA-BATTERY.cpp create mode 100644 Software/src/battery/BOLT-AMPERA-BATTERY.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index e9687df51..3637eea0d 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -11,6 +11,7 @@ /* Select battery used */ //#define BMW_I3_BATTERY //#define BMW_IX_BATTERY +//#define BOLT_AMPERA_BATTERY //#define BYD_ATTO_3_BATTERY //#define CELLPOWER_BMS //#define CHADEMO_BATTERY //NOTE: inherently enables CONTACTOR_CONTROL below diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index e17d1c065..daf5386f9 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -10,6 +10,10 @@ #include "BMW-IX-BATTERY.h" #endif +#ifdef BOLT_AMPERA_BATTERY +#include "BOLT-AMPERA-BATTERY.h" +#endif + #ifdef BYD_ATTO_3_BATTERY #include "BYD-ATTO-3-BATTERY.h" #endif diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp new file mode 100644 index 000000000..a6ecdd796 --- /dev/null +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -0,0 +1,81 @@ +#include "../include.h" +#ifdef BOLT_AMPERA_BATTERY +#include "../datalayer/datalayer.h" +#include "../datalayer/datalayer_extended.h" +#include "../devboard/utils/events.h" +#include "BOLT-AMPERA-BATTERY.h" + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send + +CAN_frame BOLT_778 = {.FD = false, + .ext_ID = false, + .DLC = 7, + .ID = 0x778, + .data = {0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer + + datalayer.battery.status.real_soc; + + datalayer.battery.status.voltage_dV; + + datalayer.battery.status.current_dA; + + datalayer.battery.info.total_capacity_Wh; + + datalayer.battery.status.remaining_capacity_Wh; + + datalayer.battery.status.soh_pptt; + + datalayer.battery.status.max_discharge_power_W; + + datalayer.battery.status.max_charge_power_W; + + datalayer.battery.status.temperature_min_dC; + + datalayer.battery.status.temperature_max_dC; +} + +void receive_can_battery(CAN_frame rx_frame) { + switch (rx_frame.ID) { + case 0x2C7: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x3E3: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + default: + break; + } +} + +void send_can_battery() { + unsigned long currentMillis = millis(); + + //Send 20ms message + if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { + // Check if sending of CAN messages has been delayed too much. + if ((currentMillis - previousMillis20 >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20)); + } else { + clear_event(EVENT_CAN_OVERRUN); + } + previousMillis20 = currentMillis; + transmit_can(&BOLT_778, can_config.battery); + } +} + +void setup_battery(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, "Chevrolet Bolt EV/Opel Ampera-e", 63); + datalayer.system.info.battery_protocol[63] = '\0'; + + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; + datalayer.system.status.battery_allows_contactor_closing = true; +} + +#endif diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.h b/Software/src/battery/BOLT-AMPERA-BATTERY.h new file mode 100644 index 000000000..42d743d59 --- /dev/null +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.h @@ -0,0 +1,18 @@ +#ifndef BOLT_AMPERA_BATTERY_H +#define BOLT_AMPERA_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED + +#define MAX_PACK_VOLTAGE_DV 4150 //5000 = 500.0V +#define MIN_PACK_VOLTAGE_DV 2500 +#define MAX_CELL_DEVIATION_MV 500 +#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value +#define MAX_CHARGE_POWER_W 5000 // Battery can be charged with this amount of power + +void setup_battery(void); +void transmit_can(CAN_frame* tx_frame, int interface); + +#endif From 4232da8aec8e06d5ecf34d77fe0ffe0f8e3f697f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 27 Nov 2024 20:00:16 +0200 Subject: [PATCH 020/225] Feature: Add initial version of CAN logger (#639) * Add initial version of CAN logger --- Software/Software.ino | 49 ++++++++++++++-- Software/src/datalayer/datalayer.h | 5 ++ .../webserver/advanced_battery_html.cpp | 4 ++ .../devboard/webserver/can_logging_html.cpp | 58 +++++++++++++++++++ .../src/devboard/webserver/can_logging_html.h | 16 +++++ .../devboard/webserver/cellmonitor_html.cpp | 4 ++ .../src/devboard/webserver/events_html.cpp | 2 + .../src/devboard/webserver/settings_html.cpp | 4 ++ Software/src/devboard/webserver/webserver.cpp | 46 +++++++++++++++ Software/src/inverter/BYD-MODBUS.h | 2 +- 10 files changed, 184 insertions(+), 6 deletions(-) create mode 100644 Software/src/devboard/webserver/can_logging_html.cpp create mode 100644 Software/src/devboard/webserver/can_logging_html.h diff --git a/Software/Software.ino b/Software/Software.ino index d88ef46bf..721eabde7 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -78,7 +78,7 @@ ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); // ModbusRTU parameters #ifdef MODBUS_INVERTER_SELECTED -#define MB_RTU_NUM_VALUES 30000 +#define MB_RTU_NUM_VALUES 13100 uint16_t mbPV[MB_RTU_NUM_VALUES]; // Process variable memory // Create a ModbusRTU server instance listening on Serial2 with 2000ms timeout ModbusServerRTU MBserver(Serial2, 2000); @@ -623,6 +623,7 @@ void init_equipment_stop_button() { enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 void print_can_frame(CAN_frame frame, frameDirection msgDir); void print_can_frame(CAN_frame frame, frameDirection msgDir) { +#ifdef DEBUG_CAN_DATA // If enabled in user settings, print out the CAN messages via USB uint8_t i = 0; Serial.print(millis()); Serial.print(" "); @@ -637,6 +638,48 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { Serial.print(" "); } Serial.println(" "); +#endif //#DEBUG_CAN_DATA + + if (datalayer.system.info.can_logging_active) { // If user clicked on CAN Logging page in webserver, start recording + + char message_string[128]; // Buffer to hold the message string + int offset = 0; // Keeps track of the current position in the buffer + + // Add timestamp + offset += snprintf(message_string + offset, sizeof(message_string) - offset, "%lu ", millis()); + + // Add direction + offset += + snprintf(message_string + offset, sizeof(message_string) - offset, "%s ", (msgDir == MSG_RX) ? "RX" : "TX"); + + // Add ID and DLC + offset += snprintf(message_string + offset, sizeof(message_string) - offset, "%X %u ", frame.ID, frame.DLC); + + // Add data bytes + for (uint8_t i = 0; i < frame.DLC; i++) { + offset += snprintf(message_string + offset, sizeof(message_string) - offset, "%s%X ", + frame.data.u8[i] < 16 ? "0" : "", frame.data.u8[i]); + } + // Add linebreak + offset += snprintf(message_string + offset, sizeof(message_string) - offset, "\n"); + + // Ensure the string is null-terminated + message_string[sizeof(message_string) - 1] = '\0'; + + // Append the message string to the system info structure + size_t current_len = + strnlen(datalayer.system.info.logged_can_messages, sizeof(datalayer.system.info.logged_can_messages)); + size_t available_space = + sizeof(datalayer.system.info.logged_can_messages) - current_len - 1; // Space left for new data + + if (available_space < strlen(message_string) + 1) { + // Not enough space, reset and start from the beginning + current_len = 0; + datalayer.system.info.logged_can_messages[0] = '\0'; + } + + strncat(datalayer.system.info.logged_can_messages, message_string, available_space); + } } #ifdef CAN_FD @@ -1103,9 +1146,7 @@ void transmit_can(CAN_frame* tx_frame, int interface) { if (!allowed_to_send_CAN) { return; } -#ifdef DEBUG_CAN_DATA print_can_frame(*tx_frame, frameDirection(MSG_TX)); -#endif //DEBUG_CAN_DATA switch (interface) { case CAN_NATIVE: @@ -1160,9 +1201,7 @@ void transmit_can(CAN_frame* tx_frame, int interface) { } void receive_can(CAN_frame* rx_frame, int interface) { -#ifdef DEBUG_CAN_DATA print_can_frame(*rx_frame, frameDirection(MSG_RX)); -#endif //DEBUG_CAN_DATA if (interface == can_config.battery) { receive_can_battery(*rx_frame); diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index dcf75b7b2..818143368 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -131,6 +131,11 @@ typedef struct { char battery_protocol[64] = {0}; /** array with type of inverter used, for displaying on webserver */ char inverter_protocol[64] = {0}; + /** array with incoming CAN messages, for displaying on webserver */ + char logged_can_messages[15000] = {0}; + /** bool, determines if CAN messages should be logged for webserver */ + bool can_logging_active = false; + } DATALAYER_SYSTEM_INFO_TYPE; typedef struct { diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 9404b36fd..b3cba77f5 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -9,6 +9,10 @@ String advanced_battery_processor(const String& var) { //Page format content += ""; content += ""; diff --git a/Software/src/devboard/webserver/can_logging_html.cpp b/Software/src/devboard/webserver/can_logging_html.cpp new file mode 100644 index 000000000..59f038239 --- /dev/null +++ b/Software/src/devboard/webserver/can_logging_html.cpp @@ -0,0 +1,58 @@ +#include "can_logging_html.h" +#include +#include "../../datalayer/datalayer.h" + +String can_logger_processor(const String& var) { + if (var == "X") { + datalayer.system.info.can_logging_active = + true; // Signal to main loop that we should log messages. Disabled by default for performance reasons + String content = ""; + // Page format + content += ""; + content += " "; + content += " "; + content += ""; + + // Start a new block for the CAN messages + content += "
"; + + // Check for messages + if (datalayer.system.info.logged_can_messages[0] == 0) { + content += "CAN logger started! Refresh page to display incoming(RX) and outgoing(TX) messages"; + } else { + // Split the messages using the newline character + String messages = String(datalayer.system.info.logged_can_messages); + int startIndex = 0; + int endIndex = messages.indexOf('\n'); + while (endIndex != -1) { + // Extract a single message and wrap it in a styled div + String singleMessage = messages.substring(startIndex, endIndex); + content += "
" + singleMessage + "
"; + startIndex = endIndex + 1; // Move past the newline character + endIndex = messages.indexOf('\n', startIndex); + } + } + + content += "
"; + + // Add JavaScript for navigation + content += ""; + return content; + } + return String(); +} diff --git a/Software/src/devboard/webserver/can_logging_html.h b/Software/src/devboard/webserver/can_logging_html.h new file mode 100644 index 000000000..f208c3fff --- /dev/null +++ b/Software/src/devboard/webserver/can_logging_html.h @@ -0,0 +1,16 @@ +#ifndef CANLOGGER_H +#define CANLOGGER_H + +#include +#include + +/** + * @brief Replaces placeholder with content section in web page + * + * @param[in] var + * + * @return String + */ +String can_logger_processor(const String& var); + +#endif diff --git a/Software/src/devboard/webserver/cellmonitor_html.cpp b/Software/src/devboard/webserver/cellmonitor_html.cpp index 21a5c1df5..f37f5d9d0 100644 --- a/Software/src/devboard/webserver/cellmonitor_html.cpp +++ b/Software/src/devboard/webserver/cellmonitor_html.cpp @@ -8,6 +8,10 @@ String cellmonitor_processor(const String& var) { // Page format content += " diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index caac64d40..484e50210 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -8,6 +8,10 @@ String settings_processor(const String& var) { //Page format content += ""; content += ""; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 360787d2c..227dee8c4 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -1,5 +1,6 @@ #include "webserver.h" #include +#include #include "../../datalayer/datalayer.h" #include "../../datalayer/datalayer_extended.h" #include "../../lib/bblanchon-ArduinoJson/ArduinoJson.h" @@ -14,6 +15,7 @@ AsyncWebServer server(80); unsigned long ota_progress_millis = 0; #include "advanced_battery_html.h" +#include "can_logging_html.h" #include "cellmonitor_html.h" #include "events_html.h" #include "index_html.cpp" @@ -56,6 +58,44 @@ void init_webserver() { request->send_P(200, "text/html", index_html, advanced_battery_processor); }); + // Route for going to CAN logging web page + server.on("/canlog", HTTP_GET, [](AsyncWebServerRequest* request) { + request->send_P(200, "text/html", index_html, can_logger_processor); + }); + + // Define the handler to stop logging + server.on("/stop_logging", HTTP_GET, [](AsyncWebServerRequest* request) { + datalayer.system.info.can_logging_active = false; + request->send_P(200, "text/plain", "Logging stopped"); + }); + + // Define the handler to export logs + server.on("/export_logs", HTTP_GET, [](AsyncWebServerRequest* request) { + String logs = String(datalayer.system.info.logged_can_messages); + if (logs.length() == 0) { + logs = "No logs available."; + } + + // Get the current time + time_t now = time(nullptr); + struct tm timeinfo; + localtime_r(&now, &timeinfo); + + // Ensure time retrieval was successful + char filename[32]; + if (strftime(filename, sizeof(filename), "canlog_%H-%M-%S.txt", &timeinfo)) { + // Valid filename created + } else { + // Fallback filename if automatic timestamping failed + strcpy(filename, "battery_emulator_can_log.txt"); + } + + // Use request->send with dynamic headers + AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", logs); + response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\""); + request->send(response); + }); + // Route for going to cellmonitor web page server.on("/cellmonitor", HTTP_GET, [](AsyncWebServerRequest* request) { if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) @@ -443,6 +483,10 @@ String processor(const String& var) { //Page format content += ""; // Start a new block with a specific background color @@ -874,6 +918,7 @@ String processor(const String& var) { content += " "; content += " "; content += " "; + content += " "; content += " "; content += " "; content += ""; @@ -898,6 +943,7 @@ String processor(const String& var) { content += "function Cellmon() { window.location.href = '/cellmonitor'; }"; content += "function Settings() { window.location.href = '/settings'; }"; content += "function Advanced() { window.location.href = '/advanced'; }"; + content += "function CANlog() { window.location.href = '/canlog'; }"; content += "function Events() { window.location.href = '/events'; }"; content += "function askReboot() { if (window.confirm('Are you sure you want to reboot the emulator? NOTE: If " diff --git a/Software/src/inverter/BYD-MODBUS.h b/Software/src/inverter/BYD-MODBUS.h index 487c97847..d13266093 100644 --- a/Software/src/inverter/BYD-MODBUS.h +++ b/Software/src/inverter/BYD-MODBUS.h @@ -4,7 +4,7 @@ #define MODBUS_INVERTER_SELECTED -#define MB_RTU_NUM_VALUES 30000 +#define MB_RTU_NUM_VALUES 13100 #define MAX_POWER 40960 //BYD Modbus specific value extern uint16_t mbPV[MB_RTU_NUM_VALUES]; From d411b0a875812da642fb23d188734d807818f8b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 1 Dec 2024 14:40:19 +0200 Subject: [PATCH 021/225] Change enable line logic --- Software/Software.ino | 11 +---------- Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 5 ++++- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index cd09171aa..5374625a0 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -545,10 +545,6 @@ void init_contactors() { pinMode(BMS_POWER, OUTPUT); digitalWrite(BMS_POWER, HIGH); #endif //HW_STARK -#ifdef SMA_TRIPOWER_CAN - //pinMode(INVERTER_CONTACTOR_ENABLE_PIN, OUTPUT); //Incase this is an output - //digitalWrite(INVERTER_CONTACTOR_ENABLE_PIN, LOW); //Incase this is an output -#endif //SMA_TRIPOWER_CAN } void init_rs485() { @@ -743,14 +739,9 @@ void check_interconnect_available() { #endif //DOUBLE_BATTERY void handle_contactors() { -#ifdef BYD_SMA +#if defined(BYD_SMA) || defined(SMA_TRIPOWER_CAN) datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); #endif -#ifdef SMA_TRIPOWER_CAN - //set(INVERTER_CONTACTOR_ENABLE_PIN, ON); //TODO: is this an input, or an output? Figure out and make logic - datalayer.system.status.inverter_allows_contactor_closing = - digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); //Incase it is input -#endif #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY handle_contactors_battery2(); diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 777f1f3ed..1296cbe7d 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -171,7 +171,10 @@ void receive_can_inverter(CAN_frame rx_frame) { void send_can_inverter() { unsigned long currentMillis = millis(); - //TODO, should we break before pairing_completed? Or rely on Enable line? + // Send CAN Message only if we're enabled by inverter + if (!datalayer.system.status.inverter_allows_contactor_closing) { + return; + } // Send CAN Message every 2s if (currentMillis - previousMillis2s >= INTERVAL_2_S) { From 4e66ffcd385b3e50c4b646c7798130b9a3518ef8 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Mon, 2 Dec 2024 01:28:37 +0900 Subject: [PATCH 022/225] docs: update README.md (#649) compability -> compatibility --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f5ad6aa52..e486e2a18 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This software enables EV battery packs to be used for stationary storage. It ach ## Hardware requirements 📜 This code fits on the LilyGo ESP32 T-CAN485 devboard , see https://github.com/Xinyuan-LilyGO/T-CAN485 -You will also need a complete EV battery. [See the battery compability list on which are supported.](https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki#supported-batteries-list) +You will also need a complete EV battery. [See the battery compatibility list on which are supported.](https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki#supported-batteries-list) Finally, you will need a [compatible hybrid solar inverter](https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki#supported-inverters-list), for example the "Fronius Gen24" or "GoodWe ET" From 0750c6ab5b4bd30f4db4a1e72cc17940275cc6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 2 Dec 2024 18:39:57 +0200 Subject: [PATCH 023/225] Feature: Volkswagen MEB platform support (#405) * Add MEB Support Co-authored-by: mvgalen --- .github/workflows/compile-all-batteries.yml | 1 + Software/Software.ino | 27 +- Software/USER_SETTINGS.h | 1 + Software/src/battery/BATTERIES.h | 4 + Software/src/battery/MEB-BATTERY.cpp | 2107 +++++++++++++++++ Software/src/battery/MEB-BATTERY.h | 138 ++ Software/src/datalayer/datalayer_extended.h | 73 + Software/src/devboard/safety/safety.cpp | 4 +- Software/src/devboard/utils/events.cpp | 3 + Software/src/devboard/utils/events.h | 1 + Software/src/devboard/utils/types.h | 2 + .../webserver/advanced_battery_html.cpp | 204 +- .../src/devboard/webserver/events_html.cpp | 2 +- 13 files changed, 2551 insertions(+), 16 deletions(-) create mode 100644 Software/src/battery/MEB-BATTERY.cpp create mode 100644 Software/src/battery/MEB-BATTERY.h diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index 287b75f24..7f95c73de 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -43,6 +43,7 @@ jobs: - KIA_HYUNDAI_64_BATTERY - KIA_E_GMP_BATTERY - KIA_HYUNDAI_HYBRID_BATTERY + - MEB_BATTERY - MG_5_BATTERY - NISSAN_LEAF_BATTERY - PYLON_BATTERY diff --git a/Software/Software.ino b/Software/Software.ino index 721eabde7..1994978f4 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -625,19 +625,20 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir); void print_can_frame(CAN_frame frame, frameDirection msgDir) { #ifdef DEBUG_CAN_DATA // If enabled in user settings, print out the CAN messages via USB uint8_t i = 0; - Serial.print(millis()); - Serial.print(" "); - (msgDir == 0) ? Serial.print("RX ") : Serial.print("TX "); + Serial.print("("); + Serial.print(millis() / 1000.0); + (msgDir == MSG_RX) ? Serial.print(") RX0 ") : Serial.print(") TX1 "); Serial.print(frame.ID, HEX); - Serial.print(" "); + Serial.print(" ["); Serial.print(frame.DLC); - Serial.print(" "); + Serial.print("] "); for (i = 0; i < frame.DLC; i++) { Serial.print(frame.data.u8[i] < 16 ? "0" : ""); Serial.print(frame.data.u8[i], HEX); - Serial.print(" "); + if (i < frame.DLC - 1) + Serial.print(" "); } - Serial.println(" "); + Serial.println(""); #endif //#DEBUG_CAN_DATA if (datalayer.system.info.can_logging_active) { // If user clicked on CAN Logging page in webserver, start recording @@ -686,16 +687,15 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { // Functions void receive_canfd() { // This section checks if we have a complete CAN-FD message incoming CANFDMessage frame; - if (canfd.available()) { + int count = 0; + while (canfd.available() && count++ < 16) { canfd.receive(frame); CAN_frame rx_frame; rx_frame.ID = frame.id; rx_frame.ext_ID = frame.ext; rx_frame.DLC = frame.len; - for (uint8_t i = 0; i < rx_frame.DLC && i < 64; i++) { - rx_frame.data.u8[i] = frame.data[i]; - } + memcpy(rx_frame.data.u8, frame.data, MIN(rx_frame.DLC, 64)); //message incoming, pass it on to the handler receive_can(&rx_frame, CAN_ADDON_FD_MCP2518); receive_can(&rx_frame, CANFD_NATIVE); @@ -1180,6 +1180,11 @@ void transmit_can(CAN_frame* tx_frame, int interface) { case CAN_ADDON_FD_MCP2518: { #ifdef CAN_FD CANFDMessage MCP2518Frame; + if (tx_frame->FD) { + MCP2518Frame.type = CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH; + } else { //Classic CAN message + MCP2518Frame.type = CANFDMessage::CAN_DATA; + } MCP2518Frame.id = tx_frame->ID; MCP2518Frame.ext = tx_frame->ext_ID ? CAN_frame_ext : CAN_frame_std; MCP2518Frame.len = tx_frame->DLC; diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index e9687df51..c846aa095 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -19,6 +19,7 @@ //#define KIA_HYUNDAI_64_BATTERY //#define KIA_E_GMP_BATTERY //#define KIA_HYUNDAI_HYBRID_BATTERY +//#define MEB_BATTERY //#define MG_5_BATTERY //#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index e17d1c065..c2c0bdac0 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -43,6 +43,10 @@ #include "KIA-HYUNDAI-HYBRID-BATTERY.h" #endif +#ifdef MEB_BATTERY +#include "MEB-BATTERY.h" +#endif + #ifdef MG_5_BATTERY #include "MG-5-BATTERY.h" #endif diff --git a/Software/src/battery/MEB-BATTERY.cpp b/Software/src/battery/MEB-BATTERY.cpp new file mode 100644 index 000000000..c6dc918cb --- /dev/null +++ b/Software/src/battery/MEB-BATTERY.cpp @@ -0,0 +1,2107 @@ +#include "../include.h" +#ifdef MEB_BATTERY +#include // For std::min and std::max +#include "../datalayer/datalayer.h" +#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage +#include "../devboard/utils/events.h" +#include "MEB-BATTERY.h" + +/* +TODO list +- Get contactors closing +- What CAN messages needs to be sent towards the battery to keep it alive +- Check value mappings on the PID polls +- Check value mappings on the constantly broadcasted messages +- Check all TODO:s in the code +- 0x1B000044 & 1B00008F seems to be missing from logs? (Classic CAN) +*/ + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis10ms = 0; // will store last time a 10ms CAN Message was send +static unsigned long previousMillis20ms = 0; // will store last time a 20ms CAN Message was send +static unsigned long previousMillis40ms = 0; // will store last time a 40ms CAN Message was send +static unsigned long previousMillis50ms = 0; // will store last time a 50ms CAN Message was send +static unsigned long previousMillis100ms = 0; // will store last time a 100ms CAN Message was send +static unsigned long previousMillis200ms = 0; // will store last time a 200ms CAN Message was send +static unsigned long previousMillis500ms = 0; // will store last time a 200ms CAN Message was send +static unsigned long previousMillis1s = 0; // will store last time a 1s CAN Message was send + +static bool toggle = false; +static uint8_t counter_1000ms = 0; +static uint8_t counter_200ms = 0; +static uint8_t counter_100ms = 0; +static uint8_t counter_50ms = 0; +static uint8_t counter_40ms = 0; +static uint8_t counter_20ms = 0; +static uint8_t counter_10ms = 0; +static uint8_t counter_040 = 0; +static uint8_t counter_0F7 = 0; +static uint8_t counter_3b5 = 0; + +static uint32_t poll_pid = 0; +static uint32_t pid_reply = 0; +static uint16_t battery_soc_polled = 0; +static uint16_t battery_voltage_polled = 1480; +static int16_t battery_current_polled = 0; +static int16_t battery_max_temp = 600; +static int16_t battery_min_temp = 600; +static uint16_t battery_max_charge_voltage = 0; +static uint16_t battery_min_discharge_voltage = 0; +static uint16_t battery_allowed_charge_power = 0; +static uint16_t battery_allowed_discharge_power = 0; +static uint16_t cellvoltages_polled[108]; +static uint16_t tempval = 0; +static uint8_t BMS_5A2_CRC = 0; +static uint8_t BMS_5CA_CRC = 0; +static uint8_t BMS_0CF_CRC = 0; +static uint8_t BMS_578_CRC = 0; +static uint8_t BMS_0C0_CRC = 0; +static uint8_t BMS_16A954A6_CRC = 0; +static uint8_t BMS_5A2_counter = 0; +static uint8_t BMS_5CA_counter = 0; +static uint8_t BMS_0CF_counter = 0; +static uint8_t BMS_0C0_counter = 0; +static uint8_t BMS_578_counter = 0; +static uint8_t BMS_16A954A6_counter = 0; +static bool BMS_ext_limits_active = + false; //The current current limits of the HV battery are expanded to start the combustion engine / confirmation of the request +static uint8_t BMS_mode = + 0x07; //0: standby; Gates open; Communication active 1: Main contactor closed / HV network activated / normal driving operation +//2: assigned depending on the project (e.g. balancing, extended DC fast charging) //3: external charging +static uint8_t BMS_HVIL_status = 0; //0 init, 1 seated, 2 open, 3 fault +static bool BMS_fault_performance = false; //Error: Battery performance is limited (e.g. due to sensor or fan failure) +static uint16_t BMS_current = 16300; +static bool BMS_fault_emergency_shutdown_crash = + false; //Error: Safety-critical error (crash detection) Battery contactors are already opened / will be opened immediately Signal is read directly by the EMS and initiates an AKS of the PWR and an active discharge of the DC link +static uint32_t BMS_voltage_intermediate = 0; +static uint32_t BMS_voltage = 0; +static uint8_t BMS_status_voltage_free = + 0; //0=Init, 1=BMS intermediate circuit voltage-free (U_Zwkr < 20V), 2=BMS intermediate circuit not voltage-free (U_Zwkr >/= 25V, hysteresis), 3=Error +static bool BMS_OBD_MIL = false; +static uint8_t BMS_error_status = + 0x7; //0 Component_IO, 1 Restricted_CompFkt_Isoerror_I, 2 Restricted_CompFkt_Isoerror_II, 3 Restricted_CompFkt_Interlock, 4 Restricted_CompFkt_SD, 5 Restricted_CompFkt_Performance red, 6 = No component function, 7 = Init +static uint16_t BMS_capacity_ah = 0; +static bool BMS_error_lamp_req = false; +static bool BMS_warning_lamp_req = false; +static uint8_t BMS_Kl30c_Status = 0; // 0 init, 1 closed, 2 open, 3 fault +static bool service_disconnect_switch_missing = false; +static bool pilotline_open = false; +static bool balancing_request = false; +static uint8_t battery_diagnostic = 0; +static uint16_t battery_Wh_left = 0; +static uint16_t battery_Wh_max = 1000; +static uint8_t battery_potential_status = 0; +static uint8_t battery_temperature_warning = 0; +static uint16_t max_discharge_power_watt = 0; +static uint16_t max_discharge_current_amp = 0; +static uint16_t max_charge_power_watt = 0; +static uint16_t max_charge_current_amp = 0; +static uint16_t battery_SOC = 0; +static uint16_t usable_energy_amount_Wh = 0; +static uint8_t status_HV_line = 0; //0 init, 1 No open HV line, 2 open HV line detected, 3 fault +static uint8_t warning_support = 0; +static bool battery_heating_active = false; +static uint16_t power_discharge_percentage = 0; +static uint16_t power_charge_percentage = 0; +static uint16_t actual_battery_voltage = 0; +static uint16_t regen_battery = 0; +static uint16_t energy_extracted_from_battery = 0; +static uint16_t max_fastcharging_current_amp = 0; //maximum DC charging current allowed +static uint8_t BMS_Status_DCLS = + 0; //Status of the voltage monitoring on the DC charging interface. 0 inactive, 1 I_O , 2 N_I_O , 3 active +static uint16_t DC_voltage_DCLS = + 0; //Factor 1, DC voltage of the charging station. Measurement between the DC HV lines. +static uint16_t DC_voltage_chargeport = + 0; //Factor 0.5, Current voltage at the HV battery DC charging terminals; Outlet to the DC charging plug. +static uint8_t BMS_welded_contactors_status = + 0; //0: Init no diagnostic result, 1: no contactor welded, 2: at least 1 contactor welded, 3: Protection status detection error +static bool BMS_error_shutdown_request = + false; // Fault: Fault condition, requires battery contactors to be opened internal battery error; Advance notification of an impending opening of the battery contactors by the BMS +static bool BMS_error_shutdown = + false; // Fault: Fault condition, requires battery contactors to be opened Internal battery error, battery contactors opened without notice by the BMS +static uint16_t power_battery_heating_watt = 0; +static uint16_t power_battery_heating_req_watt = 0; +static uint8_t cooling_request = + 0; //0 = No cooling, 1 = Light cooling, cabin prio, 2= higher cooling, 3 = immediate cooling, 4 = emergency cooling +static uint8_t heating_request = 0; //0 = init, 1= maintain temp, 2=higher demand, 3 = immediate heat demand +static uint8_t balancing_active = false; //0 = init, 1 active, 2 not active +static bool charging_active = false; +static uint16_t max_energy_Wh = 0; +static uint16_t max_charge_percent = 0; +static uint16_t min_charge_percent = 0; +static uint16_t isolation_resistance_kOhm = 0; +static bool battery_heating_installed = false; +static bool error_NT_circuit = false; +static uint8_t pump_1_control = 0; //0x0D not installed, 0x0E init, 0x0F fault +static uint8_t pump_2_control = 0; //0x0D not installed, 0x0E init, 0x0F fault +static uint8_t target_flow_temperature_C = 0; //*0,5 -40 +static uint8_t return_temperature_C = 0; //*0,5 -40 +static uint8_t status_valve_1 = 0; //0 not active, 1 active, 5 not installed, 6 init, 7 fault +static uint8_t status_valve_2 = 0; //0 not active, 1 active, 5 not installed, 6 init, 7 fault +static uint8_t battery_temperature = 0; +static uint8_t temperature_request = + 0; //0 high cooling, 1 medium cooling, 2 low cooling, 3 no temp requirement init, 4 low heating , 5 medium heating, 6 high heating, 7 circulation +static uint16_t performance_index_discharge_peak_temperature_percentage = 0; +static uint16_t performance_index_charge_peak_temperature_percentage = 0; +static uint8_t temperature_status_discharge = + 0; //0 init, 1 temp under optimal, 2 temp optimal, 3 temp over optimal, 7 fault +static uint8_t temperature_status_charge = + 0; //0 init, 1 temp under optimal, 2 temp optimal, 3 temp over optimal, 7 fault +static uint8_t isolation_fault = + 0; //0 init, 1 no iso fault, 2 iso fault threshold1, 3 iso fault threshold2, 4 IWU defective +static uint8_t isolation_status = + 0; // 0 init, 1 = larger threshold1, 2 = smaller threshold1 total, 3 = smaller threshold1 intern, 4 = smaller threshold2 total, 5 = smaller threshold2 intern, 6 = no measurement, 7 = measurement active +static uint8_t actual_temperature_highest_C = 0; //*0,5 -40 +static uint8_t actual_temperature_lowest_C = 0; //*0,5 -40 +static uint16_t actual_cellvoltage_highest_mV = 0; //bias 1000 +static uint16_t actual_cellvoltage_lowest_mV = 0; //bias 1000 +static uint16_t predicted_power_dyn_standard_watt = 0; +static uint8_t predicted_time_dyn_standard_minutes = 0; +static uint8_t mux = 0; +static int8_t celltemperature[56] = {0}; //Temperatures 1-56. Value is 0xFD if sensor not present +static uint16_t cellvoltages[160] = {0}; +static uint16_t duration_discharge_power_watt = 0; +static uint16_t duration_charge_power_watt = 0; +static uint16_t maximum_voltage = 0; +static uint16_t minimum_voltage = 0; +static uint8_t battery_serialnumber[26]; +static uint8_t realtime_overcurrent_monitor = 0; +static uint8_t realtime_CAN_communication_fault = 0; +static uint8_t realtime_overcharge_warning = 0; +static uint8_t realtime_SOC_too_high = 0; +static uint8_t realtime_SOC_too_low = 0; +static uint8_t realtime_SOC_jumping_warning = 0; +static uint8_t realtime_temperature_difference_warning = 0; +static uint8_t realtime_cell_overtemperature_warning = 0; +static uint8_t realtime_cell_undertemperature_warning = 0; +static uint8_t realtime_battery_overvoltage_warning = 0; +static uint8_t realtime_battery_undervoltage_warning = 0; +static uint8_t realtime_cell_overvoltage_warning = 0; +static uint8_t realtime_cell_undervoltage_warning = 0; +static uint8_t realtime_cell_imbalance_warning = 0; +static uint8_t realtime_warning_battery_unathorized = 0; +static bool component_protection_active = false; +static bool shutdown_active = false; +static bool transportation_mode_active = false; +static uint8_t KL15_mode = 0; +static uint8_t bus_knockout_timer = 0; +static uint8_t hybrid_wakeup_reason = 0; +static uint8_t wakeup_type = 0; +static bool instrumentation_cluster_request = false; +static uint8_t seconds = 0; +static uint32_t first_can_msg = 0; +static uint32_t last_can_msg_timestamp = 0; + +#define TIME_YEAR 2024 +#define TIME_MONTH 8 +#define TIME_DAY 20 +#define TIME_HOUR 10 +#define TIME_MINUTE 5 +#define TIME_SECOND 0 + +#define BMS_TARGET_HV_OFF 0 +#define BMS_TARGET_HV_ON 1 +#define BMS_TARGET_AC_CHARGING_EXT 3 //(HS + AC_2 contactors closed) +#define BMS_TARGET_AC_CHARGING 4 //(HS + AC contactors closed) +#define BMS_TARGET_DC_CHARGING 6 //(HS + DC contactors closed) +#define BMS_TARGET_INIT 7 + +#define DC_FASTCHARGE_NO_START_REQUEST 0x00 +#define DC_FASTCHARGE_VEHICLE 0x40 +#define DC_FASTCHARGE_LS1 0x80 +#define DC_FASTCHARGE_LS2 0xC0 + +CAN_frame MEB_POLLING_FRAME = {.FD = true, + .ext_ID = true, + .DLC = 8, + .ID = 0x1C40007B, // SOC 02 8C + .data = {0x03, 0x22, 0x02, 0x8C, 0x55, 0x55, 0x55, 0x55}}; +CAN_frame MEB_ACK_FRAME = {.FD = true, + .ext_ID = true, + .DLC = 8, + .ID = 0x1C40007B, // Ack + .data = {0x30, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55}}; +//Messages needed for contactor closing +CAN_frame MEB_040 = {.FD = true, // Airbag + .ext_ID = false, + .DLC = 8, + .ID = 0x040, //Frame5 has HV deactivate request. Needs to be 0x00 + .data = {0x7E, 0x83, 0x00, 0x01, 0x00, 0x00, 0x15, 0x00}}; +CAN_frame MEB_0C0 = { + .FD = true, // EM1 message + .ext_ID = false, + .DLC = 32, + .ID = 0x0C0, //Frame 5-6 and maybe 7-8 important (external voltage at inverter) + .data = {0x77, 0x0A, 0xFE, 0xE7, 0x7F, 0x10, 0x27, 0x00, 0xE0, 0x7F, 0xFF, 0xF3, 0x3F, 0xFF, 0xF3, 0x3F, + 0xFC, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame MEB_0FC = { + .FD = true, // + .ext_ID = false, + .DLC = 48, + .ID = 0x0FC, //This message contains emergency regen request?(byte19), battery needs to see this message + .data = {0x07, 0x08, 0x00, 0x00, 0x7E, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF4, 0x01, 0x40, 0xFF, 0xEB, 0x7F, 0x0A, 0x88, 0xE3, 0x81, 0xAF, 0x42}}; +CAN_frame MEB_6B2 = {.FD = true, // Diagnostics + .ext_ID = false, + .DLC = 8, + .ID = 0x6B2, + .data = {0x6A, 0xA7, 0x37, 0x80, 0xC9, 0xBD, 0xF6, 0xC2}}; +CAN_frame MEB_17FC007B_poll = {.FD = true, // Non period request + .ext_ID = true, + .DLC = 8, + .ID = 0x17FC007B, + .data = {0x03, 0x22, 0x1E, 0x3D, 0x55, 0x55, 0x55, 0x55}}; +CAN_frame MEB_1A5555A6 = {.FD = true, + .ext_ID = true, + .DLC = 8, + .ID = 0x1A5555A6, + .data = {0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame MEB_585 = { + .FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x585, + .data = {0xCF, 0x38, 0xAF, 0x5B, 0x25, 0x00, 0x00, 0x00}}; // CF 38 AF 5B 25 00 00 00 in start4.log +// .data = {0xCF, 0x38, 0x20, 0x02, 0x25, 0xF7, 0x30, 0x00}}; // CF 38 AF 5B 25 00 00 00 in start4.log +CAN_frame MEB_5F5 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x5F5, + .data = {0x23, 0x02, 0x39, 0xC0, 0x1B, 0x8B, 0xC8, 0x1B}}; +CAN_frame MEB_641 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x641, + .data = {0x37, 0x18, 0x00, 0x00, 0xF0, 0x00, 0xAA, 0x70}}; +CAN_frame MEB_3C0 = {.FD = true, + .ext_ID = false, + .DLC = 4, + .ID = 0x3C0, + .data = {0x66, 0x00, 0x00, 0x00}}; // Klemmen_status_01 +CAN_frame MEB_0FD = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x0FD, //CRC and counter, otherwise static + .data = {0x5F, 0xD0, 0x1F, 0x81, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame MEB_16A954FB = {.FD = true, + .ext_ID = true, + .DLC = 8, + .ID = 0x16A954FB, + .data = {0x00, 0xC0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame MEB_1A555548 = {.FD = true, + .ext_ID = true, + .DLC = 8, + .ID = 0x1A555548, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame MEB_1A55552B = {.FD = true, + .ext_ID = true, + .DLC = 8, + .ID = 0x1A55552B, + .data = {0x00, 0x00, 0x00, 0xA0, 0x02, 0x04, 0x00, 0x30}}; +CAN_frame MEB_569 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x569, //HVEM + .data = {0x00, 0x00, 0x01, 0x3A, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame MEB_16A954B4 = {.FD = true, + .ext_ID = true, + .DLC = 8, + .ID = 0x16A954B4, //eTM + .data = {0xFE, 0xB6, 0x0D, 0x00, 0x00, 0xD5, 0x48, 0xFD}}; +CAN_frame MEB_1B000046 = {.FD = false, // Not FD + .ext_ID = true, + .DLC = 8, + .ID = 0x1B000046, // Klima + .data = {0x00, 0x40, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame MEB_1B000010 = {.FD = false, // Not FD + .ext_ID = true, + .DLC = 8, + .ID = 0x1B000010, // Gateway + .data = {0x00, 0x50, 0x08, 0x50, 0x01, 0xFF, 0x30, 0x00}}; +CAN_frame MEB_1B0000B9 = {.FD = false, // Not FD + .ext_ID = true, + .DLC = 8, + .ID = 0x1B0000B9, //DC/DC converter + .data = {0x00, 0x40, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame MEB_153 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x153, // Static content + .data = {0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFE, 0xFF, 0xFF}}; +CAN_frame MEB_5E1 = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x5E1, // Static content + .data = {0x7F, 0x2A, 0x00, 0x60, 0xFE, 0x00, 0x00, 0x00}}; +CAN_frame MEB_3BE = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x3BE, // CRC, otherwise Static content + .data = {0x57, 0x0D, 0x00, 0x00, 0x00, 0x02, 0x04, 0x40}}; +CAN_frame MEB_272 = {.FD = true, //HVLM_14 + .ext_ID = false, + .DLC = 8, + .ID = 0x272, // Static content + .data = {0x00, 0x00, 0x00, 0x00, 0x48, 0x08, 0x00, 0x94}}; +CAN_frame MEB_503 = {.FD = true, //HVK_01 + .ext_ID = false, + .DLC = 8, + .ID = 0x503, // Content varies. Frame1 & 3 has HV req + .data = {0x5D, 0x61, 0x00, 0xFF, 0x7F, 0x80, 0xE3, 0x03}}; +CAN_frame MEB_14C = { + .FD = true, //Motor message + .ext_ID = false, + .DLC = 32, + .ID = 0x14C, //CRC needed, static content otherwise + .data = {0x38, 0x0A, 0xFF, 0x01, 0x01, 0xFF, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, + 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x25, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE}}; +/** Calculate the CRC checksum for VAG CAN Messages + * + * The method used is described in Chapter "7.2.1.2 8-bit 0x2F polynomial CRC Calculation". + * CRC Parameters: + * 0x2F - Polynomial + * 0xFF - Initial Value + * 0xFF - XOR Output + * + * @see https://github.com/crasbe/VW-OnBoard-Charger + * @see https://github.com/colinoflynn/crcbeagle for CRC hacking :) + * @see https://github.com/commaai/opendbc/blob/master/can/common.cc#L110 + * @see https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_CRCLibrary.pdf + * @see https://web.archive.org/web/20221105210302/https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_CRCLibrary.pdf + */ +uint8_t vw_crc_calc(uint8_t* inputBytes, uint8_t length, uint16_t address) { + + const uint8_t poly = 0x2F; + const uint8_t xor_output = 0xFF; + // VAG Magic Bytes + const uint8_t MB0040[16] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; + const uint8_t MB00C0[16] = {0x2f, 0x44, 0x72, 0xd3, 0x07, 0xf2, 0x39, 0x09, + 0x8d, 0x6f, 0x57, 0x20, 0x37, 0xf9, 0x9b, 0xfa}; + const uint8_t MB00FC[16] = {0x77, 0x5c, 0xa0, 0x89, 0x4b, 0x7c, 0xbb, 0xd6, + 0x1f, 0x6c, 0x4f, 0xf6, 0x20, 0x2b, 0x43, 0xdd}; + const uint8_t MB00FD[16] = {0xb4, 0xef, 0xf8, 0x49, 0x1e, 0xe5, 0xc2, 0xc0, + 0x97, 0x19, 0x3c, 0xc9, 0xf1, 0x98, 0xd6, 0x61}; + const uint8_t MB0097[16] = {0x3C, 0x54, 0xCF, 0xA3, 0x81, 0x93, 0x0B, 0xC7, + 0x3E, 0xDF, 0x1C, 0xB0, 0xA7, 0x25, 0xD3, 0xD8}; + const uint8_t MB00F7[16] = {0x5F, 0xA0, 0x44, 0xD0, 0x63, 0x59, 0x5B, 0xA2, + 0x68, 0x04, 0x90, 0x87, 0x52, 0x12, 0xB4, 0x9E}; + const uint8_t MB0124[16] = {0x12, 0x7E, 0x34, 0x16, 0x25, 0x8F, 0x8E, 0x35, + 0xBA, 0x7F, 0xEA, 0x59, 0x4C, 0xF0, 0x88, 0x15}; + const uint8_t MB0153[16] = {0x03, 0x13, 0x23, 0x7a, 0x40, 0x51, 0x68, 0xba, + 0xa8, 0xbe, 0x55, 0x02, 0x11, 0x31, 0x76, 0xec}; + const uint8_t MB014C[16] = {0x16, 0x35, 0x59, 0x15, 0x9a, 0x2a, 0x97, 0xb8, + 0x0e, 0x4e, 0x30, 0xcc, 0xb3, 0x07, 0x01, 0xad}; + const uint8_t MB0187[16] = {0x7F, 0xED, 0x17, 0xC2, 0x7C, 0xEB, 0x44, 0x21, + 0x01, 0xFA, 0xDB, 0x15, 0x4A, 0x6B, 0x23, 0x05}; + const uint8_t MB03A6[16] = {0xB6, 0x1C, 0xC1, 0x23, 0x6D, 0x8B, 0x0C, 0x51, + 0x38, 0x32, 0x24, 0xA8, 0x3F, 0x3A, 0xA4, 0x02}; + const uint8_t MB03AF[16] = {0x94, 0x6A, 0xB5, 0x38, 0x8A, 0xB4, 0xAB, 0x27, + 0xCB, 0x22, 0x88, 0xEF, 0xA3, 0xE1, 0xD0, 0xBB}; + const uint8_t MB03BE[16] = {0x1f, 0x28, 0xc6, 0x85, 0xe6, 0xf8, 0xb0, 0x19, + 0x5b, 0x64, 0x35, 0x21, 0xe4, 0xf7, 0x9c, 0x24}; + const uint8_t MB03C0[16] = {0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}; + const uint8_t MB0503[16] = {0xed, 0xd6, 0x96, 0x63, 0xa5, 0x12, 0xd5, 0x9a, + 0x1e, 0x0d, 0x24, 0xcd, 0x8c, 0xa6, 0x2f, 0x41}; + const uint8_t MB0578[16] = {0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48}; + const uint8_t MB05CA[16] = {0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43}; + const uint8_t MB0641[16] = {0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47}; + const uint8_t MB06A3[16] = {0xC1, 0x8B, 0x38, 0xA8, 0xA4, 0x27, 0xEB, 0xC8, + 0xEF, 0x05, 0x9A, 0xBB, 0x39, 0xF7, 0x80, 0xA7}; + const uint8_t MB06A4[16] = {0xC7, 0xD8, 0xF1, 0xC4, 0xE3, 0x5E, 0x9A, 0xE2, + 0xA1, 0xCB, 0x02, 0x4F, 0x57, 0x4E, 0x8E, 0xE4}; + const uint8_t MB16A954A6[16] = {0x79, 0xB9, 0x67, 0xAD, 0xD5, 0xF7, 0x70, 0xAA, + 0x44, 0x61, 0x5A, 0xDC, 0x26, 0xB4, 0xD2, 0xC3}; + + uint8_t crc = 0xFF; + uint8_t magicByte = 0x00; + uint8_t counter = inputBytes[1] & 0x0F; // only the low byte of the couner is relevant + + switch (address) { + case 0x0040: // Airbag + magicByte = MB0040[counter]; + break; + case 0x00C0: // + magicByte = MB00C0[counter]; + break; + case 0x00FC: + magicByte = MB00FC[counter]; + break; + case 0x00FD: + magicByte = MB00FD[counter]; + break; + case 0x0097: // ?? + magicByte = MB0097[counter]; + break; + case 0x00F7: // ?? + magicByte = MB00F7[counter]; + break; + case 0x0124: // ?? + magicByte = MB0124[counter]; + break; + case 0x014C: // Motor + magicByte = MB014C[counter]; + break; + case 0x0153: // HYB30 + magicByte = MB0153[counter]; + break; + case 0x0187: // EV_Gearshift "Gear" selection data for EVs with no gearbox + magicByte = MB0187[counter]; + break; + case 0x03A6: // ?? + magicByte = MB03A6[counter]; + break; + case 0x03AF: // ?? + magicByte = MB03AF[counter]; + break; + case 0x03BE: // Motor + magicByte = MB03BE[counter]; + break; + case 0x03C0: // Klemmen status + magicByte = MB03C0[counter]; + break; + case 0x0503: // HVK + magicByte = MB0503[counter]; + break; + case 0x0578: // BMS DC + magicByte = MB0578[counter]; + break; + case 0x05CA: // BMS + magicByte = MB05CA[counter]; + break; + case 0x0641: // Motor + magicByte = MB0641[counter]; + break; + case 0x06A3: // ?? + magicByte = MB06A3[counter]; + break; + case 0x06A4: // ?? + magicByte = MB06A4[counter]; + break; + case 0x16A954A6: + magicByte = MB16A954A6[counter]; + break; + default: // this won't lead to correct CRC checksums + magicByte = 0x00; + break; + } + + for (uint8_t i = 1; i < length + 1; i++) { + // We skip the empty CRC position and start at the timer + // The last element is the VAG magic byte for address 0x187 depending on the counter value. + if (i < length) + crc ^= inputBytes[i]; + else + crc ^= magicByte; + + for (uint8_t j = 0; j < 8; j++) { + if (crc & 0x80) + crc = (crc << 1) ^ poly; + else + crc = (crc << 1); + } + } + + crc ^= xor_output; + + return crc; +} + +void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus + + datalayer.battery.status.real_soc = battery_soc_polled * 10; + //Alternatively use battery_SOC for more precision + + datalayer.battery.status.soh_pptt; + + datalayer.battery.status.voltage_dV = battery_voltage_polled * 2.5; + + datalayer.battery.status.current_dA = (BMS_current / 10) - 1630; + + datalayer.battery.info.total_capacity_Wh = + ((float)datalayer.battery.info.number_of_cells) * 3.6458 * ((float)BMS_capacity_ah) * 0.2; + + datalayer.battery.status.remaining_capacity_Wh = usable_energy_amount_Wh * 5; + //Alternatively use battery_Wh_left + + datalayer.battery.status.max_charge_power_W = (max_charge_power_watt * 100); + + datalayer.battery.status.max_discharge_power_W = (max_discharge_power_watt * 100); + + //Power in watts, Negative = charging batt + datalayer.battery.status.active_power_W = + ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); + + datalayer.battery.status.temperature_min_dC = (battery_min_temp - 350) / 2; + + datalayer.battery.status.temperature_max_dC = (battery_max_temp - 350) / 2; + + //Map all cell voltages to the global array + memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages_polled, 108 * sizeof(uint16_t)); + + // 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 < 108; ++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; + //TODO, use actual_cellvoltage_lowest_mV instead to save performance + + if (service_disconnect_switch_missing) { + set_event(EVENT_HVIL_FAILURE, 1); + } else { + clear_event(EVENT_HVIL_FAILURE); + } + if (pilotline_open) { + set_event(EVENT_HVIL_FAILURE, 2); + } else { + clear_event(EVENT_HVIL_FAILURE); + } + + // Update webserver datalayer for "More battery info" page + datalayer_extended.meb.SDSW = service_disconnect_switch_missing; + datalayer_extended.meb.pilotline = pilotline_open; + datalayer_extended.meb.transportmode = transportation_mode_active; + datalayer_extended.meb.componentprotection = component_protection_active; + datalayer_extended.meb.shutdown_active = shutdown_active; + datalayer_extended.meb.HVIL = BMS_HVIL_status; + datalayer_extended.meb.BMS_mode = BMS_mode; + datalayer_extended.meb.battery_diagnostic = battery_diagnostic; + datalayer_extended.meb.status_HV_line = status_HV_line; + datalayer_extended.meb.warning_support = warning_support; + datalayer_extended.meb.BMS_status_voltage_free = BMS_status_voltage_free; + datalayer_extended.meb.BMS_OBD_MIL = BMS_OBD_MIL; + datalayer_extended.meb.BMS_error_status = BMS_error_status; + datalayer_extended.meb.BMS_error_lamp_req = BMS_error_lamp_req; + datalayer_extended.meb.BMS_warning_lamp_req = BMS_warning_lamp_req; + datalayer_extended.meb.BMS_Kl30c_Status = BMS_Kl30c_Status; + datalayer_extended.meb.BMS_voltage_intermediate_dV = (BMS_voltage_intermediate - 2000) * 10 / 2; + datalayer_extended.meb.BMS_voltage_dV = BMS_voltage * 10 / 4; + datalayer_extended.meb.isolation_resistance = isolation_resistance_kOhm * 5; + datalayer_extended.meb.battery_heating = battery_heating_active; + datalayer_extended.meb.rt_overcurrent = realtime_overcurrent_monitor; + datalayer_extended.meb.rt_CAN_fault = realtime_CAN_communication_fault; + datalayer_extended.meb.rt_overcharge = realtime_overcharge_warning; + datalayer_extended.meb.rt_SOC_high = realtime_SOC_too_high; + datalayer_extended.meb.rt_SOC_low = realtime_SOC_too_low; + datalayer_extended.meb.rt_SOC_jumping = realtime_SOC_jumping_warning; + datalayer_extended.meb.rt_temp_difference = realtime_temperature_difference_warning; + datalayer_extended.meb.rt_cell_overtemp = realtime_cell_overtemperature_warning; + datalayer_extended.meb.rt_cell_undertemp = realtime_cell_undertemperature_warning; + datalayer_extended.meb.rt_battery_overvolt = realtime_battery_overvoltage_warning; + datalayer_extended.meb.rt_battery_undervol = realtime_battery_undervoltage_warning; + datalayer_extended.meb.rt_cell_overvolt = realtime_cell_overvoltage_warning; + datalayer_extended.meb.rt_cell_undervol = realtime_cell_undervoltage_warning; + datalayer_extended.meb.rt_cell_imbalance = realtime_cell_imbalance_warning; + datalayer_extended.meb.rt_battery_unathorized = realtime_warning_battery_unathorized; +} + +void receive_can_battery(CAN_frame rx_frame) { + last_can_msg_timestamp = millis(); + if (first_can_msg == 0) + first_can_msg = last_can_msg_timestamp; + switch (rx_frame.ID) { + case 0x17F0007B: // BMS 500ms + component_protection_active = (rx_frame.data.u8[0] & 0x01); + shutdown_active = ((rx_frame.data.u8[0] & 0x02) >> 1); + transportation_mode_active = ((rx_frame.data.u8[0] & 0x02) >> 1); + KL15_mode = ((rx_frame.data.u8[0] & 0xF0) >> 4); + //0 = communication only when terminal 15 = ON (no run-on, cannot be woken up) + //1 = communication after terminal 15 = OFF (run-on, cannot be woken up) + //2 = communication when terminal 15 = OFF (run-on, can be woken up) + bus_knockout_timer = rx_frame.data.u8[5]; + hybrid_wakeup_reason = rx_frame.data.u8[6]; //(if several active, lowest wins) + //0 = wakeup cause not known 1 = Bus wakeup2 = KL15 HW 3 = TPA active + break; + case 0x17FE007B: // BMS - Offboard tester diag response + break; + case 0x1B00007B: // BMS - 200ms + wakeup_type = + ((rx_frame.data.u8[1] & 0x10) >> 4); //0 passive, SG has not woken up, 1 active, SG has woken up the network + instrumentation_cluster_request = ((rx_frame.data.u8[1] & 0x40) >> 6); //True/false + break; + case 0x12DD54D0: // BMS Limits 100ms + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + max_discharge_power_watt = + ((rx_frame.data.u8[6] & 0x07) << 10) | (rx_frame.data.u8[5] << 2) | (rx_frame.data.u8[4] & 0xC0) >> 6; //*100 + max_discharge_current_amp = + ((rx_frame.data.u8[3] & 0x01) << 12) | (rx_frame.data.u8[2] << 4) | (rx_frame.data.u8[1] >> 4); //*0.2 + max_charge_power_watt = (rx_frame.data.u8[7] << 5) | (rx_frame.data.u8[6] >> 3); //*100 + max_charge_current_amp = ((rx_frame.data.u8[4] & 0x3F) << 7) | (rx_frame.data.u8[3] >> 1); //*0.2 + break; + case 0x12DD54D1: // BMS 100ms + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_SOC = ((rx_frame.data.u8[3] & 0x0F) << 7) | (rx_frame.data.u8[2] >> 1); //*0.05 + usable_energy_amount_Wh = (rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]; //*5 + power_discharge_percentage = ((rx_frame.data.u8[4] & 0x3F) << 4) | rx_frame.data.u8[3] >> 4; //*0.2 + power_charge_percentage = (rx_frame.data.u8[5] << 2) | rx_frame.data.u8[4] >> 6; //*0.2 + status_HV_line = ((rx_frame.data.u8[2] & 0x01) << 1) | rx_frame.data.u8[1] >> 7; + warning_support = (rx_frame.data.u8[1] & 0x70) >> 4; + break; + case 0x12DD54D2: // BMS 100ms + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_heating_active = (rx_frame.data.u8[4] & 0x40) >> 6; + heating_request = (rx_frame.data.u8[5] & 0xE0) >> 5; + cooling_request = (rx_frame.data.u8[5] & 0x1C) >> 2; + power_battery_heating_watt = rx_frame.data.u8[6]; + power_battery_heating_req_watt = rx_frame.data.u8[7]; + break; + case 0x1A555550: // BMS 500ms + balancing_active = (rx_frame.data.u8[1] & 0xC0) >> 6; + charging_active = (rx_frame.data.u8[2] & 0x01); + max_energy_Wh = ((rx_frame.data.u8[6] & 0x1F) << 8) | rx_frame.data.u8[5]; //*40 + max_charge_percent = ((rx_frame.data.u8[7] << 3) | rx_frame.data.u8[6] >> 5); //*0.05 + min_charge_percent = ((rx_frame.data.u8[4] << 3) | rx_frame.data.u8[3] >> 5); //*0.05 + isolation_resistance_kOhm = (((rx_frame.data.u8[3] & 0x1F) << 7) | rx_frame.data.u8[2] >> 1); //*5 + break; + case 0x1A555551: // BMS 500ms + battery_heating_installed = (rx_frame.data.u8[1] & 0x20) >> 5; + error_NT_circuit = (rx_frame.data.u8[1] & 0x40) >> 6; + pump_1_control = rx_frame.data.u8[2] & 0x0F; //*10, percent + pump_2_control = (rx_frame.data.u8[2] & 0xF0) >> 4; //*10, percent + status_valve_1 = (rx_frame.data.u8[3] & 0x1C) >> 2; + status_valve_2 = (rx_frame.data.u8[3] & 0xE0) >> 5; + temperature_request = (((rx_frame.data.u8[2] & 0x03) << 1) | rx_frame.data.u8[1] >> 7); + battery_temperature = rx_frame.data.u8[5]; //*0,5 -40 + target_flow_temperature_C = rx_frame.data.u8[6]; //*0,5 -40 + return_temperature_C = rx_frame.data.u8[7]; //*0,5 -40 + break; + case 0x1A5555B2: // BMS + performance_index_discharge_peak_temperature_percentage = + (((rx_frame.data.u8[3] & 0x07) << 6) | rx_frame.data.u8[2] >> 2); //*0.2 + performance_index_charge_peak_temperature_percentage = + (((rx_frame.data.u8[4] & 0x3F) << 3) | rx_frame.data.u8[3] >> 5); //*0.2 + temperature_status_discharge = (rx_frame.data.u8[1] & 0x70) >> 4; + temperature_status_charge = (((rx_frame.data.u8[2] & 0x03) << 1) | rx_frame.data.u8[1] >> 7); + break; + case 0x16A954A6: // BMS + BMS_16A954A6_CRC = rx_frame.data.u8[0]; // Can be used to check CAN signal integrity later on + BMS_16A954A6_counter = (rx_frame.data.u8[1] & 0x0F); // Can be used to check CAN signal integrity later on + isolation_fault = (rx_frame.data.u8[2] & 0xE0) >> 5; + isolation_status = (rx_frame.data.u8[2] & 0x1E) >> 1; + actual_temperature_highest_C = rx_frame.data.u8[3]; //*0,5 -40 + actual_temperature_lowest_C = rx_frame.data.u8[4]; //*0,5 -40 + actual_cellvoltage_highest_mV = (((rx_frame.data.u8[6] & 0x0F) << 8) | rx_frame.data.u8[5]); + actual_cellvoltage_lowest_mV = ((rx_frame.data.u8[7] << 4) | rx_frame.data.u8[6] >> 4); + break; + case 0x16A954F8: // BMS + predicted_power_dyn_standard_watt = ((rx_frame.data.u8[6] << 1) | rx_frame.data.u8[5] >> 7); //*50 + predicted_time_dyn_standard_minutes = rx_frame.data.u8[7]; + break; + case 0x16A954E8: // BMS Temperature and cellvoltages - 180ms + mux = (rx_frame.data.u8[0] & 0x0F); + switch (mux) { + case 0: // Temperatures 1-56. Value is 0xFD if sensor not present + for (uint8_t i = 0; i < 56; i++) { + celltemperature[i] = (rx_frame.data.u8[i + 1] / 2) - 40; + } + break; + case 1: // Cellvoltages 1-42 + cellvoltages[0] = (((rx_frame.data.u8[2] & 0x0F) << 8) | rx_frame.data.u8[1]) + 1000; + cellvoltages[1] = ((rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[2] >> 4)) + 1000; + cellvoltages[2] = (((rx_frame.data.u8[5] & 0x0F) << 8) | rx_frame.data.u8[4]) + 1000; + cellvoltages[3] = ((rx_frame.data.u8[6] << 4) | (rx_frame.data.u8[5] >> 4)) + 1000; + cellvoltages[4] = (((rx_frame.data.u8[8] & 0x0F) << 8) | rx_frame.data.u8[7]) + 1000; + cellvoltages[5] = ((rx_frame.data.u8[9] << 4) | (rx_frame.data.u8[8] >> 4)) + 1000; + cellvoltages[6] = (((rx_frame.data.u8[11] & 0x0F) << 8) | rx_frame.data.u8[10]) + 1000; + cellvoltages[7] = ((rx_frame.data.u8[12] << 4) | (rx_frame.data.u8[11] >> 4)) + 1000; + cellvoltages[8] = (((rx_frame.data.u8[14] & 0x0F) << 8) | rx_frame.data.u8[13]) + 1000; + cellvoltages[9] = ((rx_frame.data.u8[15] << 4) | (rx_frame.data.u8[14] >> 4)) + 1000; + cellvoltages[10] = (((rx_frame.data.u8[17] & 0x0F) << 8) | rx_frame.data.u8[16]) + 1000; + cellvoltages[11] = ((rx_frame.data.u8[18] << 4) | (rx_frame.data.u8[17] >> 4)) + 1000; + cellvoltages[12] = (((rx_frame.data.u8[20] & 0x0F) << 8) | rx_frame.data.u8[19]) + 1000; + cellvoltages[13] = ((rx_frame.data.u8[21] << 4) | (rx_frame.data.u8[20] >> 4)) + 1000; + cellvoltages[14] = (((rx_frame.data.u8[23] & 0x0F) << 8) | rx_frame.data.u8[22]) + 1000; + cellvoltages[15] = ((rx_frame.data.u8[24] << 4) | (rx_frame.data.u8[23] >> 4)) + 1000; + cellvoltages[16] = (((rx_frame.data.u8[26] & 0x0F) << 8) | rx_frame.data.u8[25]) + 1000; + cellvoltages[17] = ((rx_frame.data.u8[27] << 4) | (rx_frame.data.u8[26] >> 4)) + 1000; + cellvoltages[18] = (((rx_frame.data.u8[29] & 0x0F) << 8) | rx_frame.data.u8[28]) + 1000; + cellvoltages[19] = ((rx_frame.data.u8[30] << 4) | (rx_frame.data.u8[29] >> 4)) + 1000; + cellvoltages[20] = (((rx_frame.data.u8[32] & 0x0F) << 8) | rx_frame.data.u8[31]) + 1000; + cellvoltages[21] = ((rx_frame.data.u8[33] << 4) | (rx_frame.data.u8[32] >> 4)) + 1000; + cellvoltages[22] = (((rx_frame.data.u8[35] & 0x0F) << 8) | rx_frame.data.u8[34]) + 1000; + cellvoltages[23] = ((rx_frame.data.u8[36] << 4) | (rx_frame.data.u8[35] >> 4)) + 1000; + cellvoltages[24] = (((rx_frame.data.u8[38] & 0x0F) << 8) | rx_frame.data.u8[37]) + 1000; + cellvoltages[25] = ((rx_frame.data.u8[39] << 4) | (rx_frame.data.u8[38] >> 4)) + 1000; + cellvoltages[26] = (((rx_frame.data.u8[41] & 0x0F) << 8) | rx_frame.data.u8[40]) + 1000; + cellvoltages[27] = ((rx_frame.data.u8[42] << 4) | (rx_frame.data.u8[41] >> 4)) + 1000; + cellvoltages[28] = (((rx_frame.data.u8[44] & 0x0F) << 8) | rx_frame.data.u8[43]) + 1000; + cellvoltages[29] = ((rx_frame.data.u8[45] << 4) | (rx_frame.data.u8[44] >> 4)) + 1000; + cellvoltages[30] = (((rx_frame.data.u8[47] & 0x0F) << 8) | rx_frame.data.u8[46]) + 1000; + cellvoltages[31] = ((rx_frame.data.u8[48] << 4) | (rx_frame.data.u8[47] >> 4)) + 1000; + cellvoltages[32] = (((rx_frame.data.u8[50] & 0x0F) << 8) | rx_frame.data.u8[49]) + 1000; + cellvoltages[33] = ((rx_frame.data.u8[51] << 4) | (rx_frame.data.u8[50] >> 4)) + 1000; + cellvoltages[34] = (((rx_frame.data.u8[53] & 0x0F) << 8) | rx_frame.data.u8[52]) + 1000; + cellvoltages[35] = ((rx_frame.data.u8[54] << 4) | (rx_frame.data.u8[53] >> 4)) + 1000; + cellvoltages[36] = (((rx_frame.data.u8[56] & 0x0F) << 8) | rx_frame.data.u8[55]) + 1000; + cellvoltages[37] = ((rx_frame.data.u8[57] << 4) | (rx_frame.data.u8[56] >> 4)) + 1000; + cellvoltages[38] = (((rx_frame.data.u8[59] & 0x0F) << 8) | rx_frame.data.u8[58]) + 1000; + cellvoltages[39] = ((rx_frame.data.u8[60] << 4) | (rx_frame.data.u8[59] >> 4)) + 1000; + cellvoltages[40] = (((rx_frame.data.u8[62] & 0x0F) << 8) | rx_frame.data.u8[61]) + 1000; + cellvoltages[41] = ((rx_frame.data.u8[63] << 4) | (rx_frame.data.u8[62] >> 4)) + 1000; + break; + case 2: // Cellvoltages 43-84 + cellvoltages[42] = (((rx_frame.data.u8[2] & 0x0F) << 8) | rx_frame.data.u8[1]) + 1000; + cellvoltages[43] = ((rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[2] >> 4)) + 1000; + cellvoltages[44] = (((rx_frame.data.u8[5] & 0x0F) << 8) | rx_frame.data.u8[4]) + 1000; + cellvoltages[45] = ((rx_frame.data.u8[6] << 4) | (rx_frame.data.u8[5] >> 4)) + 1000; + cellvoltages[46] = (((rx_frame.data.u8[8] & 0x0F) << 8) | rx_frame.data.u8[7]) + 1000; + cellvoltages[47] = ((rx_frame.data.u8[9] << 4) | (rx_frame.data.u8[8] >> 4)) + 1000; + cellvoltages[48] = (((rx_frame.data.u8[11] & 0x0F) << 8) | rx_frame.data.u8[10]) + 1000; + cellvoltages[49] = ((rx_frame.data.u8[12] << 4) | (rx_frame.data.u8[11] >> 4)) + 1000; + cellvoltages[50] = (((rx_frame.data.u8[14] & 0x0F) << 8) | rx_frame.data.u8[13]) + 1000; + cellvoltages[51] = ((rx_frame.data.u8[15] << 4) | (rx_frame.data.u8[14] >> 4)) + 1000; + cellvoltages[52] = (((rx_frame.data.u8[17] & 0x0F) << 8) | rx_frame.data.u8[16]) + 1000; + cellvoltages[53] = ((rx_frame.data.u8[18] << 4) | (rx_frame.data.u8[17] >> 4)) + 1000; + cellvoltages[54] = (((rx_frame.data.u8[20] & 0x0F) << 8) | rx_frame.data.u8[19]) + 1000; + cellvoltages[55] = ((rx_frame.data.u8[21] << 4) | (rx_frame.data.u8[20] >> 4)) + 1000; + cellvoltages[56] = (((rx_frame.data.u8[23] & 0x0F) << 8) | rx_frame.data.u8[22]) + 1000; + cellvoltages[57] = ((rx_frame.data.u8[24] << 4) | (rx_frame.data.u8[23] >> 4)) + 1000; + cellvoltages[58] = (((rx_frame.data.u8[26] & 0x0F) << 8) | rx_frame.data.u8[25]) + 1000; + cellvoltages[59] = ((rx_frame.data.u8[27] << 4) | (rx_frame.data.u8[26] >> 4)) + 1000; + cellvoltages[60] = (((rx_frame.data.u8[29] & 0x0F) << 8) | rx_frame.data.u8[28]) + 1000; + cellvoltages[61] = ((rx_frame.data.u8[30] << 4) | (rx_frame.data.u8[29] >> 4)) + 1000; + cellvoltages[62] = (((rx_frame.data.u8[32] & 0x0F) << 8) | rx_frame.data.u8[31]) + 1000; + cellvoltages[63] = ((rx_frame.data.u8[33] << 4) | (rx_frame.data.u8[32] >> 4)) + 1000; + cellvoltages[64] = (((rx_frame.data.u8[35] & 0x0F) << 8) | rx_frame.data.u8[34]) + 1000; + cellvoltages[65] = ((rx_frame.data.u8[36] << 4) | (rx_frame.data.u8[35] >> 4)) + 1000; + cellvoltages[66] = (((rx_frame.data.u8[38] & 0x0F) << 8) | rx_frame.data.u8[37]) + 1000; + cellvoltages[67] = ((rx_frame.data.u8[39] << 4) | (rx_frame.data.u8[38] >> 4)) + 1000; + cellvoltages[68] = (((rx_frame.data.u8[41] & 0x0F) << 8) | rx_frame.data.u8[40]) + 1000; + cellvoltages[69] = ((rx_frame.data.u8[42] << 4) | (rx_frame.data.u8[41] >> 4)) + 1000; + cellvoltages[70] = (((rx_frame.data.u8[44] & 0x0F) << 8) | rx_frame.data.u8[43]) + 1000; + cellvoltages[71] = ((rx_frame.data.u8[45] << 4) | (rx_frame.data.u8[44] >> 4)) + 1000; + cellvoltages[72] = (((rx_frame.data.u8[47] & 0x0F) << 8) | rx_frame.data.u8[46]) + 1000; + cellvoltages[73] = ((rx_frame.data.u8[48] << 4) | (rx_frame.data.u8[47] >> 4)) + 1000; + cellvoltages[74] = (((rx_frame.data.u8[50] & 0x0F) << 8) | rx_frame.data.u8[49]) + 1000; + cellvoltages[75] = ((rx_frame.data.u8[51] << 4) | (rx_frame.data.u8[50] >> 4)) + 1000; + cellvoltages[76] = (((rx_frame.data.u8[53] & 0x0F) << 8) | rx_frame.data.u8[52]) + 1000; + cellvoltages[77] = ((rx_frame.data.u8[54] << 4) | (rx_frame.data.u8[53] >> 4)) + 1000; + cellvoltages[78] = (((rx_frame.data.u8[56] & 0x0F) << 8) | rx_frame.data.u8[55]) + 1000; + cellvoltages[79] = ((rx_frame.data.u8[57] << 4) | (rx_frame.data.u8[56] >> 4)) + 1000; + cellvoltages[80] = (((rx_frame.data.u8[59] & 0x0F) << 8) | rx_frame.data.u8[58]) + 1000; + cellvoltages[81] = ((rx_frame.data.u8[60] << 4) | (rx_frame.data.u8[59] >> 4)) + 1000; + cellvoltages[82] = (((rx_frame.data.u8[62] & 0x0F) << 8) | rx_frame.data.u8[61]) + 1000; + cellvoltages[83] = ((rx_frame.data.u8[63] << 4) | (rx_frame.data.u8[62] >> 4)) + 1000; + break; + case 3: // Cellvoltages 85-126 + cellvoltages[84] = (((rx_frame.data.u8[2] & 0x0F) << 8) | rx_frame.data.u8[1]) + 1000; + cellvoltages[85] = ((rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[2] >> 4)) + 1000; + cellvoltages[86] = (((rx_frame.data.u8[5] & 0x0F) << 8) | rx_frame.data.u8[4]) + 1000; + cellvoltages[87] = ((rx_frame.data.u8[6] << 4) | (rx_frame.data.u8[5] >> 4)) + 1000; + cellvoltages[88] = (((rx_frame.data.u8[8] & 0x0F) << 8) | rx_frame.data.u8[7]) + 1000; + cellvoltages[89] = ((rx_frame.data.u8[9] << 4) | (rx_frame.data.u8[8] >> 4)) + 1000; + cellvoltages[90] = (((rx_frame.data.u8[11] & 0x0F) << 8) | rx_frame.data.u8[10]) + 1000; + cellvoltages[91] = ((rx_frame.data.u8[12] << 4) | (rx_frame.data.u8[11] >> 4)) + 1000; + cellvoltages[92] = (((rx_frame.data.u8[14] & 0x0F) << 8) | rx_frame.data.u8[13]) + 1000; + cellvoltages[93] = ((rx_frame.data.u8[15] << 4) | (rx_frame.data.u8[14] >> 4)) + 1000; + cellvoltages[94] = (((rx_frame.data.u8[17] & 0x0F) << 8) | rx_frame.data.u8[16]) + 1000; + cellvoltages[95] = ((rx_frame.data.u8[18] << 4) | (rx_frame.data.u8[17] >> 4)) + 1000; + cellvoltages[96] = (((rx_frame.data.u8[20] & 0x0F) << 8) | rx_frame.data.u8[19]) + 1000; + cellvoltages[97] = ((rx_frame.data.u8[21] << 4) | (rx_frame.data.u8[20] >> 4)) + 1000; + cellvoltages[98] = (((rx_frame.data.u8[23] & 0x0F) << 8) | rx_frame.data.u8[22]) + 1000; + cellvoltages[99] = ((rx_frame.data.u8[24] << 4) | (rx_frame.data.u8[23] >> 4)) + 1000; + cellvoltages[100] = (((rx_frame.data.u8[26] & 0x0F) << 8) | rx_frame.data.u8[25]) + 1000; + cellvoltages[101] = ((rx_frame.data.u8[27] << 4) | (rx_frame.data.u8[26] >> 4)) + 1000; + cellvoltages[102] = (((rx_frame.data.u8[29] & 0x0F) << 8) | rx_frame.data.u8[28]) + 1000; + cellvoltages[103] = ((rx_frame.data.u8[30] << 4) | (rx_frame.data.u8[29] >> 4)) + 1000; + cellvoltages[104] = (((rx_frame.data.u8[32] & 0x0F) << 8) | rx_frame.data.u8[31]) + 1000; + cellvoltages[105] = ((rx_frame.data.u8[33] << 4) | (rx_frame.data.u8[32] >> 4)) + 1000; + cellvoltages[106] = (((rx_frame.data.u8[35] & 0x0F) << 8) | rx_frame.data.u8[34]) + 1000; + cellvoltages[107] = ((rx_frame.data.u8[36] << 4) | (rx_frame.data.u8[35] >> 4)) + 1000; + cellvoltages[108] = (((rx_frame.data.u8[38] & 0x0F) << 8) | rx_frame.data.u8[37]) + 1000; + cellvoltages[109] = ((rx_frame.data.u8[39] << 4) | (rx_frame.data.u8[38] >> 4)) + 1000; + cellvoltages[110] = (((rx_frame.data.u8[41] & 0x0F) << 8) | rx_frame.data.u8[40]) + 1000; + cellvoltages[111] = ((rx_frame.data.u8[42] << 4) | (rx_frame.data.u8[41] >> 4)) + 1000; + cellvoltages[112] = (((rx_frame.data.u8[44] & 0x0F) << 8) | rx_frame.data.u8[43]) + 1000; + cellvoltages[113] = ((rx_frame.data.u8[45] << 4) | (rx_frame.data.u8[44] >> 4)) + 1000; + cellvoltages[114] = (((rx_frame.data.u8[47] & 0x0F) << 8) | rx_frame.data.u8[46]) + 1000; + cellvoltages[115] = ((rx_frame.data.u8[48] << 4) | (rx_frame.data.u8[47] >> 4)) + 1000; + cellvoltages[116] = (((rx_frame.data.u8[50] & 0x0F) << 8) | rx_frame.data.u8[49]) + 1000; + cellvoltages[117] = ((rx_frame.data.u8[51] << 4) | (rx_frame.data.u8[50] >> 4)) + 1000; + cellvoltages[118] = (((rx_frame.data.u8[53] & 0x0F) << 8) | rx_frame.data.u8[52]) + 1000; + cellvoltages[119] = ((rx_frame.data.u8[54] << 4) | (rx_frame.data.u8[53] >> 4)) + 1000; + cellvoltages[120] = (((rx_frame.data.u8[56] & 0x0F) << 8) | rx_frame.data.u8[55]) + 1000; + cellvoltages[121] = ((rx_frame.data.u8[57] << 4) | (rx_frame.data.u8[56] >> 4)) + 1000; + cellvoltages[122] = (((rx_frame.data.u8[59] & 0x0F) << 8) | rx_frame.data.u8[58]) + 1000; + cellvoltages[123] = ((rx_frame.data.u8[60] << 4) | (rx_frame.data.u8[59] >> 4)) + 1000; + cellvoltages[124] = (((rx_frame.data.u8[62] & 0x0F) << 8) | rx_frame.data.u8[61]) + 1000; + cellvoltages[125] = ((rx_frame.data.u8[63] << 4) | (rx_frame.data.u8[62] >> 4)) + 1000; + break; + case 4: //Cellvoltages 127-160 + cellvoltages[126] = (((rx_frame.data.u8[2] & 0x0F) << 8) | rx_frame.data.u8[1]) + 1000; + cellvoltages[127] = ((rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[2] >> 4)) + 1000; + cellvoltages[128] = (((rx_frame.data.u8[5] & 0x0F) << 8) | rx_frame.data.u8[4]) + 1000; + cellvoltages[129] = ((rx_frame.data.u8[6] << 4) | (rx_frame.data.u8[5] >> 4)) + 1000; + cellvoltages[130] = (((rx_frame.data.u8[8] & 0x0F) << 8) | rx_frame.data.u8[7]) + 1000; + cellvoltages[131] = ((rx_frame.data.u8[9] << 4) | (rx_frame.data.u8[8] >> 4)) + 1000; + cellvoltages[132] = (((rx_frame.data.u8[11] & 0x0F) << 8) | rx_frame.data.u8[10]) + 1000; + cellvoltages[133] = ((rx_frame.data.u8[12] << 4) | (rx_frame.data.u8[11] >> 4)) + 1000; + cellvoltages[134] = (((rx_frame.data.u8[14] & 0x0F) << 8) | rx_frame.data.u8[13]) + 1000; + cellvoltages[135] = ((rx_frame.data.u8[15] << 4) | (rx_frame.data.u8[14] >> 4)) + 1000; + cellvoltages[136] = (((rx_frame.data.u8[17] & 0x0F) << 8) | rx_frame.data.u8[16]) + 1000; + cellvoltages[137] = ((rx_frame.data.u8[18] << 4) | (rx_frame.data.u8[17] >> 4)) + 1000; + cellvoltages[138] = (((rx_frame.data.u8[20] & 0x0F) << 8) | rx_frame.data.u8[19]) + 1000; + cellvoltages[139] = ((rx_frame.data.u8[21] << 4) | (rx_frame.data.u8[20] >> 4)) + 1000; + cellvoltages[140] = (((rx_frame.data.u8[23] & 0x0F) << 8) | rx_frame.data.u8[22]) + 1000; + cellvoltages[141] = ((rx_frame.data.u8[24] << 4) | (rx_frame.data.u8[23] >> 4)) + 1000; + cellvoltages[142] = (((rx_frame.data.u8[26] & 0x0F) << 8) | rx_frame.data.u8[25]) + 1000; + cellvoltages[143] = ((rx_frame.data.u8[27] << 4) | (rx_frame.data.u8[26] >> 4)) + 1000; + cellvoltages[144] = (((rx_frame.data.u8[29] & 0x0F) << 8) | rx_frame.data.u8[28]) + 1000; + cellvoltages[145] = ((rx_frame.data.u8[30] << 4) | (rx_frame.data.u8[29] >> 4)) + 1000; + cellvoltages[146] = (((rx_frame.data.u8[32] & 0x0F) << 8) | rx_frame.data.u8[31]) + 1000; + cellvoltages[147] = ((rx_frame.data.u8[33] << 4) | (rx_frame.data.u8[32] >> 4)) + 1000; + cellvoltages[148] = (((rx_frame.data.u8[35] & 0x0F) << 8) | rx_frame.data.u8[34]) + 1000; + cellvoltages[149] = ((rx_frame.data.u8[36] << 4) | (rx_frame.data.u8[35] >> 4)) + 1000; + cellvoltages[150] = (((rx_frame.data.u8[38] & 0x0F) << 8) | rx_frame.data.u8[37]) + 1000; + cellvoltages[151] = ((rx_frame.data.u8[39] << 4) | (rx_frame.data.u8[38] >> 4)) + 1000; + cellvoltages[152] = (((rx_frame.data.u8[41] & 0x0F) << 8) | rx_frame.data.u8[40]) + 1000; + cellvoltages[153] = ((rx_frame.data.u8[42] << 4) | (rx_frame.data.u8[41] >> 4)) + 1000; + cellvoltages[154] = (((rx_frame.data.u8[44] & 0x0F) << 8) | rx_frame.data.u8[43]) + 1000; + cellvoltages[155] = ((rx_frame.data.u8[45] << 4) | (rx_frame.data.u8[44] >> 4)) + 1000; + cellvoltages[156] = (((rx_frame.data.u8[47] & 0x0F) << 8) | rx_frame.data.u8[46]) + 1000; + cellvoltages[157] = ((rx_frame.data.u8[48] << 4) | (rx_frame.data.u8[47] >> 4)) + 1000; + cellvoltages[158] = (((rx_frame.data.u8[50] & 0x0F) << 8) | rx_frame.data.u8[49]) + 1000; + cellvoltages[159] = ((rx_frame.data.u8[51] << 4) | (rx_frame.data.u8[50] >> 4)) + 1000; + break; + default: //Invalid mux + //TODO: Add corrupted CAN message counter tick? + break; + } + break; + case 0x1C42017B: // BMS - Non-Cyclic, TP_ISO + //hybrid_01_response_fd_data (Whole frame) + break; + case 0x1A5555B0: // BMS 1000ms cyclic + duration_discharge_power_watt = ((rx_frame.data.u8[6] & 0x0F) << 8) | rx_frame.data.u8[5]; + duration_charge_power_watt = (rx_frame.data.u8[7] << 4) | rx_frame.data.u8[6] >> 4; + maximum_voltage = ((rx_frame.data.u8[3] & 0x3F) << 4) | rx_frame.data.u8[2] >> 4; + minimum_voltage = (rx_frame.data.u8[4] << 2) | rx_frame.data.u8[3] >> 6; + break; + case 0x1A5555B1: // BMS 1000ms cyclic + // All realtime_ have same enumeration, 0 = no fault, 1 = error level 1, 2 error level 2, 3 error level 3 + realtime_overcurrent_monitor = ((rx_frame.data.u8[3] & 0x01) << 2) | rx_frame.data.u8[2] >> 6; + realtime_CAN_communication_fault = (rx_frame.data.u8[3] & 0x0E) >> 1; + realtime_overcharge_warning = (rx_frame.data.u8[3] & 0x70) >> 4; + realtime_SOC_too_high = ((rx_frame.data.u8[4] & 0x03) << 1) | rx_frame.data.u8[3] >> 7; + realtime_SOC_too_low = (rx_frame.data.u8[4] & 0x1C) >> 2; + realtime_SOC_jumping_warning = (rx_frame.data.u8[4] & 0xE0) >> 5; + realtime_temperature_difference_warning = rx_frame.data.u8[5] & 0x07; + realtime_cell_overtemperature_warning = (rx_frame.data.u8[5] & 0x38) >> 3; + realtime_cell_undertemperature_warning = ((rx_frame.data.u8[6] & 0x01) << 2) | rx_frame.data.u8[5] >> 6; + realtime_battery_overvoltage_warning = (rx_frame.data.u8[6] & 0x0E) >> 1; + realtime_battery_undervoltage_warning = (rx_frame.data.u8[6] & 0x70) >> 4; + realtime_cell_overvoltage_warning = ((rx_frame.data.u8[7] & 0x03) << 1) | rx_frame.data.u8[6] >> 7; + realtime_cell_undervoltage_warning = (rx_frame.data.u8[7] & 0x1C) >> 2; + realtime_cell_imbalance_warning = (rx_frame.data.u8[7] & 0xE0) >> 5; + for (uint8_t i = 0; i < 26; i++) { // Frame 9 to 34 is S/N for battery + battery_serialnumber[i] = rx_frame.data.u8[i + 9]; + } + realtime_warning_battery_unathorized = (rx_frame.data.u8[40] & 0x07); + break; + case 0x2AF: // BMS 50ms + actual_battery_voltage = + ((rx_frame.data.u8[1] & 0x3F) << 8) | rx_frame.data.u8[0]; //*0.0625 // Seems to be 0.125 in logging + regen_battery = ((rx_frame.data.u8[5] & 0x7F) << 8) | rx_frame.data.u8[4]; + energy_extracted_from_battery = ((rx_frame.data.u8[7] & 0x7F) << 8) | rx_frame.data.u8[6]; + break; + case 0x578: // BMS 100ms + BMS_578_CRC = rx_frame.data.u8[0]; // Can be used to check CAN signal integrity later on + BMS_578_counter = (rx_frame.data.u8[1] & 0x0F); // Can be used to check CAN signal integrity later on + BMS_Status_DCLS = ((rx_frame.data.u8[1] & 0x30) >> 4); + DC_voltage_DCLS = (rx_frame.data.u8[2] << 6) | (rx_frame.data.u8[1] >> 6); + max_fastcharging_current_amp = ((rx_frame.data.u8[4] & 0x01) << 8) | rx_frame.data.u8[3]; + DC_voltage_chargeport = (rx_frame.data.u8[7] << 4) | (rx_frame.data.u8[6] >> 4); + break; + case 0x5A2: // BMS 500ms normal, 100ms fast + BMS_5A2_CRC = rx_frame.data.u8[0]; // Can be used to check CAN signal integrity later on + BMS_5A2_counter = (rx_frame.data.u8[1] & 0x0F); // Can be used to check CAN signal integrity later on + service_disconnect_switch_missing = (rx_frame.data.u8[1] & 0x20) >> 5; + pilotline_open = (rx_frame.data.u8[1] & 0x10) >> 4; + BMS_status_voltage_free = (rx_frame.data.u8[1] & 0xC0) >> 6; + BMS_OBD_MIL = (rx_frame.data.u8[2] & 0x01); + BMS_error_status = (rx_frame.data.u8[2] & 0x70) >> 4; + BMS_capacity_ah = ((rx_frame.data.u8[4] & 0x03) << 9) | (rx_frame.data.u8[3] << 1) | (rx_frame.data.u8[2] >> 7); + BMS_error_lamp_req = (rx_frame.data.u8[4] & 0x04) >> 2; + BMS_warning_lamp_req = (rx_frame.data.u8[4] & 0x08) >> 3; + BMS_Kl30c_Status = (rx_frame.data.u8[4] & 0x30) >> 4; + break; + case 0x5CA: // BMS 500ms + BMS_5CA_CRC = rx_frame.data.u8[0]; // Can be used to check CAN signal integrity later on + BMS_5CA_counter = (rx_frame.data.u8[1] & 0x0F); // Can be used to check CAN signal integrity later on + balancing_request = (rx_frame.data.u8[5] & 0x08) >> 3; //True/False + battery_diagnostic = (rx_frame.data.u8[3] & 0x07); + battery_Wh_left = + (rx_frame.data.u8[2] << 4) | (rx_frame.data.u8[1] >> 4); //*50 ! Not usable, seems to always contain 0x7F0 + battery_potential_status = + (rx_frame.data.u8[5] & 0x30) >> 4; //0 = function not enabled, 1= no potential, 2 = potential on, 3 = fault + battery_temperature_warning = + (rx_frame.data.u8[7] & 0x0C) >> 2; // 0 = no warning, 1 = temp level 1, 2=temp level 2 + battery_Wh_max = + ((rx_frame.data.u8[5] & 0x07) << 8) | rx_frame.data.u8[4]; //*50 ! Not usable, seems to always contain 0x7F0 + break; + case 0x0CF: //BMS 10ms + BMS_0CF_CRC = rx_frame.data.u8[0]; // Can be used to check CAN signal integrity later on + BMS_0CF_counter = (rx_frame.data.u8[1] & 0x0F); // Can be used to check CAN signal integrity later on + BMS_welded_contactors_status = (rx_frame.data.u8[1] & 0x60) >> 5; + BMS_ext_limits_active = (rx_frame.data.u8[1] & 0x80) >> 7; + BMS_mode = (rx_frame.data.u8[2] & 0x07); + switch (BMS_mode) { + case 1: + case 3: + case 4: + datalayer.system.status.battery_allows_contactor_closing = true; + break; + default: + datalayer.system.status.battery_allows_contactor_closing = false; + } + BMS_HVIL_status = (rx_frame.data.u8[2] & 0x18) >> 3; + BMS_error_shutdown = (rx_frame.data.u8[2] & 0x20) >> 5; + BMS_error_shutdown_request = (rx_frame.data.u8[2] & 0x40) >> 6; + BMS_fault_performance = (rx_frame.data.u8[2] & 0x80) >> 7; + BMS_current = ((rx_frame.data.u8[4] & 0x7F) << 8) | rx_frame.data.u8[3]; + BMS_fault_emergency_shutdown_crash = (rx_frame.data.u8[4] & 0x80) >> 7; + BMS_voltage_intermediate = (((rx_frame.data.u8[6] & 0x0F) << 8) + (rx_frame.data.u8[5])); + BMS_voltage = ((rx_frame.data.u8[7] << 4) + ((rx_frame.data.u8[6] & 0xF0) >> 4)); + break; + case 0x1C42007B: // Reply from battery + if (rx_frame.data.u8[0] == 0x10) { //PID header + transmit_can(&MEB_ACK_FRAME, can_config.battery); + } + if (rx_frame.DLC == 8) { + pid_reply = (rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3]; + } else { //12 or 24bit message has reply in other location + pid_reply = (rx_frame.data.u8[3] << 8) + rx_frame.data.u8[4]; + } + + switch (pid_reply) { + case PID_SOC: + battery_soc_polled = rx_frame.data.u8[4] * 4; // 135*4 = 54.0% + case PID_VOLTAGE: + battery_voltage_polled = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case PID_CURRENT: // IDLE 0A: 00 08 62 1E 3D (00 02) 49 F0 39 AA AA + battery_current_polled = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); //TODO: right bits? + break; + case PID_MAX_TEMP: + battery_max_temp = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case PID_MIN_TEMP: + battery_min_temp = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case PID_MAX_CHARGE_VOLTAGE: + battery_max_charge_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case PID_MIN_DISCHARGE_VOLTAGE: + battery_min_discharge_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case PID_ALLOWED_CHARGE_POWER: + battery_allowed_charge_power = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case PID_ALLOWED_DISCHARGE_POWER: + battery_allowed_discharge_power = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case PID_CELLVOLTAGE_CELL_1: + cellvoltages_polled[0] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_2: + cellvoltages_polled[1] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_3: + cellvoltages_polled[2] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_4: + cellvoltages_polled[3] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_5: + cellvoltages_polled[4] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_6: + cellvoltages_polled[5] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_7: + cellvoltages_polled[6] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_8: + cellvoltages_polled[7] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_9: + cellvoltages_polled[8] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_10: + cellvoltages_polled[9] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_11: + cellvoltages_polled[10] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_12: + cellvoltages_polled[11] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_13: + cellvoltages_polled[12] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_14: + cellvoltages_polled[13] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_15: + cellvoltages_polled[14] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_16: + cellvoltages_polled[15] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_17: + cellvoltages_polled[16] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_18: + cellvoltages_polled[17] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_19: + cellvoltages_polled[18] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_20: + cellvoltages_polled[19] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_21: + cellvoltages_polled[20] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_22: + cellvoltages_polled[21] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_23: + cellvoltages_polled[22] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_24: + cellvoltages_polled[23] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_25: + cellvoltages_polled[24] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_26: + cellvoltages_polled[25] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_27: + cellvoltages_polled[26] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_28: + cellvoltages_polled[27] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_29: + cellvoltages_polled[28] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_30: + cellvoltages_polled[29] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_31: + cellvoltages_polled[30] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_32: + cellvoltages_polled[31] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_33: + cellvoltages_polled[32] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_34: + cellvoltages_polled[33] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_35: + cellvoltages_polled[34] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_36: + cellvoltages_polled[35] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_37: + cellvoltages_polled[36] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_38: + cellvoltages_polled[37] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_39: + cellvoltages_polled[38] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_40: + cellvoltages_polled[39] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_41: + cellvoltages_polled[40] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_42: + cellvoltages_polled[41] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_43: + cellvoltages_polled[42] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_44: + cellvoltages_polled[43] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_45: + cellvoltages_polled[44] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_46: + cellvoltages_polled[45] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_47: + cellvoltages_polled[46] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_48: + cellvoltages_polled[47] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_49: + cellvoltages_polled[48] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_50: + cellvoltages_polled[49] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_51: + cellvoltages_polled[50] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_52: + cellvoltages_polled[51] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_53: + cellvoltages_polled[52] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_54: + cellvoltages_polled[53] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_55: + cellvoltages_polled[54] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_56: + cellvoltages_polled[55] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_57: + cellvoltages_polled[56] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_58: + cellvoltages_polled[57] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_59: + cellvoltages_polled[58] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_60: + cellvoltages_polled[59] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_61: + cellvoltages_polled[60] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_62: + cellvoltages_polled[61] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_63: + cellvoltages_polled[62] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_64: + cellvoltages_polled[63] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_65: + cellvoltages_polled[64] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_66: + cellvoltages_polled[65] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_67: + cellvoltages_polled[66] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_68: + cellvoltages_polled[67] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_69: + cellvoltages_polled[68] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_70: + cellvoltages_polled[69] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_71: + cellvoltages_polled[70] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_72: + cellvoltages_polled[71] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_73: + cellvoltages_polled[72] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_74: + cellvoltages_polled[73] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_75: + cellvoltages_polled[74] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_76: + cellvoltages_polled[75] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_77: + cellvoltages_polled[76] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_78: + cellvoltages_polled[77] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_79: + cellvoltages_polled[78] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_80: + cellvoltages_polled[79] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_81: + cellvoltages_polled[80] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_82: + cellvoltages_polled[81] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_83: + cellvoltages_polled[82] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_84: + cellvoltages_polled[83] = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) + 1000); + break; + case PID_CELLVOLTAGE_CELL_85: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[84] = (tempval + 1000); + } else { // Cell 85 unavailable. We have a 84S battery (48kWh) + datalayer.battery.info.number_of_cells = 84; + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_84S_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_84S_DV; + } + break; + case PID_CELLVOLTAGE_CELL_86: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[85] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_87: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[86] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_88: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[87] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_89: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[88] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_90: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[89] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_91: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[90] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_92: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[91] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_93: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[92] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_94: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[93] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_95: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[94] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_96: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[95] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_97: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[96] = (tempval + 1000); + } else { // Cell 97 unavailable. We have a 96S battery (55kWh) (Unless already specified as 84S) + if (datalayer.battery.info.number_of_cells == 84) { + // Do nothing, we already identified it as 84S + } else { + datalayer.battery.info.number_of_cells = 96; + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_96S_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_96S_DV; + } + } + break; + case PID_CELLVOLTAGE_CELL_98: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[97] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_99: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[98] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_100: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[99] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_101: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[100] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_102: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[101] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_103: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[102] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_104: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[103] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_105: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[104] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_106: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[105] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_107: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[106] = (tempval + 1000); + } + break; + case PID_CELLVOLTAGE_CELL_108: + tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + if (tempval != 0xFFE) { + cellvoltages_polled[107] = (tempval + 1000); + datalayer.battery.info.number_of_cells = 108; + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_108S_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_108S_DV; + } + break; + default: + break; + } + break; + default: + break; + } +} + +void send_can_battery() { + unsigned long currentMillis = millis(); + // Send 10ms CAN Message + if (currentMillis > last_can_msg_timestamp + 500) { + first_can_msg = 0; + } + + if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) { + // Check if sending of CAN messages has been delayed too much. + if ((currentMillis - previousMillis10ms >= INTERVAL_10_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis10ms)); + } else { + clear_event(EVENT_CAN_OVERRUN); + } + previousMillis10ms = currentMillis; + + MEB_0FC.data.u8[1] = ((MEB_0FC.data.u8[1] & 0xF0) | counter_10ms); + MEB_0FC.data.u8[0] = vw_crc_calc(MEB_0FC.data.u8, MEB_0FC.DLC, MEB_0FC.ID); + + counter_10ms = (counter_10ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. + + transmit_can(&MEB_0FC, can_config.battery); // Required for contactor closing + } + // Send 20ms CAN Message + if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) { + previousMillis20ms = currentMillis; + + MEB_0FD.data.u8[1] = ((MEB_0FD.data.u8[1] & 0xF0) | counter_20ms); + MEB_0FD.data.u8[0] = vw_crc_calc(MEB_0FD.data.u8, MEB_0FD.DLC, MEB_0FD.ID); + + counter_20ms = (counter_20ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. + + transmit_can(&MEB_0FD, can_config.battery); // Required for contactor closing + } + // Send 40ms CAN Message + if (currentMillis - previousMillis40ms >= INTERVAL_40_MS) { + previousMillis40ms = currentMillis; + + /* Handle content for 0x040 message */ + /* Airbag message, needed for BMS to function */ + MEB_040.data.u8[7] = counter_040; + MEB_040.data.u8[1] = ((MEB_040.data.u8[1] & 0xF0) | counter_40ms); + MEB_040.data.u8[0] = vw_crc_calc(MEB_040.data.u8, MEB_040.DLC, MEB_040.ID); + counter_40ms = (counter_40ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. + if (toggle) { + counter_040 = (counter_040 + 1) % 256; // Increment only on every other pass + } + toggle = !toggle; // Flip the toggle each time the code block is executed + + transmit_can(&MEB_040, can_config.battery); // Airbag message - Needed for contactor closing + } + // Send 50ms CAN Message + if (currentMillis - previousMillis50ms >= INTERVAL_50_MS) { + previousMillis50ms = currentMillis; + + /* Handle content for 0x0C0 message */ + /* BMS needs to see this EM1 message. Content located in frame5&6 especially (can be static?)*/ + /* Also the voltage seen externally to battery is in frame 7&8. At least for the 62kWh ID3 version does not seem to matter, but we send it anyway. */ + MEB_0C0.data.u8[1] = ((MEB_0C0.data.u8[1] & 0xF0) | counter_50ms); + MEB_0C0.data.u8[7] = ((datalayer.battery.status.voltage_dV / 10) * 4) & 0x00FF; + MEB_0C0.data.u8[8] = + ((MEB_0C0.data.u8[8] & 0xF0) | ((((datalayer.battery.status.voltage_dV / 10) * 4) >> 8) & 0x0F)); + MEB_0C0.data.u8[0] = vw_crc_calc(MEB_0C0.data.u8, MEB_0C0.DLC, MEB_0C0.ID); + counter_50ms = (counter_50ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. + + transmit_can(&MEB_0C0, can_config.battery); // Needed for contactor closing + } + // Send 100ms CAN Message + if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) { + previousMillis100ms = currentMillis; + + //HV request and DC/DC control lies in 0x503 + MEB_503.data.u8[3] = 0x00; + if (datalayer.battery.status.bms_status != FAULT && first_can_msg > 0 && currentMillis > first_can_msg + 2000) { + MEB_503.data.u8[1] = 0xB0; + MEB_503.data.u8[3] = BMS_TARGET_HV_ON; //BMS_TARGET_AC_CHARGING; //TODO, should we try AC_2 or DC charging? + MEB_503.data.u8[5] = 0x82; // Bordnetz Active + MEB_503.data.u8[6] = 0xE0; // Request emergency shutdown HV system == 0, false + } else if (first_can_msg > 0 && currentMillis > first_can_msg + 2000) { //FAULT STATE, open contactors + MEB_503.data.u8[1] = 0x90; + MEB_503.data.u8[3] = BMS_TARGET_HV_OFF; + MEB_503.data.u8[5] = 0x80; // Bordnetz Inactive + MEB_503.data.u8[6] = + 0xE3; // Request emergency shutdown HV system == init (3) (not sure if we dare activate this, this is done with 0xE1) + } + MEB_503.data.u8[1] = ((MEB_503.data.u8[1] & 0xF0) | counter_100ms); + MEB_503.data.u8[0] = vw_crc_calc(MEB_503.data.u8, MEB_503.DLC, MEB_503.ID); + + //Bidirectional charging message + MEB_272.data.u8[1] = + 0x00; //0x80; // Bidirectional charging active (Set to 0x00 incase no bidirectional charging wanted) + MEB_272.data.u8[2] = 0x00; + //0x01; // High load bidirectional charging active (Set to 0x00 incase no bidirectional charging wanted) + MEB_272.data.u8[5] = DC_FASTCHARGE_NO_START_REQUEST; //DC_FASTCHARGE_VEHICLE; //DC charging + + //Klemmen status + MEB_3C0.data.u8[2] = 0x00; //0x02; //bit to signal that KL_15 is ON // Always 0 in start4.log + MEB_3C0.data.u8[1] = ((MEB_3C0.data.u8[1] & 0xF0) | counter_100ms); + MEB_3C0.data.u8[0] = vw_crc_calc(MEB_3C0.data.u8, MEB_3C0.DLC, MEB_3C0.ID); + + MEB_3BE.data.u8[1] = ((MEB_3BE.data.u8[1] & 0xF0) | counter_100ms); + MEB_3BE.data.u8[0] = vw_crc_calc(MEB_3BE.data.u8, MEB_3BE.DLC, MEB_3BE.ID); + + MEB_14C.data.u8[1] = ((MEB_14C.data.u8[1] & 0xF0) | counter_100ms); + MEB_14C.data.u8[0] = vw_crc_calc(MEB_14C.data.u8, MEB_14C.DLC, MEB_14C.ID); + + counter_100ms = (counter_100ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. + transmit_can(&MEB_503, can_config.battery); + transmit_can(&MEB_272, can_config.battery); + transmit_can(&MEB_3C0, can_config.battery); + transmit_can(&MEB_3BE, can_config.battery); + transmit_can(&MEB_14C, can_config.battery); + } + //Send 200ms message + if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) { + previousMillis200ms = currentMillis; + + //TODO: 153 does not seem to need CRC even though it has it? Empty in some logs and still works + + //TODO: MEB_1B0000B9 & MEB_1B000010 & MEB_1B000046 has CAN sleep commands, static OK? + + transmit_can(&MEB_5E1, can_config.battery); + transmit_can(&MEB_153, can_config.battery); + transmit_can(&MEB_1B0000B9, can_config.battery); + transmit_can(&MEB_1B000010, can_config.battery); + transmit_can(&MEB_1B000046, can_config.battery); + + switch (poll_pid) { + case PID_SOC: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_SOC >> 8); // High byte + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_SOC; // Low byte + poll_pid = PID_VOLTAGE; + break; + case PID_VOLTAGE: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_VOLTAGE >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_VOLTAGE; + poll_pid = PID_CURRENT; + break; + case PID_CURRENT: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_CURRENT >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CURRENT; + poll_pid = PID_MAX_TEMP; + break; + case PID_MAX_TEMP: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_MAX_TEMP >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_MAX_TEMP; + poll_pid = PID_MIN_TEMP; + break; + case PID_MIN_TEMP: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_MIN_TEMP >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_MIN_TEMP; + poll_pid = PID_MAX_CHARGE_VOLTAGE; + break; + case PID_MAX_CHARGE_VOLTAGE: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_MAX_CHARGE_VOLTAGE >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_MAX_CHARGE_VOLTAGE; + poll_pid = PID_MIN_DISCHARGE_VOLTAGE; + break; + case PID_MIN_DISCHARGE_VOLTAGE: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_MIN_DISCHARGE_VOLTAGE >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_MIN_DISCHARGE_VOLTAGE; + poll_pid = PID_ALLOWED_CHARGE_POWER; + break; + case PID_ALLOWED_CHARGE_POWER: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_ALLOWED_CHARGE_POWER >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_ALLOWED_CHARGE_POWER; + poll_pid = PID_ALLOWED_DISCHARGE_POWER; + break; + case PID_ALLOWED_DISCHARGE_POWER: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_ALLOWED_DISCHARGE_POWER >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_ALLOWED_DISCHARGE_POWER; + poll_pid = PID_CELLVOLTAGE_CELL_1; // Start polling cell voltages + break; + // Cell Voltage Cases + case PID_CELLVOLTAGE_CELL_1: + MEB_POLLING_FRAME.data.u8[2] = (uint8_t)(PID_CELLVOLTAGE_CELL_1 >> 8); + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_1; + poll_pid = PID_CELLVOLTAGE_CELL_2; + break; + case PID_CELLVOLTAGE_CELL_2: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_2; + poll_pid = PID_CELLVOLTAGE_CELL_3; + break; + case PID_CELLVOLTAGE_CELL_3: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_3; + poll_pid = PID_CELLVOLTAGE_CELL_4; + break; + case PID_CELLVOLTAGE_CELL_4: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_4; + poll_pid = PID_CELLVOLTAGE_CELL_5; + break; + case PID_CELLVOLTAGE_CELL_5: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_5; + poll_pid = PID_CELLVOLTAGE_CELL_6; + break; + case PID_CELLVOLTAGE_CELL_6: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_6; + poll_pid = PID_CELLVOLTAGE_CELL_7; + break; + case PID_CELLVOLTAGE_CELL_7: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_7; + poll_pid = PID_CELLVOLTAGE_CELL_8; + break; + case PID_CELLVOLTAGE_CELL_8: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_8; + poll_pid = PID_CELLVOLTAGE_CELL_9; + break; + case PID_CELLVOLTAGE_CELL_9: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_9; + poll_pid = PID_CELLVOLTAGE_CELL_10; + break; + case PID_CELLVOLTAGE_CELL_10: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_10; + poll_pid = PID_CELLVOLTAGE_CELL_11; + break; + case PID_CELLVOLTAGE_CELL_11: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_11; + poll_pid = PID_CELLVOLTAGE_CELL_12; + break; + case PID_CELLVOLTAGE_CELL_12: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_12; + poll_pid = PID_CELLVOLTAGE_CELL_13; + break; + case PID_CELLVOLTAGE_CELL_13: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_13; + poll_pid = PID_CELLVOLTAGE_CELL_14; + break; + case PID_CELLVOLTAGE_CELL_14: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_14; + poll_pid = PID_CELLVOLTAGE_CELL_15; + break; + case PID_CELLVOLTAGE_CELL_15: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_15; + poll_pid = PID_CELLVOLTAGE_CELL_16; + break; + case PID_CELLVOLTAGE_CELL_16: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_16; + poll_pid = PID_CELLVOLTAGE_CELL_17; + break; + case PID_CELLVOLTAGE_CELL_17: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_17; + poll_pid = PID_CELLVOLTAGE_CELL_18; + break; + case PID_CELLVOLTAGE_CELL_18: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_18; + poll_pid = PID_CELLVOLTAGE_CELL_19; + break; + case PID_CELLVOLTAGE_CELL_19: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_19; + poll_pid = PID_CELLVOLTAGE_CELL_20; + break; + case PID_CELLVOLTAGE_CELL_20: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_20; + poll_pid = PID_CELLVOLTAGE_CELL_21; + break; + case PID_CELLVOLTAGE_CELL_21: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_21; + poll_pid = PID_CELLVOLTAGE_CELL_22; + break; + case PID_CELLVOLTAGE_CELL_22: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_22; + poll_pid = PID_CELLVOLTAGE_CELL_23; + break; + case PID_CELLVOLTAGE_CELL_23: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_23; + poll_pid = PID_CELLVOLTAGE_CELL_24; + break; + case PID_CELLVOLTAGE_CELL_24: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_24; + poll_pid = PID_CELLVOLTAGE_CELL_25; + break; + case PID_CELLVOLTAGE_CELL_25: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_25; + poll_pid = PID_CELLVOLTAGE_CELL_26; + break; + case PID_CELLVOLTAGE_CELL_26: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_26; + poll_pid = PID_CELLVOLTAGE_CELL_27; + break; + case PID_CELLVOLTAGE_CELL_27: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_27; + poll_pid = PID_CELLVOLTAGE_CELL_28; + break; + case PID_CELLVOLTAGE_CELL_28: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_28; + poll_pid = PID_CELLVOLTAGE_CELL_29; + break; + case PID_CELLVOLTAGE_CELL_29: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_29; + poll_pid = PID_CELLVOLTAGE_CELL_30; + break; + case PID_CELLVOLTAGE_CELL_30: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_30; + poll_pid = PID_CELLVOLTAGE_CELL_31; + break; + case PID_CELLVOLTAGE_CELL_31: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_31; + poll_pid = PID_CELLVOLTAGE_CELL_32; + break; + case PID_CELLVOLTAGE_CELL_32: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_32; + poll_pid = PID_CELLVOLTAGE_CELL_33; + break; + case PID_CELLVOLTAGE_CELL_33: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_33; + poll_pid = PID_CELLVOLTAGE_CELL_34; + break; + case PID_CELLVOLTAGE_CELL_34: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_34; + poll_pid = PID_CELLVOLTAGE_CELL_35; + break; + case PID_CELLVOLTAGE_CELL_35: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_35; + poll_pid = PID_CELLVOLTAGE_CELL_36; + break; + case PID_CELLVOLTAGE_CELL_36: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_36; + poll_pid = PID_CELLVOLTAGE_CELL_37; + break; + case PID_CELLVOLTAGE_CELL_37: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_37; + poll_pid = PID_CELLVOLTAGE_CELL_38; + break; + case PID_CELLVOLTAGE_CELL_38: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_38; + poll_pid = PID_CELLVOLTAGE_CELL_39; + break; + case PID_CELLVOLTAGE_CELL_39: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_39; + poll_pid = PID_CELLVOLTAGE_CELL_40; + break; + case PID_CELLVOLTAGE_CELL_40: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_40; + poll_pid = PID_CELLVOLTAGE_CELL_41; + break; + case PID_CELLVOLTAGE_CELL_41: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_41; + poll_pid = PID_CELLVOLTAGE_CELL_42; + break; + case PID_CELLVOLTAGE_CELL_42: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_42; + poll_pid = PID_CELLVOLTAGE_CELL_43; + break; + case PID_CELLVOLTAGE_CELL_43: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_43; + poll_pid = PID_CELLVOLTAGE_CELL_44; + break; + case PID_CELLVOLTAGE_CELL_44: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_44; + poll_pid = PID_CELLVOLTAGE_CELL_45; + break; + case PID_CELLVOLTAGE_CELL_45: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_45; + poll_pid = PID_CELLVOLTAGE_CELL_46; + break; + case PID_CELLVOLTAGE_CELL_46: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_46; + poll_pid = PID_CELLVOLTAGE_CELL_47; + break; + case PID_CELLVOLTAGE_CELL_47: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_47; + poll_pid = PID_CELLVOLTAGE_CELL_48; + break; + case PID_CELLVOLTAGE_CELL_48: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_48; + poll_pid = PID_CELLVOLTAGE_CELL_49; + break; + case PID_CELLVOLTAGE_CELL_49: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_49; + poll_pid = PID_CELLVOLTAGE_CELL_50; + break; + case PID_CELLVOLTAGE_CELL_50: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_50; + poll_pid = PID_CELLVOLTAGE_CELL_51; + break; + case PID_CELLVOLTAGE_CELL_51: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_51; + poll_pid = PID_CELLVOLTAGE_CELL_52; + break; + case PID_CELLVOLTAGE_CELL_52: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_52; + poll_pid = PID_CELLVOLTAGE_CELL_53; + break; + case PID_CELLVOLTAGE_CELL_53: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_53; + poll_pid = PID_CELLVOLTAGE_CELL_54; + break; + case PID_CELLVOLTAGE_CELL_54: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_54; + poll_pid = PID_CELLVOLTAGE_CELL_55; + break; + case PID_CELLVOLTAGE_CELL_55: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_55; + poll_pid = PID_CELLVOLTAGE_CELL_56; + break; + case PID_CELLVOLTAGE_CELL_56: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_56; + poll_pid = PID_CELLVOLTAGE_CELL_57; + break; + case PID_CELLVOLTAGE_CELL_57: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_57; + poll_pid = PID_CELLVOLTAGE_CELL_58; + break; + case PID_CELLVOLTAGE_CELL_58: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_58; + poll_pid = PID_CELLVOLTAGE_CELL_59; + break; + case PID_CELLVOLTAGE_CELL_59: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_59; + poll_pid = PID_CELLVOLTAGE_CELL_60; + break; + case PID_CELLVOLTAGE_CELL_60: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_60; + poll_pid = PID_CELLVOLTAGE_CELL_61; + break; + case PID_CELLVOLTAGE_CELL_61: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_61; + poll_pid = PID_CELLVOLTAGE_CELL_62; + break; + case PID_CELLVOLTAGE_CELL_62: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_62; + poll_pid = PID_CELLVOLTAGE_CELL_63; + break; + case PID_CELLVOLTAGE_CELL_63: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_63; + poll_pid = PID_CELLVOLTAGE_CELL_64; + break; + case PID_CELLVOLTAGE_CELL_64: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_64; + poll_pid = PID_CELLVOLTAGE_CELL_65; + break; + case PID_CELLVOLTAGE_CELL_65: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_65; + poll_pid = PID_CELLVOLTAGE_CELL_66; + break; + case PID_CELLVOLTAGE_CELL_66: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_66; + poll_pid = PID_CELLVOLTAGE_CELL_67; + break; + case PID_CELLVOLTAGE_CELL_67: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_67; + poll_pid = PID_CELLVOLTAGE_CELL_68; + break; + case PID_CELLVOLTAGE_CELL_68: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_68; + poll_pid = PID_CELLVOLTAGE_CELL_69; + break; + case PID_CELLVOLTAGE_CELL_69: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_69; + poll_pid = PID_CELLVOLTAGE_CELL_70; + break; + case PID_CELLVOLTAGE_CELL_70: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_70; + poll_pid = PID_CELLVOLTAGE_CELL_71; + break; + case PID_CELLVOLTAGE_CELL_71: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_71; + poll_pid = PID_CELLVOLTAGE_CELL_72; + break; + case PID_CELLVOLTAGE_CELL_72: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_72; + poll_pid = PID_CELLVOLTAGE_CELL_73; + break; + case PID_CELLVOLTAGE_CELL_73: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_73; + poll_pid = PID_CELLVOLTAGE_CELL_74; + break; + case PID_CELLVOLTAGE_CELL_74: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_74; + poll_pid = PID_CELLVOLTAGE_CELL_75; + break; + case PID_CELLVOLTAGE_CELL_75: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_75; + poll_pid = PID_CELLVOLTAGE_CELL_76; + break; + case PID_CELLVOLTAGE_CELL_76: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_76; + poll_pid = PID_CELLVOLTAGE_CELL_77; + break; + case PID_CELLVOLTAGE_CELL_77: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_77; + poll_pid = PID_CELLVOLTAGE_CELL_78; + break; + case PID_CELLVOLTAGE_CELL_78: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_78; + poll_pid = PID_CELLVOLTAGE_CELL_79; + break; + case PID_CELLVOLTAGE_CELL_79: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_79; + poll_pid = PID_CELLVOLTAGE_CELL_80; + break; + case PID_CELLVOLTAGE_CELL_80: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_80; + poll_pid = PID_CELLVOLTAGE_CELL_81; + break; + case PID_CELLVOLTAGE_CELL_81: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_81; + poll_pid = PID_CELLVOLTAGE_CELL_82; + break; + case PID_CELLVOLTAGE_CELL_82: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_82; + poll_pid = PID_CELLVOLTAGE_CELL_83; + break; + case PID_CELLVOLTAGE_CELL_83: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_83; + poll_pid = PID_CELLVOLTAGE_CELL_84; + break; + case PID_CELLVOLTAGE_CELL_84: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_84; + poll_pid = PID_CELLVOLTAGE_CELL_85; + break; + case PID_CELLVOLTAGE_CELL_85: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_85; + poll_pid = PID_CELLVOLTAGE_CELL_86; + break; + case PID_CELLVOLTAGE_CELL_86: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_86; + poll_pid = PID_CELLVOLTAGE_CELL_87; + break; + case PID_CELLVOLTAGE_CELL_87: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_87; + poll_pid = PID_CELLVOLTAGE_CELL_88; + break; + case PID_CELLVOLTAGE_CELL_88: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_88; + poll_pid = PID_CELLVOLTAGE_CELL_89; + break; + case PID_CELLVOLTAGE_CELL_89: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_89; + poll_pid = PID_CELLVOLTAGE_CELL_90; + break; + case PID_CELLVOLTAGE_CELL_90: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_90; + poll_pid = PID_CELLVOLTAGE_CELL_91; + break; + case PID_CELLVOLTAGE_CELL_91: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_91; + poll_pid = PID_CELLVOLTAGE_CELL_92; + break; + case PID_CELLVOLTAGE_CELL_92: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_92; + poll_pid = PID_CELLVOLTAGE_CELL_93; + break; + case PID_CELLVOLTAGE_CELL_93: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_93; + poll_pid = PID_CELLVOLTAGE_CELL_94; + break; + case PID_CELLVOLTAGE_CELL_94: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_94; + poll_pid = PID_CELLVOLTAGE_CELL_95; + break; + case PID_CELLVOLTAGE_CELL_95: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_95; + poll_pid = PID_CELLVOLTAGE_CELL_96; + break; + case PID_CELLVOLTAGE_CELL_96: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_96; + poll_pid = PID_CELLVOLTAGE_CELL_97; + break; + case PID_CELLVOLTAGE_CELL_97: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_97; + poll_pid = PID_CELLVOLTAGE_CELL_98; + break; + case PID_CELLVOLTAGE_CELL_98: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_98; + poll_pid = PID_CELLVOLTAGE_CELL_99; + break; + case PID_CELLVOLTAGE_CELL_99: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_99; + poll_pid = PID_CELLVOLTAGE_CELL_100; + break; + case PID_CELLVOLTAGE_CELL_100: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_100; + poll_pid = PID_CELLVOLTAGE_CELL_101; + break; + case PID_CELLVOLTAGE_CELL_101: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_101; + poll_pid = PID_CELLVOLTAGE_CELL_102; + break; + case PID_CELLVOLTAGE_CELL_102: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_102; + poll_pid = PID_CELLVOLTAGE_CELL_103; + break; + case PID_CELLVOLTAGE_CELL_103: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_103; + poll_pid = PID_CELLVOLTAGE_CELL_104; + break; + case PID_CELLVOLTAGE_CELL_104: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_104; + poll_pid = PID_CELLVOLTAGE_CELL_105; + break; + case PID_CELLVOLTAGE_CELL_105: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_105; + poll_pid = PID_CELLVOLTAGE_CELL_106; + break; + case PID_CELLVOLTAGE_CELL_106: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_106; + poll_pid = PID_CELLVOLTAGE_CELL_107; + break; + case PID_CELLVOLTAGE_CELL_107: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_107; + poll_pid = PID_CELLVOLTAGE_CELL_108; + break; + case PID_CELLVOLTAGE_CELL_108: + MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_108; + poll_pid = PID_SOC; + break; + default: + poll_pid = PID_SOC; + break; + } + if (first_can_msg > 0 && currentMillis > first_can_msg + 2000) { + transmit_can(&MEB_POLLING_FRAME, can_config.battery); + } + } + + // Send 500ms CAN Message + if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) { + previousMillis500ms = currentMillis; + + transmit_can(&MEB_16A954B4, can_config.battery); //eTM, Cooling valves and pumps for BMS + transmit_can(&MEB_569, can_config.battery); // Battery heating requests + transmit_can(&MEB_1A55552B, can_config.battery); //Climate, heatpump and priorities + transmit_can(&MEB_1A555548, can_config.battery); //ORU, OTA update message for reserving battery + transmit_can(&MEB_16A954FB, can_config.battery); //Climate, request to BMS for starting preconditioning + } + + //Send 1s CANFD message + if (currentMillis - previousMillis1s >= INTERVAL_1_S) { + previousMillis1s = currentMillis; + + MEB_641.data.u8[1] = ((MEB_641.data.u8[1] & 0xF0) | counter_1000ms); + MEB_641.data.u8[0] = vw_crc_calc(MEB_641.data.u8, MEB_641.DLC, MEB_641.ID); + + MEB_1A5555A6.data.u8[2] = 0x7F; //Outside temperature, factor 0.5, offset -50 + + MEB_6B2.data.u8[0] = //driving cycle counter, 0-254 wrap around. 255 = invalid value + //MEB_6B2.data.u8[1-2-3b0-4] // Odometer, km (20 bits long) + MEB_6B2.data.u8[3] = (uint8_t)((TIME_YEAR - 2000) << 4) | MEB_6B2.data.u8[3]; + MEB_6B2.data.u8[4] = (uint8_t)((TIME_DAY & 0x01) << 7 | TIME_MONTH << 3 | (TIME_YEAR - 2000) >> 4); + MEB_6B2.data.u8[5] = (uint8_t)((TIME_HOUR & 0x0F) << 4 | TIME_DAY >> 1); + MEB_6B2.data.u8[6] = (uint8_t)((seconds & 0x01) << 7 | TIME_MINUTE << 1 | TIME_HOUR >> 4); + MEB_6B2.data.u8[7] = (uint8_t)((seconds & 0x3E) >> 1); + seconds = (seconds + 1) % 60; + + counter_1000ms = (counter_1000ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. + transmit_can(&MEB_6B2, can_config.battery); // Diagnostics - Needed for contactor closing + transmit_can(&MEB_641, can_config.battery); // Motor - OBD + transmit_can(&MEB_5F5, can_config.battery); // Loading profile + transmit_can(&MEB_585, can_config.battery); // Systeminfo + transmit_can(&MEB_1A5555A6, can_config.battery); // Temperature QBit + } +} + +void setup_battery(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, "Volkswagen Group MEB platform via CAN-FD", 63); + datalayer.system.info.battery_protocol[63] = '\0'; + datalayer.battery.info.number_of_cells = 108; //Startup in 108S mode. We figure out the actual count later. + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_108S_DV; //Defined later to correct pack size + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_84S_DV; //Defined later to correct pack size + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; +} + +#endif diff --git a/Software/src/battery/MEB-BATTERY.h b/Software/src/battery/MEB-BATTERY.h new file mode 100644 index 000000000..3648dec40 --- /dev/null +++ b/Software/src/battery/MEB-BATTERY.h @@ -0,0 +1,138 @@ +#ifndef MEB_BATTERY_H +#define MEB_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED +#define MAX_PACK_VOLTAGE_84S_DV 3528 //5000 = 500.0V +#define MIN_PACK_VOLTAGE_84S_DV 2520 +#define MAX_PACK_VOLTAGE_96S_DV 4032 +#define MIN_PACK_VOLTAGE_96S_DV 2880 +#define MAX_PACK_VOLTAGE_108S_DV 4536 +#define MIN_PACK_VOLTAGE_108S_DV 3240 +#define MAX_CELL_DEVIATION_MV 150 +#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value + +#define PID_SOC 0x028C +#define PID_VOLTAGE 0x1E3B +#define PID_CURRENT 0x1E3D +#define PID_MAX_TEMP 0x1E0E +#define PID_MIN_TEMP 0x1E0F +#define PID_MAX_CHARGE_VOLTAGE 0x5171 +#define PID_MIN_DISCHARGE_VOLTAGE 0x5170 +#define PID_ALLOWED_CHARGE_POWER 0x1E1B +#define PID_ALLOWED_DISCHARGE_POWER 0x1E1C +#define PID_CELLVOLTAGE_CELL_1 0x1E40 +#define PID_CELLVOLTAGE_CELL_2 0x1E41 +#define PID_CELLVOLTAGE_CELL_3 0x1E42 +#define PID_CELLVOLTAGE_CELL_4 0x1E43 +#define PID_CELLVOLTAGE_CELL_5 0x1E44 +#define PID_CELLVOLTAGE_CELL_6 0x1E45 +#define PID_CELLVOLTAGE_CELL_7 0x1E46 +#define PID_CELLVOLTAGE_CELL_8 0x1E47 +#define PID_CELLVOLTAGE_CELL_9 0x1E48 +#define PID_CELLVOLTAGE_CELL_10 0x1E49 +#define PID_CELLVOLTAGE_CELL_11 0x1E4A +#define PID_CELLVOLTAGE_CELL_12 0x1E4B +#define PID_CELLVOLTAGE_CELL_13 0x1E4C +#define PID_CELLVOLTAGE_CELL_14 0x1E4D +#define PID_CELLVOLTAGE_CELL_15 0x1E4E +#define PID_CELLVOLTAGE_CELL_16 0x1E4F +#define PID_CELLVOLTAGE_CELL_17 0x1E50 +#define PID_CELLVOLTAGE_CELL_18 0x1E51 +#define PID_CELLVOLTAGE_CELL_19 0x1E52 +#define PID_CELLVOLTAGE_CELL_20 0x1E53 +#define PID_CELLVOLTAGE_CELL_21 0x1E54 +#define PID_CELLVOLTAGE_CELL_22 0x1E55 +#define PID_CELLVOLTAGE_CELL_23 0x1E56 +#define PID_CELLVOLTAGE_CELL_24 0x1E57 +#define PID_CELLVOLTAGE_CELL_25 0x1E58 +#define PID_CELLVOLTAGE_CELL_26 0x1E59 +#define PID_CELLVOLTAGE_CELL_27 0x1E5A +#define PID_CELLVOLTAGE_CELL_28 0x1E5B +#define PID_CELLVOLTAGE_CELL_29 0x1E5C +#define PID_CELLVOLTAGE_CELL_30 0x1E5D +#define PID_CELLVOLTAGE_CELL_31 0x1E5E +#define PID_CELLVOLTAGE_CELL_32 0x1E5F +#define PID_CELLVOLTAGE_CELL_33 0x1E60 +#define PID_CELLVOLTAGE_CELL_34 0x1E61 +#define PID_CELLVOLTAGE_CELL_35 0x1E62 +#define PID_CELLVOLTAGE_CELL_36 0x1E63 +#define PID_CELLVOLTAGE_CELL_37 0x1E64 +#define PID_CELLVOLTAGE_CELL_38 0x1E65 +#define PID_CELLVOLTAGE_CELL_39 0x1E66 +#define PID_CELLVOLTAGE_CELL_40 0x1E67 +#define PID_CELLVOLTAGE_CELL_41 0x1E68 +#define PID_CELLVOLTAGE_CELL_42 0x1E69 +#define PID_CELLVOLTAGE_CELL_43 0x1E6A +#define PID_CELLVOLTAGE_CELL_44 0x1E6B +#define PID_CELLVOLTAGE_CELL_45 0x1E6C +#define PID_CELLVOLTAGE_CELL_46 0x1E6D +#define PID_CELLVOLTAGE_CELL_47 0x1E6E +#define PID_CELLVOLTAGE_CELL_48 0x1E6F +#define PID_CELLVOLTAGE_CELL_49 0x1E70 +#define PID_CELLVOLTAGE_CELL_50 0x1E71 +#define PID_CELLVOLTAGE_CELL_51 0x1E72 +#define PID_CELLVOLTAGE_CELL_52 0x1E73 +#define PID_CELLVOLTAGE_CELL_53 0x1E74 +#define PID_CELLVOLTAGE_CELL_54 0x1E75 +#define PID_CELLVOLTAGE_CELL_55 0x1E76 +#define PID_CELLVOLTAGE_CELL_56 0x1E77 +#define PID_CELLVOLTAGE_CELL_57 0x1E78 +#define PID_CELLVOLTAGE_CELL_58 0x1E79 +#define PID_CELLVOLTAGE_CELL_59 0x1E7A +#define PID_CELLVOLTAGE_CELL_60 0x1E7B +#define PID_CELLVOLTAGE_CELL_61 0x1E7C +#define PID_CELLVOLTAGE_CELL_62 0x1E7D +#define PID_CELLVOLTAGE_CELL_63 0x1E7E +#define PID_CELLVOLTAGE_CELL_64 0x1E7F +#define PID_CELLVOLTAGE_CELL_65 0x1E80 +#define PID_CELLVOLTAGE_CELL_66 0x1E81 +#define PID_CELLVOLTAGE_CELL_67 0x1E82 +#define PID_CELLVOLTAGE_CELL_68 0x1E83 +#define PID_CELLVOLTAGE_CELL_69 0x1E84 +#define PID_CELLVOLTAGE_CELL_70 0x1E85 +#define PID_CELLVOLTAGE_CELL_71 0x1E86 +#define PID_CELLVOLTAGE_CELL_72 0x1E87 +#define PID_CELLVOLTAGE_CELL_73 0x1E88 +#define PID_CELLVOLTAGE_CELL_74 0x1E89 +#define PID_CELLVOLTAGE_CELL_75 0x1E8A +#define PID_CELLVOLTAGE_CELL_76 0x1E8B +#define PID_CELLVOLTAGE_CELL_77 0x1E8C +#define PID_CELLVOLTAGE_CELL_78 0x1E8D +#define PID_CELLVOLTAGE_CELL_79 0x1E8E +#define PID_CELLVOLTAGE_CELL_80 0x1E8F +#define PID_CELLVOLTAGE_CELL_81 0x1E90 +#define PID_CELLVOLTAGE_CELL_82 0x1E91 +#define PID_CELLVOLTAGE_CELL_83 0x1E92 +#define PID_CELLVOLTAGE_CELL_84 0x1E93 +#define PID_CELLVOLTAGE_CELL_85 0x1E94 +#define PID_CELLVOLTAGE_CELL_86 0x1E95 +#define PID_CELLVOLTAGE_CELL_87 0x1E96 +#define PID_CELLVOLTAGE_CELL_88 0x1E97 +#define PID_CELLVOLTAGE_CELL_89 0x1E98 +#define PID_CELLVOLTAGE_CELL_90 0x1E99 +#define PID_CELLVOLTAGE_CELL_91 0x1E9A +#define PID_CELLVOLTAGE_CELL_92 0x1E9B +#define PID_CELLVOLTAGE_CELL_93 0x1E9C +#define PID_CELLVOLTAGE_CELL_94 0x1E9D +#define PID_CELLVOLTAGE_CELL_95 0x1E9E +#define PID_CELLVOLTAGE_CELL_96 0x1E9F +#define PID_CELLVOLTAGE_CELL_97 0x1EA0 +#define PID_CELLVOLTAGE_CELL_98 0x1EA1 +#define PID_CELLVOLTAGE_CELL_99 0x1EA2 +#define PID_CELLVOLTAGE_CELL_100 0x1EA3 +#define PID_CELLVOLTAGE_CELL_101 0x1EA4 +#define PID_CELLVOLTAGE_CELL_102 0x1EA5 +#define PID_CELLVOLTAGE_CELL_103 0x1EA6 +#define PID_CELLVOLTAGE_CELL_104 0x1EA7 +#define PID_CELLVOLTAGE_CELL_105 0x1EA8 +#define PID_CELLVOLTAGE_CELL_106 0x1EA9 +#define PID_CELLVOLTAGE_CELL_107 0x1EAA +#define PID_CELLVOLTAGE_CELL_108 0x1EAB + +void setup_battery(void); +void transmit_can(CAN_frame* tx_frame, int interface); + +#endif diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 7a9c2cd1d..e4aa0c029 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -278,6 +278,78 @@ typedef struct { } DATALAYER_INFO_NISSAN_LEAF; +typedef struct { + /** uint8_t */ + /** Service disconnect switch status */ + bool SDSW = 0; + /** uint8_t */ + /** Pilotline status */ + bool pilotline = 0; + /** uint8_t */ + /** Transportation mode status */ + bool transportmode = 0; + /** uint8_t */ + /** Componentprotection mode status */ + bool componentprotection = 0; + /** uint8_t */ + /** Shutdown status */ + bool shutdown_active = 0; + /** uint8_t */ + /** Battery heating status */ + bool battery_heating = 0; + /** uint8_t */ + /** All realtime_ warnings have same enumeration, 0 = no fault, 1 = error level 1, 2 error level 2, 3 error level 3 */ + uint8_t rt_overcurrent = 0; + uint8_t rt_CAN_fault = 0; + uint8_t rt_overcharge = 0; + uint8_t rt_SOC_high = 0; + uint8_t rt_SOC_low = 0; + uint8_t rt_SOC_jumping = 0; + uint8_t rt_temp_difference = 0; + uint8_t rt_cell_overtemp = 0; + uint8_t rt_cell_undertemp = 0; + uint8_t rt_battery_overvolt = 0; + uint8_t rt_battery_undervol = 0; + uint8_t rt_cell_overvolt = 0; + uint8_t rt_cell_undervol = 0; + uint8_t rt_cell_imbalance = 0; + uint8_t rt_battery_unathorized = 0; + /** uint8_t */ + /** HVIL status, 0 = Init, 1 = Closed, 2 = Open!, 3 = Fault */ + uint8_t HVIL = 0; + /** uint8_t */ + /** 0 = HV inactive, 1 = HV active, 2 = Balancing, 3 = Extern charging, 4 = AC charging, 5 = Battery error, 6 = DC charging, 7 = init */ + uint8_t BMS_mode = 0; + /** uint8_t */ + /** 1 = Battery display, 4 = Battery display OK, 4 = Display battery charging, 6 = Display battery check, 7 = Fault */ + uint8_t battery_diagnostic = 0; + /** uint8_t */ + /** 0 = init, 1 = no open HV line detected, 2 = open HV line , 3 = fault */ + uint8_t status_HV_line = 0; + /** uint8_t */ + /** 0 = OK, 1 = Not OK, 0x06 = init, 0x07 = fault */ + uint8_t warning_support = 0; + /** uint32_t */ + /** Isolation resistance in kOhm */ + uint32_t isolation_resistance = 0; + /** uint8_t */ + /** 0=Init, 1=BMS intermediate circuit voltage-free (U_Zwkr < 20V), 2=BMS intermediate circuit not voltage-free (U_Zwkr >/= 25V, hysteresis), 3=Error */ + uint8_t BMS_status_voltage_free = 0; + /** uint8_t */ + /** 0 Component_IO, 1 Restricted_CompFkt_Isoerror_I, 2 Restricted_CompFkt_Isoerror_II, 3 Restricted_CompFkt_Interlock, 4 Restricted_CompFkt_SD, 5 Restricted_CompFkt_Performance red, 6 = No component function, 7 = Init */ + uint8_t BMS_error_status = 0; + /** uint8_t */ + /** 0 init, 1 closed, 2 open, 3 fault */ + uint8_t BMS_Kl30c_Status = 0; + /** bool */ + /** true if BMS requests error/warning light */ + bool BMS_OBD_MIL = 0; + bool BMS_error_lamp_req = 0; + bool BMS_warning_lamp_req = 0; + int32_t BMS_voltage_intermediate_dV = 0; + int32_t BMS_voltage_dV = 0; +} DATALAYER_INFO_MEB; + typedef struct { /** uint16_t */ /** Values WIP*/ @@ -332,6 +404,7 @@ class DataLayerExtended { DATALAYER_INFO_CELLPOWER cellpower; DATALAYER_INFO_TESLA tesla; DATALAYER_INFO_NISSAN_LEAF nissanleaf; + DATALAYER_INFO_MEB meb; DATALAYER_INFO_ZOE_PH2 zoePH2; }; diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp index ee72af88b..4c5572468 100644 --- a/Software/src/devboard/safety/safety.cpp +++ b/Software/src/devboard/safety/safety.cpp @@ -97,7 +97,7 @@ void update_machineryprotection() { clear_event(EVENT_SOH_LOW); } -#if !defined(PYLON_BATTERY) && !defined(RENAULT_TWIZY_BATTERY) +#ifdef NISSAN_LEAF_BATTERY // Check if SOC% is plausible if (datalayer.battery.status.voltage_dV > (datalayer.battery.info.max_design_voltage_dV - @@ -108,7 +108,7 @@ void update_machineryprotection() { clear_event(EVENT_SOC_PLAUSIBILITY_ERROR); } } -#endif +#endif //NISSAN_LEAF_BATTERY // Check diff between highest and lowest cell cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV); diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 795848852..b0c3e2853 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -144,6 +144,7 @@ void init_events(void) { events.entries[EVENT_CANMCP_INIT_FAILURE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANFD_BUFFER_FULL].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CAN_OVERRUN].level = EVENT_LEVEL_INFO; + events.entries[EVENT_CANFD_RX_OVERRUN].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CAN_RX_FAILURE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_CAN2_RX_FAILURE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANFD_RX_FAILURE].level = EVENT_LEVEL_ERROR; @@ -270,6 +271,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) { return "CAN-FD buffer overflowed. Some CAN messages were not sent. Contact developers."; case EVENT_CAN_OVERRUN: return "CAN message failed to send within defined time. Contact developers, CPU load might be too high."; + case EVENT_CANFD_RX_OVERRUN: + return "CAN-FD failed to receive all messages from CAN bus. Contact developers, CPU load might be too high."; case EVENT_CAN_RX_FAILURE: return "No CAN communication detected for 60s. Shutting down battery control."; case EVENT_CAN2_RX_FAILURE: diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index dcdcfd6a7..b50d7de4f 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -30,6 +30,7 @@ XX(EVENT_CANMCP_INIT_FAILURE) \ XX(EVENT_CANFD_BUFFER_FULL) \ XX(EVENT_CAN_OVERRUN) \ + XX(EVENT_CANFD_RX_OVERRUN) \ XX(EVENT_CAN_RX_FAILURE) \ XX(EVENT_CAN2_RX_FAILURE) \ XX(EVENT_CANFD_RX_FAILURE) \ diff --git a/Software/src/devboard/utils/types.h b/Software/src/devboard/utils/types.h index 5af0845f5..126aff261 100644 --- a/Software/src/devboard/utils/types.h +++ b/Software/src/devboard/utils/types.h @@ -13,7 +13,9 @@ enum led_color { GREEN, YELLOW, RED, BLUE, RGB }; #define INTERVAL_10_MS 10 #define INTERVAL_20_MS 20 #define INTERVAL_30_MS 30 +#define INTERVAL_40_MS 40 #define INTERVAL_50_MS 50 +#define INTERVAL_70_MS 70 #define INTERVAL_100_MS 100 #define INTERVAL_200_MS 200 #define INTERVAL_250_MS 250 diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index b3cba77f5..5806bb32a 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -420,6 +420,205 @@ String advanced_battery_processor(const String& var) { content += "

Challenge failed: " + String(datalayer_extended.nissanleaf.challengeFailed) + "

"; #endif +#ifdef MEB_BATTERY + content += datalayer_extended.meb.SDSW ? "

Service disconnect switch: Missing!

" + : "

Service disconnect switch: OK

"; + content += datalayer_extended.meb.pilotline ? "

Pilotline: Open!

" : "

Pilotline: OK

"; + content += datalayer_extended.meb.transportmode ? "

Transportmode: Locked!

" : "

Transportmode: OK

"; + content += datalayer_extended.meb.shutdown_active ? "

Shutdown: Active!

" : "

Shutdown: No

"; + content += datalayer_extended.meb.componentprotection ? "

Component protection: Active!

" + : "

Component protection: No

"; + content += "

HVIL status: "; + switch (datalayer_extended.meb.HVIL) { + case 0: + content += String("Init"); + break; + case 1: + content += String("Closed"); + break; + case 2: + content += String("Open!"); + break; + case 3: + content += String("Fault"); + break; + default: + content += String("?"); + } + content += "

KL30C status: "; + switch (datalayer_extended.meb.BMS_Kl30c_Status) { + case 0: + content += String("Init"); + break; + case 1: + content += String("Closed"); + break; + case 2: + content += String("Open!"); + break; + case 3: + content += String("Fault"); + break; + default: + content += String("?"); + } + content += "

BMS mode: "; + switch (datalayer_extended.meb.BMS_mode) { + case 0: + content += String("HV inactive"); + break; + case 1: + content += String("HV active"); + break; + case 2: + content += String("Balancing"); + break; + case 3: + content += String("Extern charging"); + break; + case 4: + content += String("AC charging"); + break; + case 5: + content += String("Battery error"); + break; + case 6: + content += String("DC charging"); + break; + case 7: + content += String("Init"); + break; + default: + content += String("?"); + } + content += "

Diagnostic: "; + switch (datalayer_extended.meb.battery_diagnostic) { + case 0: + content += String("Init"); + break; + case 1: + content += String("Battery display"); + break; + case 4: + content += String("Battery display OK"); + break; + case 6: + content += String("Battery display check"); + break; + case 7: + content += String("Fault"); + break; + default: + content += String("?"); + } + content += "

HV line status: "; + switch (datalayer_extended.meb.status_HV_line) { + case 0: + content += String("Init"); + break; + case 1: + content += String("No open HV line detected"); + break; + case 2: + content += String("Open HV line"); + break; + case 3: + content += String("Fault"); + break; + default: + content += String("? ") + String(datalayer_extended.meb.status_HV_line); + } + content += "

Warning support: "; + switch (datalayer_extended.meb.warning_support) { + case 0: + content += String("OK"); + break; + case 1: + content += String("Not OK"); + break; + case 6: + content += String("Init"); + break; + case 7: + content += String("Fault"); + break; + default: + content += String("?"); + } + content += "

Interm. Voltage (" + String(datalayer_extended.meb.BMS_voltage_intermediate_dV / 10.0, 1) + + "V) status: "; + switch (datalayer_extended.meb.BMS_status_voltage_free) { + case 0: + content += String("Init"); + break; + case 1: + content += String("BMS interm circuit voltage free (U<20V)"); + break; + case 2: + content += String("BMS interm circuit not voltage free (U >= 25V)"); + break; + case 3: + content += String("Error"); + break; + default: + content += String("?"); + } + content += "

BMS error status: "; + switch (datalayer_extended.meb.BMS_error_status) { + case 0: + content += String("Component IO"); + break; + case 1: + content += String("Iso Error 1"); + break; + case 2: + content += String("Iso Error 2"); + break; + case 3: + content += String("Interlock"); + break; + case 4: + content += String("SD"); + break; + case 5: + content += String("Performance red"); + break; + case 6: + content += String("No component function"); + break; + case 7: + content += String("Init"); + break; + default: + content += String("?"); + } + content += "

BMS voltage: " + String(datalayer_extended.meb.BMS_voltage_dV / 10.0, 1) + "

"; + content += datalayer_extended.meb.BMS_OBD_MIL ? "

OBD MIL: ON!

" : "

OBD MIL: Off

"; + content += + datalayer_extended.meb.BMS_error_lamp_req ? "

Red error lamp: ON!

" : "

Red error lamp: Off

"; + content += datalayer_extended.meb.BMS_warning_lamp_req ? "

Yellow warning lamp: ON!

" + : "

Yellow warning lamp: Off

"; + content += "

Isolation resistance: " + String(datalayer_extended.meb.isolation_resistance) + " kOhm

"; + content += + datalayer_extended.meb.battery_heating ? "

Battery heating: Active!

" : "

Battery heating: Off

"; + const char* rt_enum[] = {"No", "Error level 1", "Error level 2", "Error level 3"}; + content += "

Overcurrent: " + String(rt_enum[datalayer_extended.meb.rt_overcurrent]) + "

"; + content += "

CAN fault: " + String(rt_enum[datalayer_extended.meb.rt_CAN_fault]) + "

"; + content += "

Overcharged: " + String(rt_enum[datalayer_extended.meb.rt_overcharge]) + "

"; + content += "

SOC too high: " + String(rt_enum[datalayer_extended.meb.rt_SOC_high]) + "

"; + content += "

SOC too low: " + String(rt_enum[datalayer_extended.meb.rt_SOC_low]) + "

"; + content += "

SOC jumping: " + String(rt_enum[datalayer_extended.meb.rt_SOC_jumping]) + "

"; + content += "

Temp difference: " + String(rt_enum[datalayer_extended.meb.rt_temp_difference]) + "

"; + content += "

Cell overtemp: " + String(rt_enum[datalayer_extended.meb.rt_cell_overtemp]) + "

"; + content += "

Cell undertemp: " + String(rt_enum[datalayer_extended.meb.rt_cell_undertemp]) + "

"; + content += "

Battery overvoltage: " + String(rt_enum[datalayer_extended.meb.rt_battery_overvolt]) + "

"; + content += "

Battery undervoltage: " + String(rt_enum[datalayer_extended.meb.rt_battery_undervol]) + "

"; + content += "

Cell overvoltage: " + String(rt_enum[datalayer_extended.meb.rt_cell_overvolt]) + "

"; + content += "

Cell undervoltage: " + String(rt_enum[datalayer_extended.meb.rt_cell_undervol]) + "

"; + content += "

Cell imbalance: " + String(rt_enum[datalayer_extended.meb.rt_cell_imbalance]) + "

"; + content += "

Battery unathorized: " + String(rt_enum[datalayer_extended.meb.rt_battery_unathorized]) + "

"; +#endif //MEB_BATTERY + #ifdef RENAULT_ZOE_GEN2_BATTERY content += "

soc: " + String(datalayer_extended.zoePH2.battery_soc) + "

"; content += "

usable soc: " + String(datalayer_extended.zoePH2.battery_usable_soc) + "

"; @@ -467,8 +666,9 @@ String advanced_battery_processor(const String& var) { content += "

soc max: " + String(datalayer_extended.zoePH2.battery_soc_max) + "

"; #endif //RENAULT_ZOE_GEN2_BATTERY -#if !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ - !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) +#if !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ + !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ + !defined(MEB_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif diff --git a/Software/src/devboard/webserver/events_html.cpp b/Software/src/devboard/webserver/events_html.cpp index 18915e6a5..3cb3edbe8 100644 --- a/Software/src/devboard/webserver/events_html.cpp +++ b/Software/src/devboard/webserver/events_html.cpp @@ -60,8 +60,8 @@ String events_processor(const String& var) { order_events.clear(); content.concat(FPSTR(EVENTS_HTML_END)); return content; - return String(); } + return String(); } /* Script for displaying event log before it gets minified From 025a9feb02cbc53d15dff9116444bc31e53e87b1 Mon Sep 17 00:00:00 2001 From: mvgalen Date: Mon, 2 Dec 2024 22:31:25 +0100 Subject: [PATCH 024/225] Improvement: General MEB improvements (#654) * Update MEB-BATTERY.cpp - Only use values form CAN message if BMS is not in init state. - Quickly determine number of cell of the pack - Use broadcast battery_voltage and battery_SOC - Set default SOC to 0.05% to prevent battery empty event on startup * Add BMS_HVIL_STATUS as source for HVIL_FAILURE event --- Software/src/battery/MEB-BATTERY.cpp | 63 +++++++++++++++++++--------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/Software/src/battery/MEB-BATTERY.cpp b/Software/src/battery/MEB-BATTERY.cpp index c6dc918cb..643824ee7 100644 --- a/Software/src/battery/MEB-BATTERY.cpp +++ b/Software/src/battery/MEB-BATTERY.cpp @@ -8,12 +8,15 @@ /* TODO list -- Get contactors closing -- What CAN messages needs to be sent towards the battery to keep it alive - Check value mappings on the PID polls -- Check value mappings on the constantly broadcasted messages - Check all TODO:s in the code - 0x1B000044 & 1B00008F seems to be missing from logs? (Classic CAN) +- Scaled remaining capacity, should take already scaled total capacity into account, or we +should undo the scaling on the total capacity (which is calculated from the ah value now, +which is scaled already). +- Investigate why opening and then closing contactors from webpage does not always work +- Invertigate why contactors don't close when lilygo and battery are powered on simultaneously -> timeout on can msgs triggers to late, reset when open contactors is executed +- Find out how to get the battery in balancing mode */ /* Do not change code below unless you are sure what you are doing */ @@ -38,7 +41,8 @@ static uint8_t counter_040 = 0; static uint8_t counter_0F7 = 0; static uint8_t counter_3b5 = 0; -static uint32_t poll_pid = 0; +static uint32_t poll_pid = PID_CELLVOLTAGE_CELL_85; // We start here to quickly determine the cell size of the pack. +static bool nof_cells_determined = false; static uint32_t pid_reply = 0; static uint16_t battery_soc_polled = 0; static uint16_t battery_voltage_polled = 1480; @@ -74,7 +78,7 @@ static uint16_t BMS_current = 16300; static bool BMS_fault_emergency_shutdown_crash = false; //Error: Safety-critical error (crash detection) Battery contactors are already opened / will be opened immediately Signal is read directly by the EMS and initiates an AKS of the PWR and an active discharge of the DC link static uint32_t BMS_voltage_intermediate = 0; -static uint32_t BMS_voltage = 0; +static uint32_t BMS_voltage = 1480; static uint8_t BMS_status_voltage_free = 0; //0=Init, 1=BMS intermediate circuit voltage-free (U_Zwkr < 20V), 2=BMS intermediate circuit not voltage-free (U_Zwkr >/= 25V, hysteresis), 3=Error static bool BMS_OBD_MIL = false; @@ -96,7 +100,7 @@ static uint16_t max_discharge_power_watt = 0; static uint16_t max_discharge_current_amp = 0; static uint16_t max_charge_power_watt = 0; static uint16_t max_charge_current_amp = 0; -static uint16_t battery_SOC = 0; +static uint16_t battery_SOC = 1; static uint16_t usable_energy_amount_Wh = 0; static uint8_t status_HV_line = 0; //0 init, 1 No open HV line, 2 open HV line detected, 3 fault static uint8_t warning_support = 0; @@ -514,12 +518,12 @@ uint8_t vw_crc_calc(uint8_t* inputBytes, uint8_t length, uint16_t address) { void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus - datalayer.battery.status.real_soc = battery_soc_polled * 10; + datalayer.battery.status.real_soc = battery_SOC * 5; //*0.05*100 battery_soc_polled * 10; //Alternatively use battery_SOC for more precision datalayer.battery.status.soh_pptt; - datalayer.battery.status.voltage_dV = battery_voltage_polled * 2.5; + datalayer.battery.status.voltage_dV = BMS_voltage * 2.5; // *0.25*10 datalayer.battery.status.current_dA = (BMS_current / 10) - 1630; @@ -570,7 +574,7 @@ void update_values_battery() { //This function maps all the values fetched via } else { clear_event(EVENT_HVIL_FAILURE); } - if (pilotline_open) { + if (pilotline_open || BMS_HVIL_status == 2) { set_event(EVENT_HVIL_FAILURE, 2); } else { clear_event(EVENT_HVIL_FAILURE); @@ -649,10 +653,12 @@ void receive_can_battery(CAN_frame rx_frame) { break; case 0x12DD54D1: // BMS 100ms datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - battery_SOC = ((rx_frame.data.u8[3] & 0x0F) << 7) | (rx_frame.data.u8[2] >> 1); //*0.05 - usable_energy_amount_Wh = (rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]; //*5 - power_discharge_percentage = ((rx_frame.data.u8[4] & 0x3F) << 4) | rx_frame.data.u8[3] >> 4; //*0.2 - power_charge_percentage = (rx_frame.data.u8[5] << 2) | rx_frame.data.u8[4] >> 6; //*0.2 + if (rx_frame.data.u8[6] != 0xFE || rx_frame.data.u8[7] != 0xFF) { // Init state, values below invalid + battery_SOC = ((rx_frame.data.u8[3] & 0x0F) << 7) | (rx_frame.data.u8[2] >> 1); //*0.05 + usable_energy_amount_Wh = (rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]; //*5 + power_discharge_percentage = ((rx_frame.data.u8[4] & 0x3F) << 4) | rx_frame.data.u8[3] >> 4; //*0.2 + power_charge_percentage = (rx_frame.data.u8[5] << 2) | rx_frame.data.u8[4] >> 6; //*0.2 + } status_HV_line = ((rx_frame.data.u8[2] & 0x01) << 1) | rx_frame.data.u8[1] >> 7; warning_support = (rx_frame.data.u8[1] & 0x70) >> 4; break; @@ -939,10 +945,12 @@ void receive_can_battery(CAN_frame rx_frame) { BMS_status_voltage_free = (rx_frame.data.u8[1] & 0xC0) >> 6; BMS_OBD_MIL = (rx_frame.data.u8[2] & 0x01); BMS_error_status = (rx_frame.data.u8[2] & 0x70) >> 4; - BMS_capacity_ah = ((rx_frame.data.u8[4] & 0x03) << 9) | (rx_frame.data.u8[3] << 1) | (rx_frame.data.u8[2] >> 7); BMS_error_lamp_req = (rx_frame.data.u8[4] & 0x04) >> 2; BMS_warning_lamp_req = (rx_frame.data.u8[4] & 0x08) >> 3; BMS_Kl30c_Status = (rx_frame.data.u8[4] & 0x30) >> 4; + if (BMS_Kl30c_Status != 0) { // init state + BMS_capacity_ah = ((rx_frame.data.u8[4] & 0x03) << 9) | (rx_frame.data.u8[3] << 1) | (rx_frame.data.u8[2] >> 7); + } break; case 0x5CA: // BMS 500ms BMS_5CA_CRC = rx_frame.data.u8[0]; // Can be used to check CAN signal integrity later on @@ -977,10 +985,12 @@ void receive_can_battery(CAN_frame rx_frame) { BMS_error_shutdown = (rx_frame.data.u8[2] & 0x20) >> 5; BMS_error_shutdown_request = (rx_frame.data.u8[2] & 0x40) >> 6; BMS_fault_performance = (rx_frame.data.u8[2] & 0x80) >> 7; - BMS_current = ((rx_frame.data.u8[4] & 0x7F) << 8) | rx_frame.data.u8[3]; BMS_fault_emergency_shutdown_crash = (rx_frame.data.u8[4] & 0x80) >> 7; - BMS_voltage_intermediate = (((rx_frame.data.u8[6] & 0x0F) << 8) + (rx_frame.data.u8[5])); - BMS_voltage = ((rx_frame.data.u8[7] << 4) + ((rx_frame.data.u8[6] & 0xF0) >> 4)); + if (BMS_mode != 7) { // Init state, values below are invalid + BMS_current = ((rx_frame.data.u8[4] & 0x7F) << 8) | rx_frame.data.u8[3]; + BMS_voltage_intermediate = (((rx_frame.data.u8[6] & 0x0F) << 8) + (rx_frame.data.u8[5])); + BMS_voltage = ((rx_frame.data.u8[7] << 4) + ((rx_frame.data.u8[6] & 0xF0) >> 4)); + } break; case 0x1C42007B: // Reply from battery if (rx_frame.data.u8[0] == 0x10) { //PID header @@ -1277,6 +1287,7 @@ void receive_can_battery(CAN_frame rx_frame) { cellvoltages_polled[84] = (tempval + 1000); } else { // Cell 85 unavailable. We have a 84S battery (48kWh) datalayer.battery.info.number_of_cells = 84; + nof_cells_determined = true; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_84S_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_84S_DV; } @@ -1356,6 +1367,7 @@ void receive_can_battery(CAN_frame rx_frame) { // Do nothing, we already identified it as 84S } else { datalayer.battery.info.number_of_cells = 96; + nof_cells_determined = true; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_96S_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_96S_DV; } @@ -1423,6 +1435,8 @@ void receive_can_battery(CAN_frame rx_frame) { break; case PID_CELLVOLTAGE_CELL_108: tempval = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + nof_cells_determined = true; // This is placed outside of the if, to make + // sure we only take the shortcuts to determine the number of cells once. if (tempval != 0xFFE) { cellvoltages_polled[107] = (tempval + 1000); datalayer.battery.info.number_of_cells = 108; @@ -1948,7 +1962,15 @@ void send_can_battery() { break; case PID_CELLVOLTAGE_CELL_84: MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_84; - poll_pid = PID_CELLVOLTAGE_CELL_85; + if (datalayer.battery.info.number_of_cells > 84) { + if (nof_cells_determined) { + poll_pid = PID_CELLVOLTAGE_CELL_85; + } else { + poll_pid = PID_CELLVOLTAGE_CELL_97; + } + } else { + poll_pid = PID_SOC; + } break; case PID_CELLVOLTAGE_CELL_85: MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_85; @@ -1996,7 +2018,10 @@ void send_can_battery() { break; case PID_CELLVOLTAGE_CELL_96: MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_96; - poll_pid = PID_CELLVOLTAGE_CELL_97; + if (datalayer.battery.info.number_of_cells > 96) + poll_pid = PID_CELLVOLTAGE_CELL_97; + else + poll_pid = PID_SOC; break; case PID_CELLVOLTAGE_CELL_97: MEB_POLLING_FRAME.data.u8[3] = (uint8_t)PID_CELLVOLTAGE_CELL_97; From 6f9da5b33062cc4e3b55b6e47463e9eddca8e03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 2 Dec 2024 23:37:50 +0200 Subject: [PATCH 025/225] Add OBD2 PID polling for BoltAmpera --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 537 ++++++++++++++++++- Software/src/battery/BOLT-AMPERA-BATTERY.h | 117 +++- 2 files changed, 643 insertions(+), 11 deletions(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index a6ecdd796..a0cb0e95c 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -6,21 +6,168 @@ #include "BOLT-AMPERA-BATTERY.h" /* Do not change code below unless you are sure what you are doing */ -static unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send +static unsigned long previousMillis20ms = 0; // will store last time a 20ms CAN Message was send +static unsigned long previousMillis200ms = 0; // will store last time a 200ms CAN Message was send -CAN_frame BOLT_778 = {.FD = false, +CAN_frame BOLT_778 = {.FD = false, // Unsure of what this message is, added only as example .ext_ID = false, .DLC = 7, .ID = 0x778, .data = {0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame BOLT_POLL_7E4 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E4, + .data = {0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +static uint16_t battery_cell_voltages[96]; //array with all the cellvoltages +static uint16_t battery_capacity_my17_18 = 0; +static uint16_t battery_capacity_my19plus = 0; +static uint16_t battery_SOC_display = 0; +static uint16_t battery_SOC_raw_highprec = 0; +static uint16_t battery_max_temperature = 0; +static uint16_t battery_min_temperature = 0; +static uint16_t battery_min_cell_voltage = 0; +static uint16_t battery_max_cell_voltage = 0; +static uint16_t battery_internal_resistance = 0; +static uint16_t battery_min_voltage = 0; +static uint16_t battery_max_voltage = 0; +static uint16_t battery_voltage = 3700; +static uint16_t battery_vehicle_isolation = 0; +static uint16_t battery_isolation_kohm = 0; +static uint16_t battery_HV_locked = 0; +static uint16_t battery_crash_event = 0; +static uint16_t battery_HVIL = 0; +static uint16_t battery_HVIL_status = 0; +static int16_t battery_current = 0; + +static uint8_t poll_index = 0; +static uint16_t currentpoll = POLL_CAPACITY_EST_GEN1; +static uint16_t reply_poll = 0; + +const uint16_t poll_commands[115] = {POLL_CAPACITY_EST_GEN1, + POLL_CAPACITY_EST_GEN2, + POLL_SOC_DISPLAY, + POLL_SOC_RAW_HIGHPREC, + POLL_MAX_TEMPERATURE, + POLL_MIN_TEMPERATURE, + POLL_MIN_CELL_V, + POLL_MAX_CELL_V, + POLL_INTERNAL_RES, + POLL_MIN_BATT_V, + POLL_MAX_BATT_V, + POLL_VOLTAGE, + POLL_VEHICLE_ISOLATION, + POLL_ISOLATION_TEST_KOHM, + POLL_HV_LOCKED_OUT, + POLL_CRASH_EVENT, + POLL_HVIL, + POLL_HVIL_STATUS, + POLL_CURRENT, + POLL_CELL_01, + POLL_CELL_02, + POLL_CELL_03, + POLL_CELL_04, + POLL_CELL_05, + POLL_CELL_06, + POLL_CELL_07, + POLL_CELL_08, + POLL_CELL_09, + POLL_CELL_10, + POLL_CELL_11, + POLL_CELL_12, + POLL_CELL_13, + POLL_CELL_14, + POLL_CELL_15, + POLL_CELL_16, + POLL_CELL_17, + POLL_CELL_18, + POLL_CELL_19, + POLL_CELL_20, + POLL_CELL_21, + POLL_CELL_22, + POLL_CELL_23, + POLL_CELL_24, + POLL_CELL_25, + POLL_CELL_26, + POLL_CELL_27, + POLL_CELL_28, + POLL_CELL_29, + POLL_CELL_30, + POLL_CELL_31, + POLL_CELL_32, + POLL_CELL_33, + POLL_CELL_34, + POLL_CELL_35, + POLL_CELL_36, + POLL_CELL_37, + POLL_CELL_38, + POLL_CELL_39, + POLL_CELL_40, + POLL_CELL_41, + POLL_CELL_42, + POLL_CELL_43, + POLL_CELL_44, + POLL_CELL_45, + POLL_CELL_46, + POLL_CELL_47, + POLL_CELL_48, + POLL_CELL_49, + POLL_CELL_50, + POLL_CELL_51, + POLL_CELL_52, + POLL_CELL_53, + POLL_CELL_54, + POLL_CELL_55, + POLL_CELL_56, + POLL_CELL_57, + POLL_CELL_58, + POLL_CELL_59, + POLL_CELL_60, + POLL_CELL_61, + POLL_CELL_62, + POLL_CELL_63, + POLL_CELL_64, + POLL_CELL_65, + POLL_CELL_66, + POLL_CELL_67, + POLL_CELL_68, + POLL_CELL_69, + POLL_CELL_70, + POLL_CELL_71, + POLL_CELL_72, + POLL_CELL_73, + POLL_CELL_74, + POLL_CELL_75, + POLL_CELL_76, + POLL_CELL_77, + POLL_CELL_78, + POLL_CELL_79, + POLL_CELL_80, + POLL_CELL_81, + POLL_CELL_82, + POLL_CELL_83, + POLL_CELL_84, + POLL_CELL_85, + POLL_CELL_86, + POLL_CELL_87, + POLL_CELL_88, + POLL_CELL_89, + POLL_CELL_90, + POLL_CELL_91, + POLL_CELL_92, + POLL_CELL_93, + POLL_CELL_94, + POLL_CELL_95, + POLL_CELL_96}; void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer - datalayer.battery.status.real_soc; + datalayer.battery.status.real_soc = (battery_SOC_display * 100 / 255); - datalayer.battery.status.voltage_dV; + datalayer.battery.status.voltage_dV = battery_voltage * 0.52; - datalayer.battery.status.current_dA; + datalayer.battery.status.current_dA = battery_current / -6.675; datalayer.battery.info.total_capacity_Wh; @@ -35,6 +182,9 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.temperature_min_dC; datalayer.battery.status.temperature_max_dC; + + //Map all cell voltages to the global array + memcpy(datalayer.battery.status.cell_voltages_mV, battery_cell_voltages, 96 * sizeof(uint16_t)); } void receive_can_battery(CAN_frame rx_frame) { @@ -45,6 +195,359 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x3E3: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; break; + case 0x7EC: //TODO: Confirm if this is the reply from BMS when polling + //Frame 2 & 3 contains reply + reply_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + + switch (reply_poll) { + case POLL_CAPACITY_EST_GEN1: + battery_capacity_my17_18 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CAPACITY_EST_GEN2: + battery_capacity_my19plus = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_SOC_DISPLAY: + battery_SOC_display = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_SOC_RAW_HIGHPREC: + battery_SOC_raw_highprec = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_MAX_TEMPERATURE: + battery_max_temperature = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_MIN_TEMPERATURE: + battery_min_temperature = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_MIN_CELL_V: + battery_min_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_MAX_CELL_V: + battery_max_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_INTERNAL_RES: + battery_internal_resistance = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_MIN_BATT_V: + battery_min_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_MAX_BATT_V: + battery_max_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_VOLTAGE: + battery_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_VEHICLE_ISOLATION: + battery_vehicle_isolation = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_ISOLATION_TEST_KOHM: + battery_isolation_kohm = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_HV_LOCKED_OUT: + battery_HV_locked = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CRASH_EVENT: + battery_crash_event = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_HVIL: + battery_HVIL = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_HVIL_STATUS: + battery_HVIL_status = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CURRENT: + battery_current = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_01: + battery_cell_voltages[0] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_02: + battery_cell_voltages[1] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_03: + battery_cell_voltages[2] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_04: + battery_cell_voltages[3] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_05: + battery_cell_voltages[4] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_06: + battery_cell_voltages[5] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_07: + battery_cell_voltages[6] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_08: + battery_cell_voltages[7] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_09: + battery_cell_voltages[8] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_10: + battery_cell_voltages[9] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_11: + battery_cell_voltages[10] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_12: + battery_cell_voltages[11] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_13: + battery_cell_voltages[12] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_14: + battery_cell_voltages[13] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_15: + battery_cell_voltages[14] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_16: + battery_cell_voltages[15] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_17: + battery_cell_voltages[16] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_18: + battery_cell_voltages[17] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_19: + battery_cell_voltages[18] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_20: + battery_cell_voltages[19] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_21: + battery_cell_voltages[20] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_22: + battery_cell_voltages[21] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_23: + battery_cell_voltages[22] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_24: + battery_cell_voltages[23] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_25: + battery_cell_voltages[24] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_26: + battery_cell_voltages[25] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_27: + battery_cell_voltages[26] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_28: + battery_cell_voltages[27] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_29: + battery_cell_voltages[28] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_30: + battery_cell_voltages[29] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_31: + battery_cell_voltages[30] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_32: + battery_cell_voltages[31] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_33: + battery_cell_voltages[32] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_34: + battery_cell_voltages[33] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_35: + battery_cell_voltages[34] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_36: + battery_cell_voltages[35] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_37: + battery_cell_voltages[36] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_38: + battery_cell_voltages[37] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_39: + battery_cell_voltages[38] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_40: + battery_cell_voltages[39] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_41: + battery_cell_voltages[40] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_42: + battery_cell_voltages[41] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_43: + battery_cell_voltages[42] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_44: + battery_cell_voltages[43] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_45: + battery_cell_voltages[44] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_46: + battery_cell_voltages[45] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_47: + battery_cell_voltages[46] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_48: + battery_cell_voltages[47] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_49: + battery_cell_voltages[48] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_50: + battery_cell_voltages[49] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_51: + battery_cell_voltages[50] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_52: + battery_cell_voltages[51] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_53: + battery_cell_voltages[52] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_54: + battery_cell_voltages[53] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_55: + battery_cell_voltages[54] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_56: + battery_cell_voltages[55] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_57: + battery_cell_voltages[56] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_58: + battery_cell_voltages[57] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_59: + battery_cell_voltages[58] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_60: + battery_cell_voltages[59] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_61: + battery_cell_voltages[60] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_62: + battery_cell_voltages[61] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_63: + battery_cell_voltages[62] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_64: + battery_cell_voltages[63] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_65: + battery_cell_voltages[64] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_66: + battery_cell_voltages[65] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_67: + battery_cell_voltages[66] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_68: + battery_cell_voltages[67] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_69: + battery_cell_voltages[68] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_70: + battery_cell_voltages[69] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_71: + battery_cell_voltages[70] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_72: + battery_cell_voltages[71] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_73: + battery_cell_voltages[72] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_74: + battery_cell_voltages[73] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_75: + battery_cell_voltages[74] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_76: + battery_cell_voltages[75] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_77: + battery_cell_voltages[76] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_78: + battery_cell_voltages[77] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_79: + battery_cell_voltages[78] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_80: + battery_cell_voltages[79] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_81: + battery_cell_voltages[80] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_82: + battery_cell_voltages[81] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_83: + battery_cell_voltages[82] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_84: + battery_cell_voltages[83] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_85: + battery_cell_voltages[84] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_86: + battery_cell_voltages[85] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_87: + battery_cell_voltages[86] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_88: + battery_cell_voltages[87] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_89: + battery_cell_voltages[88] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_90: + battery_cell_voltages[89] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_91: + battery_cell_voltages[90] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_92: + battery_cell_voltages[91] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_93: + battery_cell_voltages[92] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_94: + battery_cell_voltages[93] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_95: + battery_cell_voltages[94] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_CELL_96: + battery_cell_voltages[95] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + default: + break; + } default: break; } @@ -54,22 +557,36 @@ void send_can_battery() { unsigned long currentMillis = millis(); //Send 20ms message - if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { + if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) { // Check if sending of CAN messages has been delayed too much. - if ((currentMillis - previousMillis20 >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { - set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20)); + if ((currentMillis - previousMillis20ms >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20ms)); } else { clear_event(EVENT_CAN_OVERRUN); } - previousMillis20 = currentMillis; + previousMillis20ms = currentMillis; transmit_can(&BOLT_778, can_config.battery); } + + //Send 200ms message + if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) { + previousMillis200ms = currentMillis; + + // Update current poll from the array + currentpoll = poll_commands[poll_index]; + poll_index = (poll_index + 1) % 115; + + BOLT_POLL_7E4.data.u8[2] = (uint8_t)((currentpoll & 0xFF00) >> 8); + BOLT_POLL_7E4.data.u8[3] = (uint8_t)(currentpoll & 0x00FF); + + transmit_can(&BOLT_POLL_7E4, can_config.battery); + } } void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "Chevrolet Bolt EV/Opel Ampera-e", 63); datalayer.system.info.battery_protocol[63] = '\0'; - + datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.h b/Software/src/battery/BOLT-AMPERA-BATTERY.h index 42d743d59..46c28f0a0 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.h +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.h @@ -10,7 +10,122 @@ #define MAX_CELL_DEVIATION_MV 500 #define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value -#define MAX_CHARGE_POWER_W 5000 // Battery can be charged with this amount of power + +#define POLL_CAPACITY_EST_GEN1 0x41A3 +#define POLL_CAPACITY_EST_GEN2 0x45F9 +#define POLL_SOC_DISPLAY 0x8334 +#define POLL_SOC_RAW_HIGHPREC 0x43AF +#define POLL_MAX_TEMPERATURE 0x4349 +#define POLL_MIN_TEMPERATURE 0x434A +#define POLL_MIN_CELL_V 0x4329 +#define POLL_MAX_CELL_V 0x432B +#define POLL_INTERNAL_RES 0x40E9 +#define POLL_MIN_BATT_V 0x433B +#define POLL_MAX_BATT_V 0x433C +#define POLL_VOLTAGE 0x432D +#define POLL_VEHICLE_ISOLATION 0x41EC +#define POLL_ISOLATION_TEST_KOHM 0x43A6 +#define POLL_HV_LOCKED_OUT 0x44F8 +#define POLL_CRASH_EVENT 0x4522 +#define POLL_HVIL 0x4310 +#define POLL_HVIL_STATUS 0x4311 +#define POLL_CURRENT 0x4356 +#define POLL_CELL_01 0x4181 +#define POLL_CELL_02 0x4182 +#define POLL_CELL_03 0x4183 +#define POLL_CELL_04 0x4184 +#define POLL_CELL_05 0x4185 +#define POLL_CELL_06 0x4186 +#define POLL_CELL_07 0x4187 +#define POLL_CELL_08 0x4188 +#define POLL_CELL_09 0x4189 +#define POLL_CELL_10 0x418A +#define POLL_CELL_11 0x418B +#define POLL_CELL_12 0x418C +#define POLL_CELL_13 0x418D +#define POLL_CELL_14 0x418E +#define POLL_CELL_15 0x418F +#define POLL_CELL_16 0x4190 +#define POLL_CELL_17 0x4191 +#define POLL_CELL_18 0x4192 +#define POLL_CELL_19 0x4193 +#define POLL_CELL_20 0x4194 +#define POLL_CELL_21 0x4195 +#define POLL_CELL_22 0x4196 +#define POLL_CELL_23 0x4197 +#define POLL_CELL_24 0x4198 +#define POLL_CELL_25 0x4199 +#define POLL_CELL_26 0x419A +#define POLL_CELL_27 0x419B +#define POLL_CELL_28 0x419C +#define POLL_CELL_29 0x419D +#define POLL_CELL_30 0x419E +#define POLL_CELL_31 0x419F +#define POLL_CELL_32 0x4200 +#define POLL_CELL_33 0x4201 +#define POLL_CELL_34 0x4202 +#define POLL_CELL_35 0x4203 +#define POLL_CELL_36 0x4204 +#define POLL_CELL_37 0x4205 +#define POLL_CELL_38 0x4206 +#define POLL_CELL_39 0x4207 +#define POLL_CELL_40 0x4208 +#define POLL_CELL_41 0x4209 +#define POLL_CELL_42 0x420A +#define POLL_CELL_43 0x420B +#define POLL_CELL_44 0x420C +#define POLL_CELL_45 0x420D +#define POLL_CELL_46 0x420E +#define POLL_CELL_47 0x420F +#define POLL_CELL_48 0x4210 +#define POLL_CELL_49 0x4211 +#define POLL_CELL_50 0x4212 +#define POLL_CELL_51 0x4213 +#define POLL_CELL_52 0x4214 +#define POLL_CELL_53 0x4215 +#define POLL_CELL_54 0x4216 +#define POLL_CELL_55 0x4217 +#define POLL_CELL_56 0x4218 +#define POLL_CELL_57 0x4219 +#define POLL_CELL_58 0x421A +#define POLL_CELL_59 0x421B +#define POLL_CELL_60 0x421C +#define POLL_CELL_61 0x421D +#define POLL_CELL_62 0x421E +#define POLL_CELL_63 0x421F +#define POLL_CELL_64 0x4220 +#define POLL_CELL_65 0x4221 +#define POLL_CELL_66 0x4222 +#define POLL_CELL_67 0x4223 +#define POLL_CELL_68 0x4224 +#define POLL_CELL_69 0x4225 +#define POLL_CELL_70 0x4226 +#define POLL_CELL_71 0x4227 +#define POLL_CELL_72 0x4228 +#define POLL_CELL_73 0x4229 +#define POLL_CELL_74 0x422A +#define POLL_CELL_75 0x422B +#define POLL_CELL_76 0x422C +#define POLL_CELL_77 0x422D +#define POLL_CELL_78 0x422E +#define POLL_CELL_79 0x422F +#define POLL_CELL_80 0x4230 +#define POLL_CELL_81 0x4231 +#define POLL_CELL_82 0x4232 +#define POLL_CELL_83 0x4233 +#define POLL_CELL_84 0x4234 +#define POLL_CELL_85 0x4235 +#define POLL_CELL_86 0x4236 +#define POLL_CELL_87 0x4237 +#define POLL_CELL_88 0x4238 +#define POLL_CELL_89 0x4239 +#define POLL_CELL_90 0x423A +#define POLL_CELL_91 0x423B +#define POLL_CELL_92 0x423C +#define POLL_CELL_93 0x423D +#define POLL_CELL_94 0x423E +#define POLL_CELL_95 0x423F +#define POLL_CELL_96 0x4240 void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); From 3d1a3eb2c3bbc65e077e835bd2c9806681938f70 Mon Sep 17 00:00:00 2001 From: mvgalen Date: Wed, 4 Dec 2024 10:26:21 +0100 Subject: [PATCH 026/225] Change web based CAN log file format to CANdump (#655) * Update web page CAN logging to CANdump format * Improve performance of web based CAN logging by removing unnecessary strcat and strlen calls. --- Software/Software.ino | 46 +++++++++++++----------------- Software/src/datalayer/datalayer.h | 1 + 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 1994978f4..79e99bf86 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -642,44 +642,38 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { #endif //#DEBUG_CAN_DATA if (datalayer.system.info.can_logging_active) { // If user clicked on CAN Logging page in webserver, start recording + 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); - char message_string[128]; // Buffer to hold the message string - int offset = 0; // Keeps track of the current position in the buffer - + if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { + // Not enough space, reset and start from the beginning + offset = 0; + } + unsigned long currentTime = millis(); // Add timestamp - offset += snprintf(message_string + offset, sizeof(message_string) - offset, "%lu ", millis()); + offset += snprintf(message_string + offset, message_string_size - offset, "(%lu.%03lu) ", currentTime / 1000, + currentTime % 1000); - // Add direction + // 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, sizeof(message_string) - offset, "%s ", (msgDir == MSG_RX) ? "RX" : "TX"); + snprintf(message_string + offset, message_string_size - offset, "%s ", (msgDir == MSG_RX) ? "RX0" : "TX1"); // Add ID and DLC - offset += snprintf(message_string + offset, sizeof(message_string) - offset, "%X %u ", frame.ID, frame.DLC); + offset += snprintf(message_string + offset, message_string_size - offset, "%X [%u] ", frame.ID, frame.DLC); // Add data bytes for (uint8_t i = 0; i < frame.DLC; i++) { - offset += snprintf(message_string + offset, sizeof(message_string) - offset, "%s%X ", - frame.data.u8[i] < 16 ? "0" : "", frame.data.u8[i]); + if (i < frame.DLC - 1) { + offset += snprintf(message_string + offset, message_string_size - offset, "%02X ", frame.data.u8[i]); + } else { + offset += snprintf(message_string + offset, message_string_size - offset, "%02X", frame.data.u8[i]); + } } // Add linebreak - offset += snprintf(message_string + offset, sizeof(message_string) - offset, "\n"); - - // Ensure the string is null-terminated - message_string[sizeof(message_string) - 1] = '\0'; - - // Append the message string to the system info structure - size_t current_len = - strnlen(datalayer.system.info.logged_can_messages, sizeof(datalayer.system.info.logged_can_messages)); - size_t available_space = - sizeof(datalayer.system.info.logged_can_messages) - current_len - 1; // Space left for new data - - if (available_space < strlen(message_string) + 1) { - // Not enough space, reset and start from the beginning - current_len = 0; - datalayer.system.info.logged_can_messages[0] = '\0'; - } + offset += snprintf(message_string + offset, message_string_size - offset, "\n"); - strncat(datalayer.system.info.logged_can_messages, message_string, available_space); + datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer } } diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 818143368..e6de68ce0 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -133,6 +133,7 @@ typedef struct { char inverter_protocol[64] = {0}; /** array with incoming CAN messages, for displaying on webserver */ char logged_can_messages[15000] = {0}; + size_t logged_can_messages_offset = 0; /** bool, determines if CAN messages should be logged for webserver */ bool can_logging_active = false; From 12215bdbd237a626c1769e2005b838f3f7d9b56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 4 Dec 2024 22:42:37 +0200 Subject: [PATCH 027/225] Add temperature mappings and more CAN messages --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 79 +++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index a0cb0e95c..49dcb996c 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -40,6 +40,14 @@ static uint16_t battery_crash_event = 0; static uint16_t battery_HVIL = 0; static uint16_t battery_HVIL_status = 0; static int16_t battery_current = 0; +static int16_t temperature_1 = 0; +static int16_t temperature_2 = 0; +static int16_t temperature_3 = 0; +static int16_t temperature_4 = 0; +static int16_t temperature_5 = 0; +static int16_t temperature_6 = 0; +static int16_t temperature_highest = 0; +static int16_t temperature_lowest = 0; static uint8_t poll_index = 0; static uint16_t currentpoll = POLL_CAPACITY_EST_GEN1; @@ -179,9 +187,26 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_charge_power_W; - datalayer.battery.status.temperature_min_dC; + // Store temperatures in an array + int16_t temperatures[] = {temperature_1, temperature_2, temperature_3, temperature_4, temperature_5, temperature_6}; - datalayer.battery.status.temperature_max_dC; + // Initialize highest and lowest to the first element + temperature_highest = temperatures[0]; + temperature_lowest = temperatures[0]; + + // Iterate through the array to find the highest and lowest values + for (uint8_t i = 1; i < 6; ++i) { + if (temperatures[i] > temperature_highest) { + temperature_highest = temperatures[i]; + } + if (temperatures[i] < temperature_lowest) { + temperature_lowest = temperatures[i]; + } + } + + datalayer.battery.status.temperature_min_dC = temperature_lowest * 10; + + datalayer.battery.status.temperature_max_dC = temperature_highest * 10; //Map all cell voltages to the global array memcpy(datalayer.battery.status.cell_voltages_mV, battery_cell_voltages, 96 * sizeof(uint16_t)); @@ -189,12 +214,62 @@ void update_values_battery() { //This function maps all the values fetched via void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { + case 0x200: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x202: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x204: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x206: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x208: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x20C: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x216: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; case 0x2C7: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; break; + case 0x260: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x270: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x272: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x274: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x302: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + //302 8 03 5C 5C 5D 5D 5C 5C 1E + //Could be temperatures here? + temperature_1 = (rx_frame.data.u8[1] - 40); + temperature_2 = (rx_frame.data.u8[2] - 40); + temperature_3 = (rx_frame.data.u8[3] - 40); + temperature_4 = (rx_frame.data.u8[4] - 40); + temperature_5 = (rx_frame.data.u8[5] - 40); + temperature_6 = (rx_frame.data.u8[6] - 40); + break; case 0x3E3: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; break; + case 0x460: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x5EF: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; case 0x7EC: //TODO: Confirm if this is the reply from BMS when polling //Frame 2 & 3 contains reply reply_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; From 3340e029023ba5b00bdb9982658263ac8c7d8d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 4 Dec 2024 23:20:25 +0200 Subject: [PATCH 028/225] Add voltage candidate --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index 49dcb996c..a871f579e 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -33,6 +33,7 @@ static uint16_t battery_internal_resistance = 0; static uint16_t battery_min_voltage = 0; static uint16_t battery_max_voltage = 0; static uint16_t battery_voltage = 3700; +static uint16_t battery_voltage_periodic = 0; static uint16_t battery_vehicle_isolation = 0; static uint16_t battery_isolation_kohm = 0; static uint16_t battery_HV_locked = 0; @@ -48,6 +49,7 @@ static int16_t temperature_5 = 0; static int16_t temperature_6 = 0; static int16_t temperature_highest = 0; static int16_t temperature_lowest = 0; +static uint8_t mux = 0; static uint8_t poll_index = 0; static uint16_t currentpoll = POLL_CAPACITY_EST_GEN1; @@ -173,7 +175,8 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.real_soc = (battery_SOC_display * 100 / 255); - datalayer.battery.status.voltage_dV = battery_voltage * 0.52; + //datalayer.battery.status.voltage_dV = battery_voltage * 0.52; + datalayer.battery.status.voltage_dV = (battery_voltage_periodic / 8) * 10; datalayer.battery.status.current_dA = battery_current / -6.675; @@ -216,18 +219,23 @@ void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x200: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 break; case 0x202: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 break; case 0x204: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 break; case 0x206: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 break; case 0x208: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 break; case 0x20C: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; @@ -237,6 +245,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; case 0x2C7: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_voltage_periodic = (rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[4] >> 4); break; case 0x260: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; From f68fec57cb86fa6ef9c3737856820e4bd3225059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 5 Dec 2024 22:25:29 +0200 Subject: [PATCH 029/225] Fix temperatures scaled wrong --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index a871f579e..5a22e8c2d 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -263,12 +263,12 @@ void receive_can_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //302 8 03 5C 5C 5D 5D 5C 5C 1E //Could be temperatures here? - temperature_1 = (rx_frame.data.u8[1] - 40); - temperature_2 = (rx_frame.data.u8[2] - 40); - temperature_3 = (rx_frame.data.u8[3] - 40); - temperature_4 = (rx_frame.data.u8[4] - 40); - temperature_5 = (rx_frame.data.u8[5] - 40); - temperature_6 = (rx_frame.data.u8[6] - 40); + temperature_1 = ((rx_frame.data.u8[1] / 2) - 40); + temperature_2 = ((rx_frame.data.u8[2] / 2) - 40); + temperature_3 = ((rx_frame.data.u8[3] / 2) - 40); + temperature_4 = ((rx_frame.data.u8[4] / 2) - 40); + temperature_5 = ((rx_frame.data.u8[5] / 2) - 40); + temperature_6 = ((rx_frame.data.u8[6] / 2) - 40); break; case 0x3E3: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; From 257ee27d5c7ba8deb7b71f394474c2b4e78f18c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 6 Dec 2024 22:41:13 +0200 Subject: [PATCH 030/225] Tweak 7E4 bit0 --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index 5a22e8c2d..c804643b4 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -18,7 +18,7 @@ CAN_frame BOLT_POLL_7E4 = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x7E4, - .data = {0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + .data = {0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; static uint16_t battery_cell_voltages[96]; //array with all the cellvoltages static uint16_t battery_capacity_my17_18 = 0; From 5023415a83b15c8a074a1d24ec20b012ff72579d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 8 Dec 2024 01:07:15 +0200 Subject: [PATCH 031/225] Improve polling --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 51 ++++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index c804643b4..30b476f94 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -18,7 +18,25 @@ CAN_frame BOLT_POLL_7E4 = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x7E4, - .data = {0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + .data = {0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame BOLT_ACK_7E4 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E4, + .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame BOLT_POLL_7E7 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E7, + .data = {0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame BOLT_ACK_7E7 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E7, + .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +// 7E4 Battery , reply 000007EC +// 7E7 Battery (Cell voltages), reply 000007EF static uint16_t battery_cell_voltages[96]; //array with all the cellvoltages static uint16_t battery_capacity_my17_18 = 0; @@ -261,14 +279,12 @@ void receive_can_battery(CAN_frame rx_frame) { break; case 0x302: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - //302 8 03 5C 5C 5D 5D 5C 5C 1E - //Could be temperatures here? - temperature_1 = ((rx_frame.data.u8[1] / 2) - 40); - temperature_2 = ((rx_frame.data.u8[2] / 2) - 40); - temperature_3 = ((rx_frame.data.u8[3] / 2) - 40); - temperature_4 = ((rx_frame.data.u8[4] / 2) - 40); - temperature_5 = ((rx_frame.data.u8[5] / 2) - 40); - temperature_6 = ((rx_frame.data.u8[6] / 2) - 40); + temperature_1 = ((rx_frame.data.u8[1] / 2) - 40); //Module 1 Temperature + temperature_2 = ((rx_frame.data.u8[2] / 2) - 40); //Module 2 Temperature + temperature_3 = ((rx_frame.data.u8[3] / 2) - 40); //Module 3 Temperature + temperature_4 = ((rx_frame.data.u8[4] / 2) - 40); //Module 4 Temperature + temperature_5 = ((rx_frame.data.u8[5] / 2) - 40); //Module 5 Temperature + temperature_6 = ((rx_frame.data.u8[6] / 2) - 40); //Module 6 Temperature break; case 0x3E3: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; @@ -279,7 +295,18 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x5EF: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; break; - case 0x7EC: //TODO: Confirm if this is the reply from BMS when polling + case 0x7EC: //When polling 7E4 BMS replies with 7EC ?? + case 0x7EF: //When polling 7E7 BMS replies with 7EF ?? + + if (rx_frame.data.u8[0] == 0x10) { //"PID Header" + if (rx_frame.ID == 0x7EC) { + transmit_can(&BOLT_ACK_7E4, can_config.battery); + } + if (rx_frame.ID == 0x7EF) { + transmit_can(&BOLT_ACK_7E7, can_config.battery); + } + } + //Frame 2 & 3 contains reply reply_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; @@ -663,7 +690,11 @@ void send_can_battery() { BOLT_POLL_7E4.data.u8[2] = (uint8_t)((currentpoll & 0xFF00) >> 8); BOLT_POLL_7E4.data.u8[3] = (uint8_t)(currentpoll & 0x00FF); + BOLT_POLL_7E7.data.u8[2] = (uint8_t)((currentpoll & 0xFF00) >> 8); + BOLT_POLL_7E7.data.u8[3] = (uint8_t)(currentpoll & 0x00FF); + transmit_can(&BOLT_POLL_7E4, can_config.battery); + transmit_can(&BOLT_POLL_7E7, can_config.battery); } } From e900888d400a79359d97030ccd6d0811082b074e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 8 Dec 2024 11:45:46 +0200 Subject: [PATCH 032/225] 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 79e99bf86..9bd0225e1 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -53,7 +53,7 @@ Preferences settings; // Store user settings // The current software version, shown on webserver -const char* version_number = "7.9.dev"; +const char* version_number = "7.9.0"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From 30507e78bd5f733ef3bf6aeda5a51cb7e118dd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 8 Dec 2024 11:53:07 +0200 Subject: [PATCH 033/225] 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 9bd0225e1..df46dca04 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -53,7 +53,7 @@ Preferences settings; // Store user settings // The current software version, shown on webserver -const char* version_number = "7.9.0"; +const char* version_number = "8.0.dev"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From 0c1e7d5ed916afd9cff2aca21102d97ef9b4de52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 8 Dec 2024 17:30:19 +0200 Subject: [PATCH 034/225] Refactor 7E7 polls --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 483 ++++++++---------- Software/src/battery/BOLT-AMPERA-BATTERY.h | 223 ++++---- Software/src/datalayer/datalayer_extended.h | 18 + .../webserver/advanced_battery_html.cpp | 23 +- 4 files changed, 356 insertions(+), 391 deletions(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index 30b476f94..a113d3a93 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -28,14 +28,14 @@ CAN_frame BOLT_POLL_7E7 = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x7E7, - .data = {0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + .data = {0x03, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; CAN_frame BOLT_ACK_7E7 = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x7E7, .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -// 7E4 Battery , reply 000007EC +// 7E4 Battery , reply 000007EC (For some reason does not work) // 7E7 Battery (Cell voltages), reply 000007EF static uint16_t battery_cell_voltages[96]; //array with all the cellvoltages @@ -58,6 +58,17 @@ static uint16_t battery_HV_locked = 0; static uint16_t battery_crash_event = 0; static uint16_t battery_HVIL = 0; static uint16_t battery_HVIL_status = 0; +static uint16_t battery_5V_ref = 0; +static uint16_t battery_module_temp_1 = 0; +static uint16_t battery_module_temp_2 = 0; +static uint16_t battery_module_temp_3 = 0; +static uint16_t battery_module_temp_4 = 0; +static uint16_t battery_module_temp_5 = 0; +static uint16_t battery_module_temp_6 = 0; +static uint16_t battery_cell_average_voltage = 0; +static uint16_t battery_cell_average_voltage_2 = 0; +static uint16_t battery_terminal_voltage = 0; +static uint16_t battery_ignition_power_mode = 0; static int16_t battery_current = 0; static int16_t temperature_1 = 0; static int16_t temperature_2 = 0; @@ -70,124 +81,63 @@ static int16_t temperature_lowest = 0; static uint8_t mux = 0; static uint8_t poll_index = 0; -static uint16_t currentpoll = POLL_CAPACITY_EST_GEN1; +static uint16_t currentpoll = POLL_7E7_CURRENT; static uint16_t reply_poll = 0; -const uint16_t poll_commands[115] = {POLL_CAPACITY_EST_GEN1, - POLL_CAPACITY_EST_GEN2, - POLL_SOC_DISPLAY, - POLL_SOC_RAW_HIGHPREC, - POLL_MAX_TEMPERATURE, - POLL_MIN_TEMPERATURE, - POLL_MIN_CELL_V, - POLL_MAX_CELL_V, - POLL_INTERNAL_RES, - POLL_MIN_BATT_V, - POLL_MAX_BATT_V, - POLL_VOLTAGE, - POLL_VEHICLE_ISOLATION, - POLL_ISOLATION_TEST_KOHM, - POLL_HV_LOCKED_OUT, - POLL_CRASH_EVENT, - POLL_HVIL, - POLL_HVIL_STATUS, - POLL_CURRENT, - POLL_CELL_01, - POLL_CELL_02, - POLL_CELL_03, - POLL_CELL_04, - POLL_CELL_05, - POLL_CELL_06, - POLL_CELL_07, - POLL_CELL_08, - POLL_CELL_09, - POLL_CELL_10, - POLL_CELL_11, - POLL_CELL_12, - POLL_CELL_13, - POLL_CELL_14, - POLL_CELL_15, - POLL_CELL_16, - POLL_CELL_17, - POLL_CELL_18, - POLL_CELL_19, - POLL_CELL_20, - POLL_CELL_21, - POLL_CELL_22, - POLL_CELL_23, - POLL_CELL_24, - POLL_CELL_25, - POLL_CELL_26, - POLL_CELL_27, - POLL_CELL_28, - POLL_CELL_29, - POLL_CELL_30, - POLL_CELL_31, - POLL_CELL_32, - POLL_CELL_33, - POLL_CELL_34, - POLL_CELL_35, - POLL_CELL_36, - POLL_CELL_37, - POLL_CELL_38, - POLL_CELL_39, - POLL_CELL_40, - POLL_CELL_41, - POLL_CELL_42, - POLL_CELL_43, - POLL_CELL_44, - POLL_CELL_45, - POLL_CELL_46, - POLL_CELL_47, - POLL_CELL_48, - POLL_CELL_49, - POLL_CELL_50, - POLL_CELL_51, - POLL_CELL_52, - POLL_CELL_53, - POLL_CELL_54, - POLL_CELL_55, - POLL_CELL_56, - POLL_CELL_57, - POLL_CELL_58, - POLL_CELL_59, - POLL_CELL_60, - POLL_CELL_61, - POLL_CELL_62, - POLL_CELL_63, - POLL_CELL_64, - POLL_CELL_65, - POLL_CELL_66, - POLL_CELL_67, - POLL_CELL_68, - POLL_CELL_69, - POLL_CELL_70, - POLL_CELL_71, - POLL_CELL_72, - POLL_CELL_73, - POLL_CELL_74, - POLL_CELL_75, - POLL_CELL_76, - POLL_CELL_77, - POLL_CELL_78, - POLL_CELL_79, - POLL_CELL_80, - POLL_CELL_81, - POLL_CELL_82, - POLL_CELL_83, - POLL_CELL_84, - POLL_CELL_85, - POLL_CELL_86, - POLL_CELL_87, - POLL_CELL_88, - POLL_CELL_89, - POLL_CELL_90, - POLL_CELL_91, - POLL_CELL_92, - POLL_CELL_93, - POLL_CELL_94, - POLL_CELL_95, - POLL_CELL_96}; +const uint16_t poll_commands_7E7[108] = {POLL_7E7_CURRENT, POLL_7E7_5V_REF, + POLL_7E7_MODULE_TEMP_1, POLL_7E7_MODULE_TEMP_2, + POLL_7E7_MODULE_TEMP_3, POLL_7E7_MODULE_TEMP_4, + POLL_7E7_MODULE_TEMP_5, POLL_7E7_MODULE_TEMP_6, + POLL_7E7_CELL_AVG_VOLTAGE, POLL_7E7_CELL_AVG_VOLTAGE_2, + POLL_7E7_TERMINAL_VOLTAGE, POLL_7E7_IGNITION_POWER_MODE, + POLL_7E7_CELL_01, POLL_7E7_CELL_02, + POLL_7E7_CELL_03, POLL_7E7_CELL_04, + POLL_7E7_CELL_05, POLL_7E7_CELL_06, + POLL_7E7_CELL_07, POLL_7E7_CELL_08, + POLL_7E7_CELL_09, POLL_7E7_CELL_10, + POLL_7E7_CELL_11, POLL_7E7_CELL_12, + POLL_7E7_CELL_13, POLL_7E7_CELL_14, + POLL_7E7_CELL_15, POLL_7E7_CELL_16, + POLL_7E7_CELL_17, POLL_7E7_CELL_18, + POLL_7E7_CELL_19, POLL_7E7_CELL_20, + POLL_7E7_CELL_21, POLL_7E7_CELL_22, + POLL_7E7_CELL_23, POLL_7E7_CELL_24, + POLL_7E7_CELL_25, POLL_7E7_CELL_26, + POLL_7E7_CELL_27, POLL_7E7_CELL_28, + POLL_7E7_CELL_29, POLL_7E7_CELL_30, + POLL_7E7_CELL_31, POLL_7E7_CELL_32, + POLL_7E7_CELL_33, POLL_7E7_CELL_34, + POLL_7E7_CELL_35, POLL_7E7_CELL_36, + POLL_7E7_CELL_37, POLL_7E7_CELL_38, + POLL_7E7_CELL_39, POLL_7E7_CELL_40, + POLL_7E7_CELL_41, POLL_7E7_CELL_42, + POLL_7E7_CELL_43, POLL_7E7_CELL_44, + POLL_7E7_CELL_45, POLL_7E7_CELL_46, + POLL_7E7_CELL_47, POLL_7E7_CELL_48, + POLL_7E7_CELL_49, POLL_7E7_CELL_50, + POLL_7E7_CELL_51, POLL_7E7_CELL_52, + POLL_7E7_CELL_53, POLL_7E7_CELL_54, + POLL_7E7_CELL_55, POLL_7E7_CELL_56, + POLL_7E7_CELL_57, POLL_7E7_CELL_58, + POLL_7E7_CELL_59, POLL_7E7_CELL_60, + POLL_7E7_CELL_61, POLL_7E7_CELL_62, + POLL_7E7_CELL_63, POLL_7E7_CELL_64, + POLL_7E7_CELL_65, POLL_7E7_CELL_66, + POLL_7E7_CELL_67, POLL_7E7_CELL_68, + POLL_7E7_CELL_69, POLL_7E7_CELL_70, + POLL_7E7_CELL_71, POLL_7E7_CELL_72, + POLL_7E7_CELL_73, POLL_7E7_CELL_74, + POLL_7E7_CELL_75, POLL_7E7_CELL_76, + POLL_7E7_CELL_77, POLL_7E7_CELL_78, + POLL_7E7_CELL_79, POLL_7E7_CELL_80, + POLL_7E7_CELL_81, POLL_7E7_CELL_82, + POLL_7E7_CELL_83, POLL_7E7_CELL_84, + POLL_7E7_CELL_85, POLL_7E7_CELL_86, + POLL_7E7_CELL_87, POLL_7E7_CELL_88, + POLL_7E7_CELL_89, POLL_7E7_CELL_90, + POLL_7E7_CELL_91, POLL_7E7_CELL_92, + POLL_7E7_CELL_93, POLL_7E7_CELL_94, + POLL_7E7_CELL_95, POLL_7E7_CELL_96}; void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer @@ -196,7 +146,7 @@ void update_values_battery() { //This function maps all the values fetched via //datalayer.battery.status.voltage_dV = battery_voltage * 0.52; datalayer.battery.status.voltage_dV = (battery_voltage_periodic / 8) * 10; - datalayer.battery.status.current_dA = battery_current / -6.675; + datalayer.battery.status.current_dA = (battery_current / 20) - 400; datalayer.battery.info.total_capacity_Wh; @@ -231,6 +181,20 @@ void update_values_battery() { //This function maps all the values fetched via //Map all cell voltages to the global array memcpy(datalayer.battery.status.cell_voltages_mV, battery_cell_voltages, 96 * sizeof(uint16_t)); + + // Update webserver datalayer + datalayer_extended.boltampera.battery_5V_ref = battery_5V_ref; + datalayer_extended.boltampera.battery_module_temp_1 = battery_module_temp_1; + datalayer_extended.boltampera.battery_module_temp_2 = battery_module_temp_2; + datalayer_extended.boltampera.battery_module_temp_3 = battery_module_temp_3; + datalayer_extended.boltampera.battery_module_temp_4 = battery_module_temp_4; + datalayer_extended.boltampera.battery_module_temp_5 = battery_module_temp_5; + datalayer_extended.boltampera.battery_module_temp_6 = battery_module_temp_6; + datalayer_extended.boltampera.battery_cell_average_voltage = battery_cell_average_voltage; + datalayer_extended.boltampera.battery_cell_average_voltage_2 = battery_cell_average_voltage_2; + datalayer_extended.boltampera.battery_terminal_voltage = battery_terminal_voltage; + datalayer_extended.boltampera.battery_ignition_power_mode = battery_ignition_power_mode; + datalayer_extended.boltampera.battery_current = battery_current; } void receive_can_battery(CAN_frame rx_frame) { @@ -296,364 +260,339 @@ void receive_can_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; break; case 0x7EC: //When polling 7E4 BMS replies with 7EC ?? - case 0x7EF: //When polling 7E7 BMS replies with 7EF ?? + break; + case 0x7EF: //When polling 7E7 BMS replies with 7EF if (rx_frame.data.u8[0] == 0x10) { //"PID Header" - if (rx_frame.ID == 0x7EC) { - transmit_can(&BOLT_ACK_7E4, can_config.battery); - } - if (rx_frame.ID == 0x7EF) { - transmit_can(&BOLT_ACK_7E7, can_config.battery); - } + transmit_can(&BOLT_ACK_7E7, can_config.battery); } //Frame 2 & 3 contains reply reply_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; switch (reply_poll) { - case POLL_CAPACITY_EST_GEN1: - battery_capacity_my17_18 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - break; - case POLL_CAPACITY_EST_GEN2: - battery_capacity_my19plus = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - break; - case POLL_SOC_DISPLAY: - battery_SOC_display = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - break; - case POLL_SOC_RAW_HIGHPREC: - battery_SOC_raw_highprec = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - break; - case POLL_MAX_TEMPERATURE: - battery_max_temperature = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - break; - case POLL_MIN_TEMPERATURE: - battery_min_temperature = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - break; - case POLL_MIN_CELL_V: - battery_min_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - break; - case POLL_MAX_CELL_V: - battery_max_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_CURRENT: + battery_current = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_INTERNAL_RES: - battery_internal_resistance = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_5V_REF: + battery_5V_ref = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_MIN_BATT_V: - battery_min_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_MODULE_TEMP_1: + battery_module_temp_1 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_MAX_BATT_V: - battery_max_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_MODULE_TEMP_2: + battery_module_temp_2 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_VOLTAGE: - battery_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_MODULE_TEMP_3: + battery_module_temp_3 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_VEHICLE_ISOLATION: - battery_vehicle_isolation = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_MODULE_TEMP_4: + battery_module_temp_4 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_ISOLATION_TEST_KOHM: - battery_isolation_kohm = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_MODULE_TEMP_5: + battery_module_temp_5 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_HV_LOCKED_OUT: - battery_HV_locked = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_MODULE_TEMP_6: + battery_module_temp_6 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CRASH_EVENT: - battery_crash_event = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_CELL_AVG_VOLTAGE: + battery_cell_average_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_HVIL: - battery_HVIL = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_CELL_AVG_VOLTAGE_2: + battery_cell_average_voltage_2 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_HVIL_STATUS: - battery_HVIL_status = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_TERMINAL_VOLTAGE: + battery_terminal_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CURRENT: - battery_current = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + case POLL_7E7_IGNITION_POWER_MODE: + battery_ignition_power_mode = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_01: + case POLL_7E7_CELL_01: battery_cell_voltages[0] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_02: + case POLL_7E7_CELL_02: battery_cell_voltages[1] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_03: + case POLL_7E7_CELL_03: battery_cell_voltages[2] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_04: + case POLL_7E7_CELL_04: battery_cell_voltages[3] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_05: + case POLL_7E7_CELL_05: battery_cell_voltages[4] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_06: + case POLL_7E7_CELL_06: battery_cell_voltages[5] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_07: + case POLL_7E7_CELL_07: battery_cell_voltages[6] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_08: + case POLL_7E7_CELL_08: battery_cell_voltages[7] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_09: + case POLL_7E7_CELL_09: battery_cell_voltages[8] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_10: + case POLL_7E7_CELL_10: battery_cell_voltages[9] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_11: + case POLL_7E7_CELL_11: battery_cell_voltages[10] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_12: + case POLL_7E7_CELL_12: battery_cell_voltages[11] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_13: + case POLL_7E7_CELL_13: battery_cell_voltages[12] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_14: + case POLL_7E7_CELL_14: battery_cell_voltages[13] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_15: + case POLL_7E7_CELL_15: battery_cell_voltages[14] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_16: + case POLL_7E7_CELL_16: battery_cell_voltages[15] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_17: + case POLL_7E7_CELL_17: battery_cell_voltages[16] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_18: + case POLL_7E7_CELL_18: battery_cell_voltages[17] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_19: + case POLL_7E7_CELL_19: battery_cell_voltages[18] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_20: + case POLL_7E7_CELL_20: battery_cell_voltages[19] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_21: + case POLL_7E7_CELL_21: battery_cell_voltages[20] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_22: + case POLL_7E7_CELL_22: battery_cell_voltages[21] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_23: + case POLL_7E7_CELL_23: battery_cell_voltages[22] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_24: + case POLL_7E7_CELL_24: battery_cell_voltages[23] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_25: + case POLL_7E7_CELL_25: battery_cell_voltages[24] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_26: + case POLL_7E7_CELL_26: battery_cell_voltages[25] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_27: + case POLL_7E7_CELL_27: battery_cell_voltages[26] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_28: + case POLL_7E7_CELL_28: battery_cell_voltages[27] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_29: + case POLL_7E7_CELL_29: battery_cell_voltages[28] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_30: + case POLL_7E7_CELL_30: battery_cell_voltages[29] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_31: + case POLL_7E7_CELL_31: battery_cell_voltages[30] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_32: + case POLL_7E7_CELL_32: battery_cell_voltages[31] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_33: + case POLL_7E7_CELL_33: battery_cell_voltages[32] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_34: + case POLL_7E7_CELL_34: battery_cell_voltages[33] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_35: + case POLL_7E7_CELL_35: battery_cell_voltages[34] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_36: + case POLL_7E7_CELL_36: battery_cell_voltages[35] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_37: + case POLL_7E7_CELL_37: battery_cell_voltages[36] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_38: + case POLL_7E7_CELL_38: battery_cell_voltages[37] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_39: + case POLL_7E7_CELL_39: battery_cell_voltages[38] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_40: + case POLL_7E7_CELL_40: battery_cell_voltages[39] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_41: + case POLL_7E7_CELL_41: battery_cell_voltages[40] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_42: + case POLL_7E7_CELL_42: battery_cell_voltages[41] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_43: + case POLL_7E7_CELL_43: battery_cell_voltages[42] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_44: + case POLL_7E7_CELL_44: battery_cell_voltages[43] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_45: + case POLL_7E7_CELL_45: battery_cell_voltages[44] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_46: + case POLL_7E7_CELL_46: battery_cell_voltages[45] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_47: + case POLL_7E7_CELL_47: battery_cell_voltages[46] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_48: + case POLL_7E7_CELL_48: battery_cell_voltages[47] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_49: + case POLL_7E7_CELL_49: battery_cell_voltages[48] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_50: + case POLL_7E7_CELL_50: battery_cell_voltages[49] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_51: + case POLL_7E7_CELL_51: battery_cell_voltages[50] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_52: + case POLL_7E7_CELL_52: battery_cell_voltages[51] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_53: + case POLL_7E7_CELL_53: battery_cell_voltages[52] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_54: + case POLL_7E7_CELL_54: battery_cell_voltages[53] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_55: + case POLL_7E7_CELL_55: battery_cell_voltages[54] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_56: + case POLL_7E7_CELL_56: battery_cell_voltages[55] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_57: + case POLL_7E7_CELL_57: battery_cell_voltages[56] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_58: + case POLL_7E7_CELL_58: battery_cell_voltages[57] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_59: + case POLL_7E7_CELL_59: battery_cell_voltages[58] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_60: + case POLL_7E7_CELL_60: battery_cell_voltages[59] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_61: + case POLL_7E7_CELL_61: battery_cell_voltages[60] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_62: + case POLL_7E7_CELL_62: battery_cell_voltages[61] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_63: + case POLL_7E7_CELL_63: battery_cell_voltages[62] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_64: + case POLL_7E7_CELL_64: battery_cell_voltages[63] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_65: + case POLL_7E7_CELL_65: battery_cell_voltages[64] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_66: + case POLL_7E7_CELL_66: battery_cell_voltages[65] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_67: + case POLL_7E7_CELL_67: battery_cell_voltages[66] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_68: + case POLL_7E7_CELL_68: battery_cell_voltages[67] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_69: + case POLL_7E7_CELL_69: battery_cell_voltages[68] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_70: + case POLL_7E7_CELL_70: battery_cell_voltages[69] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_71: + case POLL_7E7_CELL_71: battery_cell_voltages[70] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_72: + case POLL_7E7_CELL_72: battery_cell_voltages[71] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_73: + case POLL_7E7_CELL_73: battery_cell_voltages[72] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_74: + case POLL_7E7_CELL_74: battery_cell_voltages[73] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_75: + case POLL_7E7_CELL_75: battery_cell_voltages[74] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_76: + case POLL_7E7_CELL_76: battery_cell_voltages[75] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_77: + case POLL_7E7_CELL_77: battery_cell_voltages[76] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_78: + case POLL_7E7_CELL_78: battery_cell_voltages[77] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_79: + case POLL_7E7_CELL_79: battery_cell_voltages[78] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_80: + case POLL_7E7_CELL_80: battery_cell_voltages[79] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_81: + case POLL_7E7_CELL_81: battery_cell_voltages[80] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_82: + case POLL_7E7_CELL_82: battery_cell_voltages[81] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_83: + case POLL_7E7_CELL_83: battery_cell_voltages[82] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_84: + case POLL_7E7_CELL_84: battery_cell_voltages[83] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_85: + case POLL_7E7_CELL_85: battery_cell_voltages[84] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_86: + case POLL_7E7_CELL_86: battery_cell_voltages[85] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_87: + case POLL_7E7_CELL_87: battery_cell_voltages[86] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_88: + case POLL_7E7_CELL_88: battery_cell_voltages[87] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_89: + case POLL_7E7_CELL_89: battery_cell_voltages[88] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_90: + case POLL_7E7_CELL_90: battery_cell_voltages[89] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_91: + case POLL_7E7_CELL_91: battery_cell_voltages[90] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_92: + case POLL_7E7_CELL_92: battery_cell_voltages[91] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_93: + case POLL_7E7_CELL_93: battery_cell_voltages[92] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_94: + case POLL_7E7_CELL_94: battery_cell_voltages[93] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_95: + case POLL_7E7_CELL_95: battery_cell_voltages[94] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; - case POLL_CELL_96: + case POLL_7E7_CELL_96: battery_cell_voltages[95] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; default: @@ -683,17 +622,13 @@ void send_can_battery() { if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) { previousMillis200ms = currentMillis; - // Update current poll from the array - currentpoll = poll_commands[poll_index]; - poll_index = (poll_index + 1) % 115; - - BOLT_POLL_7E4.data.u8[2] = (uint8_t)((currentpoll & 0xFF00) >> 8); - BOLT_POLL_7E4.data.u8[3] = (uint8_t)(currentpoll & 0x00FF); + // Update current poll from the 7E7 array + currentpoll = poll_commands_7E7[poll_index]; + poll_index = (poll_index + 1) % 108; BOLT_POLL_7E7.data.u8[2] = (uint8_t)((currentpoll & 0xFF00) >> 8); BOLT_POLL_7E7.data.u8[3] = (uint8_t)(currentpoll & 0x00FF); - transmit_can(&BOLT_POLL_7E4, can_config.battery); transmit_can(&BOLT_POLL_7E7, can_config.battery); } } diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.h b/Software/src/battery/BOLT-AMPERA-BATTERY.h index 46c28f0a0..acc553759 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.h +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.h @@ -11,121 +11,114 @@ #define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value -#define POLL_CAPACITY_EST_GEN1 0x41A3 -#define POLL_CAPACITY_EST_GEN2 0x45F9 -#define POLL_SOC_DISPLAY 0x8334 -#define POLL_SOC_RAW_HIGHPREC 0x43AF -#define POLL_MAX_TEMPERATURE 0x4349 -#define POLL_MIN_TEMPERATURE 0x434A -#define POLL_MIN_CELL_V 0x4329 -#define POLL_MAX_CELL_V 0x432B -#define POLL_INTERNAL_RES 0x40E9 -#define POLL_MIN_BATT_V 0x433B -#define POLL_MAX_BATT_V 0x433C -#define POLL_VOLTAGE 0x432D -#define POLL_VEHICLE_ISOLATION 0x41EC -#define POLL_ISOLATION_TEST_KOHM 0x43A6 -#define POLL_HV_LOCKED_OUT 0x44F8 -#define POLL_CRASH_EVENT 0x4522 -#define POLL_HVIL 0x4310 -#define POLL_HVIL_STATUS 0x4311 -#define POLL_CURRENT 0x4356 -#define POLL_CELL_01 0x4181 -#define POLL_CELL_02 0x4182 -#define POLL_CELL_03 0x4183 -#define POLL_CELL_04 0x4184 -#define POLL_CELL_05 0x4185 -#define POLL_CELL_06 0x4186 -#define POLL_CELL_07 0x4187 -#define POLL_CELL_08 0x4188 -#define POLL_CELL_09 0x4189 -#define POLL_CELL_10 0x418A -#define POLL_CELL_11 0x418B -#define POLL_CELL_12 0x418C -#define POLL_CELL_13 0x418D -#define POLL_CELL_14 0x418E -#define POLL_CELL_15 0x418F -#define POLL_CELL_16 0x4190 -#define POLL_CELL_17 0x4191 -#define POLL_CELL_18 0x4192 -#define POLL_CELL_19 0x4193 -#define POLL_CELL_20 0x4194 -#define POLL_CELL_21 0x4195 -#define POLL_CELL_22 0x4196 -#define POLL_CELL_23 0x4197 -#define POLL_CELL_24 0x4198 -#define POLL_CELL_25 0x4199 -#define POLL_CELL_26 0x419A -#define POLL_CELL_27 0x419B -#define POLL_CELL_28 0x419C -#define POLL_CELL_29 0x419D -#define POLL_CELL_30 0x419E -#define POLL_CELL_31 0x419F -#define POLL_CELL_32 0x4200 -#define POLL_CELL_33 0x4201 -#define POLL_CELL_34 0x4202 -#define POLL_CELL_35 0x4203 -#define POLL_CELL_36 0x4204 -#define POLL_CELL_37 0x4205 -#define POLL_CELL_38 0x4206 -#define POLL_CELL_39 0x4207 -#define POLL_CELL_40 0x4208 -#define POLL_CELL_41 0x4209 -#define POLL_CELL_42 0x420A -#define POLL_CELL_43 0x420B -#define POLL_CELL_44 0x420C -#define POLL_CELL_45 0x420D -#define POLL_CELL_46 0x420E -#define POLL_CELL_47 0x420F -#define POLL_CELL_48 0x4210 -#define POLL_CELL_49 0x4211 -#define POLL_CELL_50 0x4212 -#define POLL_CELL_51 0x4213 -#define POLL_CELL_52 0x4214 -#define POLL_CELL_53 0x4215 -#define POLL_CELL_54 0x4216 -#define POLL_CELL_55 0x4217 -#define POLL_CELL_56 0x4218 -#define POLL_CELL_57 0x4219 -#define POLL_CELL_58 0x421A -#define POLL_CELL_59 0x421B -#define POLL_CELL_60 0x421C -#define POLL_CELL_61 0x421D -#define POLL_CELL_62 0x421E -#define POLL_CELL_63 0x421F -#define POLL_CELL_64 0x4220 -#define POLL_CELL_65 0x4221 -#define POLL_CELL_66 0x4222 -#define POLL_CELL_67 0x4223 -#define POLL_CELL_68 0x4224 -#define POLL_CELL_69 0x4225 -#define POLL_CELL_70 0x4226 -#define POLL_CELL_71 0x4227 -#define POLL_CELL_72 0x4228 -#define POLL_CELL_73 0x4229 -#define POLL_CELL_74 0x422A -#define POLL_CELL_75 0x422B -#define POLL_CELL_76 0x422C -#define POLL_CELL_77 0x422D -#define POLL_CELL_78 0x422E -#define POLL_CELL_79 0x422F -#define POLL_CELL_80 0x4230 -#define POLL_CELL_81 0x4231 -#define POLL_CELL_82 0x4232 -#define POLL_CELL_83 0x4233 -#define POLL_CELL_84 0x4234 -#define POLL_CELL_85 0x4235 -#define POLL_CELL_86 0x4236 -#define POLL_CELL_87 0x4237 -#define POLL_CELL_88 0x4238 -#define POLL_CELL_89 0x4239 -#define POLL_CELL_90 0x423A -#define POLL_CELL_91 0x423B -#define POLL_CELL_92 0x423C -#define POLL_CELL_93 0x423D -#define POLL_CELL_94 0x423E -#define POLL_CELL_95 0x423F -#define POLL_CELL_96 0x4240 +#define POLL_7E7_CURRENT 0x40D4 +#define POLL_7E7_5V_REF 0x40D3 +#define POLL_7E7_MODULE_TEMP_1 0x40D7 +#define POLL_7E7_MODULE_TEMP_2 0x40D9 +#define POLL_7E7_MODULE_TEMP_3 0x40DB +#define POLL_7E7_MODULE_TEMP_4 0x40DD +#define POLL_7E7_MODULE_TEMP_5 0x40DF +#define POLL_7E7_MODULE_TEMP_6 0x40E1 +#define POLL_7E7_CELL_AVG_VOLTAGE 0xC218 +#define POLL_7E7_CELL_AVG_VOLTAGE_2 0x44B9 +#define POLL_7E7_TERMINAL_VOLTAGE 0x82A3 +#define POLL_7E7_IGNITION_POWER_MODE 0x8002 +#define POLL_7E7_CELL_01 0x4181 +#define POLL_7E7_CELL_02 0x4182 +#define POLL_7E7_CELL_03 0x4183 +#define POLL_7E7_CELL_04 0x4184 +#define POLL_7E7_CELL_05 0x4185 +#define POLL_7E7_CELL_06 0x4186 +#define POLL_7E7_CELL_07 0x4187 +#define POLL_7E7_CELL_08 0x4188 +#define POLL_7E7_CELL_09 0x4189 +#define POLL_7E7_CELL_10 0x418A +#define POLL_7E7_CELL_11 0x418B +#define POLL_7E7_CELL_12 0x418C +#define POLL_7E7_CELL_13 0x418D +#define POLL_7E7_CELL_14 0x418E +#define POLL_7E7_CELL_15 0x418F +#define POLL_7E7_CELL_16 0x4190 +#define POLL_7E7_CELL_17 0x4191 +#define POLL_7E7_CELL_18 0x4192 +#define POLL_7E7_CELL_19 0x4193 +#define POLL_7E7_CELL_20 0x4194 +#define POLL_7E7_CELL_21 0x4195 +#define POLL_7E7_CELL_22 0x4196 +#define POLL_7E7_CELL_23 0x4197 +#define POLL_7E7_CELL_24 0x4198 +#define POLL_7E7_CELL_25 0x4199 +#define POLL_7E7_CELL_26 0x419A +#define POLL_7E7_CELL_27 0x419B +#define POLL_7E7_CELL_28 0x419C +#define POLL_7E7_CELL_29 0x419D +#define POLL_7E7_CELL_30 0x419E +#define POLL_7E7_CELL_31 0x419F +#define POLL_7E7_CELL_32 0x4200 +#define POLL_7E7_CELL_33 0x4201 +#define POLL_7E7_CELL_34 0x4202 +#define POLL_7E7_CELL_35 0x4203 +#define POLL_7E7_CELL_36 0x4204 +#define POLL_7E7_CELL_37 0x4205 +#define POLL_7E7_CELL_38 0x4206 +#define POLL_7E7_CELL_39 0x4207 +#define POLL_7E7_CELL_40 0x4208 +#define POLL_7E7_CELL_41 0x4209 +#define POLL_7E7_CELL_42 0x420A +#define POLL_7E7_CELL_43 0x420B +#define POLL_7E7_CELL_44 0x420C +#define POLL_7E7_CELL_45 0x420D +#define POLL_7E7_CELL_46 0x420E +#define POLL_7E7_CELL_47 0x420F +#define POLL_7E7_CELL_48 0x4210 +#define POLL_7E7_CELL_49 0x4211 +#define POLL_7E7_CELL_50 0x4212 +#define POLL_7E7_CELL_51 0x4213 +#define POLL_7E7_CELL_52 0x4214 +#define POLL_7E7_CELL_53 0x4215 +#define POLL_7E7_CELL_54 0x4216 +#define POLL_7E7_CELL_55 0x4217 +#define POLL_7E7_CELL_56 0x4218 +#define POLL_7E7_CELL_57 0x4219 +#define POLL_7E7_CELL_58 0x421A +#define POLL_7E7_CELL_59 0x421B +#define POLL_7E7_CELL_60 0x421C +#define POLL_7E7_CELL_61 0x421D +#define POLL_7E7_CELL_62 0x421E +#define POLL_7E7_CELL_63 0x421F +#define POLL_7E7_CELL_64 0x4220 +#define POLL_7E7_CELL_65 0x4221 +#define POLL_7E7_CELL_66 0x4222 +#define POLL_7E7_CELL_67 0x4223 +#define POLL_7E7_CELL_68 0x4224 +#define POLL_7E7_CELL_69 0x4225 +#define POLL_7E7_CELL_70 0x4226 +#define POLL_7E7_CELL_71 0x4227 +#define POLL_7E7_CELL_72 0x4228 +#define POLL_7E7_CELL_73 0x4229 +#define POLL_7E7_CELL_74 0x422A +#define POLL_7E7_CELL_75 0x422B +#define POLL_7E7_CELL_76 0x422C +#define POLL_7E7_CELL_77 0x422D +#define POLL_7E7_CELL_78 0x422E +#define POLL_7E7_CELL_79 0x422F +#define POLL_7E7_CELL_80 0x4230 +#define POLL_7E7_CELL_81 0x4231 +#define POLL_7E7_CELL_82 0x4232 +#define POLL_7E7_CELL_83 0x4233 +#define POLL_7E7_CELL_84 0x4234 +#define POLL_7E7_CELL_85 0x4235 +#define POLL_7E7_CELL_86 0x4236 +#define POLL_7E7_CELL_87 0x4237 +#define POLL_7E7_CELL_88 0x4238 +#define POLL_7E7_CELL_89 0x4239 +#define POLL_7E7_CELL_90 0x423A +#define POLL_7E7_CELL_91 0x423B +#define POLL_7E7_CELL_92 0x423C +#define POLL_7E7_CELL_93 0x423D +#define POLL_7E7_CELL_94 0x423E +#define POLL_7E7_CELL_95 0x423F +#define POLL_7E7_CELL_96 0x4240 void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 7a9c2cd1d..55cfde9b1 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -3,6 +3,23 @@ #include "../include.h" +typedef struct { + /** uint16_t */ + /** PID polling parameters */ + uint16_t battery_5V_ref = 0; + uint16_t battery_module_temp_1 = 0; + uint16_t battery_module_temp_2 = 0; + uint16_t battery_module_temp_3 = 0; + uint16_t battery_module_temp_4 = 0; + uint16_t battery_module_temp_5 = 0; + uint16_t battery_module_temp_6 = 0; + uint16_t battery_cell_average_voltage = 0; + uint16_t battery_cell_average_voltage_2 = 0; + uint16_t battery_terminal_voltage = 0; + uint16_t battery_ignition_power_mode = 0; + int16_t battery_current = 0; +} DATALAYER_INFO_BOLTAMPERA; + typedef struct { /** uint16_t */ /** Terminal 30 - 12V SME Supply Voltage */ @@ -326,6 +343,7 @@ typedef struct { class DataLayerExtended { public: + DATALAYER_INFO_BOLTAMPERA boltampera; DATALAYER_INFO_BMWIX bmwix; DATALAYER_INFO_BMWI3 bmwi3; DATALAYER_INFO_BYDATTO3 bydAtto3; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index b3cba77f5..816325d84 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -20,6 +20,24 @@ String advanced_battery_processor(const String& var) { // Start a new block with a specific background color content += "
"; +#ifdef BOLT_AMPERA_BATTERY + content += "

5V Reference: " + String(datalayer_extended.boltampera.battery_5V_ref) + "

"; + content += "

Module 1 temp: " + String(datalayer_extended.boltampera.battery_module_temp_1) + "

"; + content += "

Module 2 temp: " + String(datalayer_extended.boltampera.battery_module_temp_2) + "

"; + content += "

Module 3 temp: " + String(datalayer_extended.boltampera.battery_module_temp_3) + "

"; + content += "

Module 4 temp: " + String(datalayer_extended.boltampera.battery_module_temp_4) + "

"; + content += "

Module 5 temp: " + String(datalayer_extended.boltampera.battery_module_temp_5) + "

"; + content += "

Module 6 temp: " + String(datalayer_extended.boltampera.battery_module_temp_6) + "

"; + content += + "

Cell average voltage: " + String(datalayer_extended.boltampera.battery_cell_average_voltage) + "

"; + content += + "

Cell average voltage 2: " + String(datalayer_extended.boltampera.battery_cell_average_voltage_2) + "

"; + content += "

Terminal voltage: " + String(datalayer_extended.boltampera.battery_terminal_voltage) + "

"; + content += + "

Ignition power mode: " + String(datalayer_extended.boltampera.battery_ignition_power_mode) + "

"; + content += "

Battery current: " + String(datalayer_extended.boltampera.battery_current) + "

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

Battery Voltage after Contactor: " + String(datalayer_extended.bmwix.battery_voltage_after_contactor) + @@ -467,8 +485,9 @@ String advanced_battery_processor(const String& var) { content += "

soc max: " + String(datalayer_extended.zoePH2.battery_soc_max) + "

"; #endif //RENAULT_ZOE_GEN2_BATTERY -#if !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ - !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) +#if !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_BATTERY) && !defined(TESLA_BATTERY) && \ + !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && !defined(BYD_ATTO_3_BATTERY) && \ + !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) content += "No extra information available for this battery type"; #endif From 691173c9c06d2668d22919955ced6ff20ad916d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 8 Dec 2024 18:33:52 +0200 Subject: [PATCH 035/225] Fix scaling on 7E7 polls --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 228 +++++++++---------- Software/src/datalayer/datalayer_extended.h | 12 +- 2 files changed, 120 insertions(+), 120 deletions(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index a113d3a93..ac15f68c7 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -59,12 +59,12 @@ static uint16_t battery_crash_event = 0; static uint16_t battery_HVIL = 0; static uint16_t battery_HVIL_status = 0; static uint16_t battery_5V_ref = 0; -static uint16_t battery_module_temp_1 = 0; -static uint16_t battery_module_temp_2 = 0; -static uint16_t battery_module_temp_3 = 0; -static uint16_t battery_module_temp_4 = 0; -static uint16_t battery_module_temp_5 = 0; -static uint16_t battery_module_temp_6 = 0; +static int16_t battery_module_temp_1 = 0; +static int16_t battery_module_temp_2 = 0; +static int16_t battery_module_temp_3 = 0; +static int16_t battery_module_temp_4 = 0; +static int16_t battery_module_temp_5 = 0; +static int16_t battery_module_temp_6 = 0; static uint16_t battery_cell_average_voltage = 0; static uint16_t battery_cell_average_voltage_2 = 0; static uint16_t battery_terminal_voltage = 0; @@ -146,7 +146,7 @@ void update_values_battery() { //This function maps all the values fetched via //datalayer.battery.status.voltage_dV = battery_voltage * 0.52; datalayer.battery.status.voltage_dV = (battery_voltage_periodic / 8) * 10; - datalayer.battery.status.current_dA = (battery_current / 20) - 400; + datalayer.battery.status.current_dA = battery_current; datalayer.battery.info.total_capacity_Wh; @@ -275,325 +275,325 @@ void receive_can_battery(CAN_frame rx_frame) { battery_current = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; case POLL_7E7_5V_REF: - battery_5V_ref = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_5V_ref = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5) / 65535); break; case POLL_7E7_MODULE_TEMP_1: - battery_module_temp_1 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_module_temp_1 = (rx_frame.data.u8[4] - 40); break; case POLL_7E7_MODULE_TEMP_2: - battery_module_temp_2 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_module_temp_2 = (rx_frame.data.u8[4] - 40); break; case POLL_7E7_MODULE_TEMP_3: - battery_module_temp_3 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_module_temp_3 = (rx_frame.data.u8[4] - 40); break; case POLL_7E7_MODULE_TEMP_4: - battery_module_temp_4 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_module_temp_4 = (rx_frame.data.u8[4] - 40); break; case POLL_7E7_MODULE_TEMP_5: - battery_module_temp_5 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_module_temp_5 = (rx_frame.data.u8[4] - 40); break; case POLL_7E7_MODULE_TEMP_6: - battery_module_temp_6 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_module_temp_6 = (rx_frame.data.u8[4] - 40); break; case POLL_7E7_CELL_AVG_VOLTAGE: - battery_cell_average_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_average_voltage = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_AVG_VOLTAGE_2: - battery_cell_average_voltage_2 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_average_voltage_2 = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 8000) * 1000); break; case POLL_7E7_TERMINAL_VOLTAGE: - battery_terminal_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_terminal_voltage = rx_frame.data.u8[4] * 2; break; case POLL_7E7_IGNITION_POWER_MODE: - battery_ignition_power_mode = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_ignition_power_mode = rx_frame.data.u8[4]; break; case POLL_7E7_CELL_01: - battery_cell_voltages[0] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[0] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_02: - battery_cell_voltages[1] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[1] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_03: - battery_cell_voltages[2] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[2] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_04: - battery_cell_voltages[3] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[3] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_05: - battery_cell_voltages[4] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[4] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_06: - battery_cell_voltages[5] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[5] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_07: - battery_cell_voltages[6] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[6] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_08: - battery_cell_voltages[7] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[7] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_09: - battery_cell_voltages[8] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[8] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_10: - battery_cell_voltages[9] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[9] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_11: - battery_cell_voltages[10] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[10] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_12: - battery_cell_voltages[11] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[11] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_13: - battery_cell_voltages[12] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[12] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_14: - battery_cell_voltages[13] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[13] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_15: - battery_cell_voltages[14] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[14] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_16: - battery_cell_voltages[15] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[15] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_17: - battery_cell_voltages[16] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[16] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_18: - battery_cell_voltages[17] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[17] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_19: - battery_cell_voltages[18] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[18] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_20: - battery_cell_voltages[19] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[19] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_21: - battery_cell_voltages[20] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[20] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_22: - battery_cell_voltages[21] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[21] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_23: - battery_cell_voltages[22] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[22] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_24: - battery_cell_voltages[23] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[23] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_25: - battery_cell_voltages[24] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[24] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_26: - battery_cell_voltages[25] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[25] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_27: - battery_cell_voltages[26] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[26] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_28: - battery_cell_voltages[27] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[27] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_29: - battery_cell_voltages[28] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[28] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_30: - battery_cell_voltages[29] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[29] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_31: - battery_cell_voltages[30] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[30] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_32: - battery_cell_voltages[31] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[31] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_33: - battery_cell_voltages[32] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[32] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_34: - battery_cell_voltages[33] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[33] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_35: - battery_cell_voltages[34] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[34] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_36: - battery_cell_voltages[35] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[35] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_37: - battery_cell_voltages[36] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[36] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_38: - battery_cell_voltages[37] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[37] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_39: - battery_cell_voltages[38] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[38] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_40: - battery_cell_voltages[39] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[39] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_41: - battery_cell_voltages[40] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[40] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_42: - battery_cell_voltages[41] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[41] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_43: - battery_cell_voltages[42] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[42] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_44: - battery_cell_voltages[43] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[43] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_45: - battery_cell_voltages[44] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[44] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_46: - battery_cell_voltages[45] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[45] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_47: - battery_cell_voltages[46] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[46] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_48: - battery_cell_voltages[47] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[47] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_49: - battery_cell_voltages[48] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[48] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_50: - battery_cell_voltages[49] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[49] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_51: - battery_cell_voltages[50] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[50] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_52: - battery_cell_voltages[51] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[51] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_53: - battery_cell_voltages[52] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[52] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_54: - battery_cell_voltages[53] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[53] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_55: - battery_cell_voltages[54] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[54] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_56: - battery_cell_voltages[55] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[55] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_57: - battery_cell_voltages[56] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[56] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_58: - battery_cell_voltages[57] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[57] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_59: - battery_cell_voltages[58] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[58] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_60: - battery_cell_voltages[59] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[59] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_61: - battery_cell_voltages[60] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[60] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_62: - battery_cell_voltages[61] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[61] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_63: - battery_cell_voltages[62] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[62] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_64: - battery_cell_voltages[63] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[63] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_65: - battery_cell_voltages[64] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[64] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_66: - battery_cell_voltages[65] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[65] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_67: - battery_cell_voltages[66] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[66] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_68: - battery_cell_voltages[67] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[67] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_69: - battery_cell_voltages[68] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[68] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_70: - battery_cell_voltages[69] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[69] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_71: - battery_cell_voltages[70] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[70] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_72: - battery_cell_voltages[71] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[71] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_73: - battery_cell_voltages[72] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[72] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_74: - battery_cell_voltages[73] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[73] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_75: - battery_cell_voltages[74] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[74] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_76: - battery_cell_voltages[75] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[75] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_77: - battery_cell_voltages[76] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[76] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_78: - battery_cell_voltages[77] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[77] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_79: - battery_cell_voltages[78] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[78] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_80: - battery_cell_voltages[79] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[79] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_81: - battery_cell_voltages[80] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[80] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_82: - battery_cell_voltages[81] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[81] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_83: - battery_cell_voltages[82] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[82] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_84: - battery_cell_voltages[83] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[83] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_85: - battery_cell_voltages[84] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[84] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_86: - battery_cell_voltages[85] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[85] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_87: - battery_cell_voltages[86] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[86] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_88: - battery_cell_voltages[87] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[87] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_89: - battery_cell_voltages[88] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[88] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_90: - battery_cell_voltages[89] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[89] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_91: - battery_cell_voltages[90] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[90] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_92: - battery_cell_voltages[91] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[91] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_93: - battery_cell_voltages[92] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[92] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_94: - battery_cell_voltages[93] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[93] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_95: - battery_cell_voltages[94] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[94] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; case POLL_7E7_CELL_96: - battery_cell_voltages[95] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_cell_voltages[95] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); break; default: break; diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 55cfde9b1..77efc6427 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -7,12 +7,12 @@ typedef struct { /** uint16_t */ /** PID polling parameters */ uint16_t battery_5V_ref = 0; - uint16_t battery_module_temp_1 = 0; - uint16_t battery_module_temp_2 = 0; - uint16_t battery_module_temp_3 = 0; - uint16_t battery_module_temp_4 = 0; - uint16_t battery_module_temp_5 = 0; - uint16_t battery_module_temp_6 = 0; + int16_t battery_module_temp_1 = 0; + int16_t battery_module_temp_2 = 0; + int16_t battery_module_temp_3 = 0; + int16_t battery_module_temp_4 = 0; + int16_t battery_module_temp_5 = 0; + int16_t battery_module_temp_6 = 0; uint16_t battery_cell_average_voltage = 0; uint16_t battery_cell_average_voltage_2 = 0; uint16_t battery_terminal_voltage = 0; From 8b221924a87546039cef5fd2e164b70ccaf33b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 8 Dec 2024 20:49:21 +0200 Subject: [PATCH 036/225] Add 7E4 mappings --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 175 +++++++++++++++--- Software/src/battery/BOLT-AMPERA-BATTERY.h | 20 ++ Software/src/datalayer/datalayer_extended.h | 21 ++- .../webserver/advanced_battery_html.cpp | 22 ++- 4 files changed, 212 insertions(+), 26 deletions(-) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index ac15f68c7..510b90b72 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -7,7 +7,8 @@ /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis20ms = 0; // will store last time a 20ms CAN Message was send -static unsigned long previousMillis200ms = 0; // will store last time a 200ms CAN Message was send +static unsigned long previousMillis100ms = 0; // will store last time a 100ms CAN Message was send +static unsigned long previousMillis120ms = 0; // will store last time a 120ms CAN Message was send CAN_frame BOLT_778 = {.FD = false, // Unsure of what this message is, added only as example .ext_ID = false, @@ -18,7 +19,7 @@ CAN_frame BOLT_POLL_7E4 = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x7E4, - .data = {0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + .data = {0x03, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; CAN_frame BOLT_ACK_7E4 = {.FD = false, .ext_ID = false, .DLC = 8, @@ -35,7 +36,7 @@ CAN_frame BOLT_ACK_7E7 = {.FD = false, .ID = 0x7E7, .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -// 7E4 Battery , reply 000007EC (For some reason does not work) +// 7E4 Battery , reply 000007EC // 7E7 Battery (Cell voltages), reply 000007EF static uint16_t battery_cell_voltages[96]; //array with all the cellvoltages @@ -48,9 +49,9 @@ static uint16_t battery_min_temperature = 0; static uint16_t battery_min_cell_voltage = 0; static uint16_t battery_max_cell_voltage = 0; static uint16_t battery_internal_resistance = 0; -static uint16_t battery_min_voltage = 0; -static uint16_t battery_max_voltage = 0; -static uint16_t battery_voltage = 3700; +static uint16_t battery_lowest_cell = 0; +static uint16_t battery_highest_cell = 0; +static uint16_t battery_voltage_polled = 0; static uint16_t battery_voltage_periodic = 0; static uint16_t battery_vehicle_isolation = 0; static uint16_t battery_isolation_kohm = 0; @@ -59,6 +60,7 @@ static uint16_t battery_crash_event = 0; static uint16_t battery_HVIL = 0; static uint16_t battery_HVIL_status = 0; static uint16_t battery_5V_ref = 0; +static int16_t battery_current_7E4 = 0; static int16_t battery_module_temp_1 = 0; static int16_t battery_module_temp_2 = 0; static int16_t battery_module_temp_3 = 0; @@ -69,7 +71,7 @@ static uint16_t battery_cell_average_voltage = 0; static uint16_t battery_cell_average_voltage_2 = 0; static uint16_t battery_terminal_voltage = 0; static uint16_t battery_ignition_power_mode = 0; -static int16_t battery_current = 0; +static int16_t battery_current_7E7 = 0; static int16_t temperature_1 = 0; static int16_t temperature_2 = 0; static int16_t temperature_3 = 0; @@ -79,10 +81,32 @@ static int16_t temperature_6 = 0; static int16_t temperature_highest = 0; static int16_t temperature_lowest = 0; static uint8_t mux = 0; - -static uint8_t poll_index = 0; -static uint16_t currentpoll = POLL_7E7_CURRENT; -static uint16_t reply_poll = 0; +static uint8_t poll_index_7E4 = 0; +static uint16_t currentpoll_7E4 = POLL_7E4_CAPACITY_EST_GEN1; +static uint16_t reply_poll_7E4 = 0; +static uint8_t poll_index_7E7 = 0; +static uint16_t currentpoll_7E7 = POLL_7E7_CURRENT; +static uint16_t reply_poll_7E7 = 0; + +const uint16_t poll_commands_7E4[19] = {POLL_7E4_CAPACITY_EST_GEN1, + POLL_7E4_CAPACITY_EST_GEN2, + POLL_7E4_SOC_DISPLAY, + POLL_7E4_SOC_RAW_HIGHPREC, + POLL_7E4_MAX_TEMPERATURE, + POLL_7E4_MIN_TEMPERATURE, + POLL_7E4_MIN_CELL_V, + POLL_7E4_MAX_CELL_V, + POLL_7E4_INTERNAL_RES, + POLL_7E4_LOWEST_CELL_NUMBER, + POLL_7E4_HIGHEST_CELL_NUMBER, + POLL_7E4_VOLTAGE, + POLL_7E4_VEHICLE_ISOLATION, + POLL_7E4_ISOLATION_TEST_KOHM, + POLL_7E4_HV_LOCKED_OUT, + POLL_7E4_CRASH_EVENT, + POLL_7E4_HVIL, + POLL_7E4_HVIL_STATUS, + POLL_7E4_CURRENT}; const uint16_t poll_commands_7E7[108] = {POLL_7E7_CURRENT, POLL_7E7_5V_REF, POLL_7E7_MODULE_TEMP_1, POLL_7E7_MODULE_TEMP_2, @@ -141,12 +165,12 @@ const uint16_t poll_commands_7E7[108] = {POLL_7E7_CURRENT, POLL_7E7_5V_ void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer - datalayer.battery.status.real_soc = (battery_SOC_display * 100 / 255); + datalayer.battery.status.real_soc = battery_SOC_display; //datalayer.battery.status.voltage_dV = battery_voltage * 0.52; datalayer.battery.status.voltage_dV = (battery_voltage_periodic / 8) * 10; - datalayer.battery.status.current_dA = battery_current; + datalayer.battery.status.current_dA = battery_current_7E7; datalayer.battery.info.total_capacity_Wh; @@ -194,7 +218,26 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.boltampera.battery_cell_average_voltage_2 = battery_cell_average_voltage_2; datalayer_extended.boltampera.battery_terminal_voltage = battery_terminal_voltage; datalayer_extended.boltampera.battery_ignition_power_mode = battery_ignition_power_mode; - datalayer_extended.boltampera.battery_current = battery_current; + datalayer_extended.boltampera.battery_current_7E7 = battery_current_7E7; + datalayer_extended.boltampera.battery_capacity_my17_18 = battery_capacity_my17_18; + datalayer_extended.boltampera.battery_capacity_my19plus = battery_capacity_my19plus; + datalayer_extended.boltampera.battery_SOC_display = battery_SOC_display; + datalayer_extended.boltampera.battery_SOC_raw_highprec = battery_SOC_raw_highprec; + datalayer_extended.boltampera.battery_max_temperature = battery_max_temperature; + datalayer_extended.boltampera.battery_min_temperature = battery_min_temperature; + datalayer_extended.boltampera.battery_min_cell_voltage = battery_min_cell_voltage; + datalayer_extended.boltampera.battery_max_cell_voltage = battery_max_cell_voltage; + datalayer_extended.boltampera.battery_lowest_cell = battery_lowest_cell; + datalayer_extended.boltampera.battery_highest_cell = battery_highest_cell; + datalayer_extended.boltampera.battery_internal_resistance = battery_internal_resistance; + datalayer_extended.boltampera.battery_voltage_polled = battery_voltage_polled; + datalayer_extended.boltampera.battery_vehicle_isolation = battery_vehicle_isolation; + datalayer_extended.boltampera.battery_isolation_kohm = battery_isolation_kohm; + datalayer_extended.boltampera.battery_HV_locked = battery_HV_locked; + datalayer_extended.boltampera.battery_crash_event = battery_crash_event; + datalayer_extended.boltampera.battery_HVIL = battery_HVIL; + datalayer_extended.boltampera.battery_HVIL_status = battery_HVIL_status; + datalayer_extended.boltampera.battery_current_7E4 = battery_current_7E4; } void receive_can_battery(CAN_frame rx_frame) { @@ -260,6 +303,76 @@ void receive_can_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; break; case 0x7EC: //When polling 7E4 BMS replies with 7EC ?? + + if (rx_frame.data.u8[0] == 0x10) { //"PID Header" + transmit_can(&BOLT_ACK_7E4, can_config.battery); + } + + //Frame 2 & 3 contains reply + reply_poll_7E4 = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + + switch (reply_poll_7E4) { + case POLL_7E4_CAPACITY_EST_GEN1: + battery_capacity_my17_18 = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case POLL_7E4_CAPACITY_EST_GEN2: + battery_capacity_my19plus = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case POLL_7E4_SOC_DISPLAY: + battery_SOC_display = ((rx_frame.data.u8[4] * 100) / 255); + break; + case POLL_7E4_SOC_RAW_HIGHPREC: + battery_SOC_raw_highprec = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 100) / 65535); + break; + case POLL_7E4_MAX_TEMPERATURE: + battery_max_temperature = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E4_MIN_TEMPERATURE: + battery_min_temperature = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E4_MIN_CELL_V: + battery_min_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 1666; + break; + case POLL_7E4_MAX_CELL_V: + battery_max_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 1666; + break; + case POLL_7E4_INTERNAL_RES: + battery_internal_resistance = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 2; + break; + case POLL_7E4_LOWEST_CELL_NUMBER: + battery_lowest_cell = rx_frame.data.u8[4]; + break; + case POLL_7E4_HIGHEST_CELL_NUMBER: + battery_highest_cell = rx_frame.data.u8[4]; + break; + case POLL_7E4_VOLTAGE: + battery_voltage_polled = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 0.52); + break; + case POLL_7E4_VEHICLE_ISOLATION: + battery_vehicle_isolation = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case POLL_7E4_ISOLATION_TEST_KOHM: + battery_isolation_kohm = (rx_frame.data.u8[4] * 25); + break; + case POLL_7E4_HV_LOCKED_OUT: + battery_HV_locked = rx_frame.data.u8[4]; + break; + case POLL_7E4_CRASH_EVENT: + battery_crash_event = rx_frame.data.u8[4]; + break; + case POLL_7E4_HVIL: + battery_HVIL = rx_frame.data.u8[4]; + break; + case POLL_7E4_HVIL_STATUS: + battery_HVIL_status = rx_frame.data.u8[4]; + break; + case POLL_7E4_CURRENT: + battery_current_7E4 = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / (-6.675)); + break; + default: + break; + } + break; case 0x7EF: //When polling 7E7 BMS replies with 7EF @@ -268,11 +381,11 @@ void receive_can_battery(CAN_frame rx_frame) { } //Frame 2 & 3 contains reply - reply_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + reply_poll_7E7 = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; - switch (reply_poll) { + switch (reply_poll_7E7) { case POLL_7E7_CURRENT: - battery_current = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + battery_current_7E7 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; break; case POLL_7E7_5V_REF: battery_5V_ref = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5) / 65535); @@ -618,19 +731,33 @@ void send_can_battery() { transmit_can(&BOLT_778, can_config.battery); } - //Send 200ms message - if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) { - previousMillis200ms = currentMillis; + //Send 100ms message + if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) { + previousMillis100ms = currentMillis; // Update current poll from the 7E7 array - currentpoll = poll_commands_7E7[poll_index]; - poll_index = (poll_index + 1) % 108; + currentpoll_7E7 = poll_commands_7E7[poll_index_7E7]; + poll_index_7E7 = (poll_index_7E7 + 1) % 108; - BOLT_POLL_7E7.data.u8[2] = (uint8_t)((currentpoll & 0xFF00) >> 8); - BOLT_POLL_7E7.data.u8[3] = (uint8_t)(currentpoll & 0x00FF); + BOLT_POLL_7E7.data.u8[2] = (uint8_t)((currentpoll_7E7 & 0xFF00) >> 8); + BOLT_POLL_7E7.data.u8[3] = (uint8_t)(currentpoll_7E7 & 0x00FF); transmit_can(&BOLT_POLL_7E7, can_config.battery); } + + //Send 120ms message + if (currentMillis - previousMillis120ms >= 120) { + previousMillis120ms = currentMillis; + + // Update current poll from the 7E4 array + currentpoll_7E4 = poll_commands_7E4[poll_index_7E4]; + poll_index_7E4 = (poll_index_7E4 + 1) % 19; + + BOLT_POLL_7E4.data.u8[2] = (uint8_t)((currentpoll_7E4 & 0xFF00) >> 8); + BOLT_POLL_7E4.data.u8[3] = (uint8_t)(currentpoll_7E4 & 0x00FF); + + transmit_can(&BOLT_POLL_7E4, can_config.battery); + } } void setup_battery(void) { // Performs one time setup at startup diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.h b/Software/src/battery/BOLT-AMPERA-BATTERY.h index acc553759..7d8772206 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.h +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.h @@ -11,6 +11,26 @@ #define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value +#define POLL_7E4_CAPACITY_EST_GEN1 0x41A3 +#define POLL_7E4_CAPACITY_EST_GEN2 0x45F9 +#define POLL_7E4_SOC_DISPLAY 0x8334 +#define POLL_7E4_SOC_RAW_HIGHPREC 0x43AF +#define POLL_7E4_MAX_TEMPERATURE 0x4349 +#define POLL_7E4_MIN_TEMPERATURE 0x434A +#define POLL_7E4_MIN_CELL_V 0x4329 +#define POLL_7E4_MAX_CELL_V 0x432B +#define POLL_7E4_INTERNAL_RES 0x40E9 +#define POLL_7E4_LOWEST_CELL_NUMBER 0x433B +#define POLL_7E4_HIGHEST_CELL_NUMBER 0x433C +#define POLL_7E4_VOLTAGE 0x432D +#define POLL_7E4_VEHICLE_ISOLATION 0x41EC +#define POLL_7E4_ISOLATION_TEST_KOHM 0x43A6 +#define POLL_7E4_HV_LOCKED_OUT 0x44F8 +#define POLL_7E4_CRASH_EVENT 0x4522 +#define POLL_7E4_HVIL 0x4310 +#define POLL_7E4_HVIL_STATUS 0x4311 +#define POLL_7E4_CURRENT 0x4356 + #define POLL_7E7_CURRENT 0x40D4 #define POLL_7E7_5V_REF 0x40D3 #define POLL_7E7_MODULE_TEMP_1 0x40D7 diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 77efc6427..a46fde127 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -17,7 +17,26 @@ typedef struct { uint16_t battery_cell_average_voltage_2 = 0; uint16_t battery_terminal_voltage = 0; uint16_t battery_ignition_power_mode = 0; - int16_t battery_current = 0; + int16_t battery_current_7E7 = 0; + uint16_t battery_capacity_my17_18 = 0; + uint16_t battery_capacity_my19plus = 0; + uint16_t battery_SOC_display = 0; + uint16_t battery_SOC_raw_highprec = 0; + uint16_t battery_max_temperature = 0; + uint16_t battery_min_temperature = 0; + uint16_t battery_max_cell_voltage = 0; + uint16_t battery_min_cell_voltage = 0; + uint16_t battery_lowest_cell = 0; + uint16_t battery_highest_cell = 0; + uint16_t battery_internal_resistance = 0; + uint16_t battery_voltage_polled = 0; + uint16_t battery_vehicle_isolation = 0; + uint16_t battery_isolation_kohm = 0; + uint16_t battery_HV_locked = 0; + uint16_t battery_crash_event = 0; + uint16_t battery_HVIL = 0; + uint16_t battery_HVIL_status = 0; + int16_t battery_current_7E4 = 0; } DATALAYER_INFO_BOLTAMPERA; typedef struct { diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 816325d84..fc4da60ea 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -35,7 +35,27 @@ String advanced_battery_processor(const String& var) { content += "

Terminal voltage: " + String(datalayer_extended.boltampera.battery_terminal_voltage) + "

"; content += "

Ignition power mode: " + String(datalayer_extended.boltampera.battery_ignition_power_mode) + "

"; - content += "

Battery current: " + String(datalayer_extended.boltampera.battery_current) + "

"; + content += "

Battery current (7E7): " + String(datalayer_extended.boltampera.battery_current_7E7) + "

"; + content += "

Capacity MY17-18: " + String(datalayer_extended.boltampera.battery_capacity_my17_18) + "

"; + content += "

Capacity MY19+: " + String(datalayer_extended.boltampera.battery_capacity_my19plus) + "

"; + content += "

SOC Display: " + String(datalayer_extended.boltampera.battery_SOC_display) + "

"; + content += "

SOC Raw highprec: " + String(datalayer_extended.boltampera.battery_SOC_raw_highprec) + "

"; + content += "

Max temp: " + String(datalayer_extended.boltampera.battery_max_temperature) + "

"; + content += "

Min temp: " + String(datalayer_extended.boltampera.battery_min_temperature) + "

"; + content += "

Cell max mV: " + String(datalayer_extended.boltampera.battery_max_cell_voltage) + "

"; + content += "

Cell min mV: " + String(datalayer_extended.boltampera.battery_min_cell_voltage) + "

"; + content += "

Lowest cell: " + String(datalayer_extended.boltampera.battery_lowest_cell) + "

"; + content += "

Highest cell: " + String(datalayer_extended.boltampera.battery_highest_cell) + "

"; + content += + "

Internal resistance: " + String(datalayer_extended.boltampera.battery_internal_resistance) + "

"; + content += "

Voltage: " + String(datalayer_extended.boltampera.battery_voltage_polled) + "

"; + content += "

Isolation Ohm: " + String(datalayer_extended.boltampera.battery_vehicle_isolation) + "

"; + content += "

Isolation kOhm: " + String(datalayer_extended.boltampera.battery_isolation_kohm) + "

"; + content += "

HV locked: " + String(datalayer_extended.boltampera.battery_HV_locked) + "

"; + content += "

Crash event: " + String(datalayer_extended.boltampera.battery_crash_event) + "

"; + content += "

HVIL: " + String(datalayer_extended.boltampera.battery_HVIL) + "

"; + content += "

HVIL status: " + String(datalayer_extended.boltampera.battery_HVIL_status) + "

"; + content += "

Current (7E4): " + String(datalayer_extended.boltampera.battery_current_7E4) + "

"; #endif //BOLT_AMPERA_BATTERY #ifdef BMW_IX_BATTERY From a467575a57916d3f8b3efb59f51b434fae6f3ab2 Mon Sep 17 00:00:00 2001 From: Bryant Eadon Date: Wed, 11 Dec 2024 10:07:56 -0800 Subject: [PATCH 037/225] Update cellvoltage writing for second battery This fixes issue 663 --- Software/src/battery/BMW-I3-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index e43eaa5ae..cf535f5f3 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -785,7 +785,7 @@ void receive_can_battery2(CAN_frame rx_frame) { datalayer.battery2.status.cell_voltages_mV[3] = ((rx_frame.data.u8[4] * 10) + 1800); datalayer.battery2.status.cell_voltages_mV[4] = ((rx_frame.data.u8[5] * 10) + 1800); datalayer.battery2.status.cell_voltages_mV[5] = ((rx_frame.data.u8[6] * 10) + 1800); - datalayer.battery2.status.cell_voltages_mV[5] = ((rx_frame.data.u8[7] * 10) + 1800); + datalayer.battery2.status.cell_voltages_mV[6] = ((rx_frame.data.u8[7] * 10) + 1800); } break; case 0x430: //BMS [1s] - Charging status of high-voltage battery - 2 From da8c7198c2da1b72a63b105b52b1c9ec9cfa3603 Mon Sep 17 00:00:00 2001 From: rha Date: Wed, 11 Dec 2024 20:49:59 +0200 Subject: [PATCH 038/225] BMW S-BOX Shunt/Contactor support --- Software/Software.ino | 14 ++ Software/USER_SETTINGS.cpp | 3 +- Software/USER_SETTINGS.h | 4 + Software/src/battery/BATTERIES.h | 7 + Software/src/battery/BMW-SBOX.cpp | 175 ++++++++++++++++++ Software/src/battery/BMW-SBOX.h | 7 + Software/src/datalayer/datalayer.h | 10 + .../src/devboard/webserver/settings_html.cpp | 5 + Software/src/devboard/webserver/webserver.cpp | 6 + 9 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 Software/src/battery/BMW-SBOX.cpp create mode 100644 Software/src/battery/BMW-SBOX.h diff --git a/Software/Software.ino b/Software/Software.ino index df46dca04..6570102e5 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -1,3 +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" */ @@ -198,6 +199,9 @@ void setup() { setup_battery(); #ifdef EQUIPMENT_STOP_BUTTON init_equipment_stop_button(); +#endif +#ifdef CAN_SHUNT_SELECTED + setup_can_shunt(); #endif // BOOT button at runtime is used as an input for various things pinMode(0, INPUT_PULLUP); @@ -730,6 +734,10 @@ void send_can() { #ifdef CHARGER_SELECTED send_can_charger(); #endif // CHARGER_SELECTED + +#ifdef CAN_SHUNT_SELECTED + send_can_shunt(); +#endif // CAN_SHUNT_SELECTED } #ifdef DUAL_CAN @@ -1008,6 +1016,7 @@ void update_values_inverter() { #ifdef MODBUS_INVERTER_SELECTED update_modbus_registers_inverter(); #endif + #ifdef RS485_INVERTER_SELECTED update_RS485_registers_inverter(); #endif @@ -1221,6 +1230,11 @@ void receive_can(CAN_frame* rx_frame, int interface) { if (interface == can_config.charger) { #ifdef CHARGER_SELECTED receive_can_charger(*rx_frame); +#endif + } + if (interface == can_config.shunt) { +#ifdef CAN_SHUNT_SELECTED + receive_can_shunt(*rx_frame); #endif } } diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 7e916e68e..fd139182e 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -16,7 +16,8 @@ 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? + .charger = CAN_NATIVE, // (OPTIONAL) Which CAN is your charger connected to? + .shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your charger connected to? }; #ifdef WIFI diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index c846aa095..045d3ff22 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -63,6 +63,9 @@ //#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! +/* Shunt/Contactor settings */ +//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement + /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) @@ -137,6 +140,7 @@ typedef struct { 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; diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index c2c0bdac0..9f5fe8f36 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -2,6 +2,13 @@ #define BATTERIES_H #include "../../USER_SETTINGS.h" +#ifdef BMW_SBOX +#include "BMW-SBOX.h" +void receive_can_shunt(CAN_frame rx_frame); +void send_can_shunt(); +void setup_can_shunt(); +#endif + #ifdef BMW_I3_BATTERY #include "BMW-I3-BATTERY.h" #endif diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp new file mode 100644 index 000000000..5c8a7f21b --- /dev/null +++ b/Software/src/battery/BMW-SBOX.cpp @@ -0,0 +1,175 @@ +#include "../include.h" +#ifdef BMW_SBOX +#include "../datalayer/datalayer.h" +#include "BMW-SBOX.h" + + +#define MAX_ALLOWED_FAULT_TICKS 1000 +/* NOTE: modify the precharge time constant below to account for the resistance and capacitance of the target system. + * t=3RC at minimum, t=5RC ideally + */ + +#define PRECHARGE_TIME_MS 160 // Time before negative contactor engages and precharging starts +#define NEGATIVE_CONTACTOR_TIME_MS 1000 // Precharge time before precharge resistor is bypassed by positive contactor +#define POSITIVE_CONTACTOR_TIME_MS 2000 // Precharge relay lead time after positive contactor has been engaged + +enum State { DISCONNECTED, PRECHARGE, NEGATIVE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED }; +State contactorStatus = DISCONNECTED; + +unsigned long prechargeStartTime = 0; +unsigned long negativeStartTime = 0; +unsigned long positiveStartTime = 0; +unsigned long timeSpentInFaultedMode = 0; +unsigned long LastMsgTime = 0; // will store last time a 20ms CAN Message was send + +uint8_t CAN100_cnt=0; + +CAN_frame SBOX_100 = {.FD = false, + .ext_ID = false, + .DLC = 4, + .ID = 0x100, + .data = {0x55, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Byte 0: relay control, Byte 1: counter 0-E, Byte 4: CRC + +CAN_frame SBOX_300 = {.FD = false, + .ext_ID = false, + .DLC = 4, + .ID = 0x300, + .data = {0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}}; // Static frame + + +uint8_t reverse_bits(uint8_t byte) { + uint8_t reversed = 0; + for (int i = 0; i < 8; i++) { + reversed = (reversed << 1) | (byte & 1); + byte >>= 1; + } + return reversed; +} + +uint8_t calculateCRC(CAN_frame CAN) { + uint8_t crc = 0; + for (size_t i = 0; i < CAN.DLC; i++) { + uint8_t reversed_byte = reverse_bits(CAN.data.u8[i]); + crc ^= reversed_byte; + for (int j = 0; j < 8; j++) { + if (crc & 0x80) { + crc = (crc << 1) ^ 0x31; + } else { + crc <<= 1; + } + crc &= 0xFF; + } + } + crc=reverse_bits(crc); + return crc; +} + +void receive_can_shunt(CAN_frame rx_frame) { + if(rx_frame.ID ==0x200) + { + datalayer.shunt.measured_amperage_mA=((rx_frame.data.u8[2]<<24)| (rx_frame.data.u8[1]<<16)| (rx_frame.data.u8[0]<<8))/256; + } + else if(rx_frame.ID ==0x210) //Battery voltage + { + datalayer.shunt.measured_voltage_mV==((rx_frame.data.u8[2]<<24)| (rx_frame.data.u8[1]<<16)| (rx_frame.data.u8[0]<<8))/256; + } + else if(rx_frame.ID ==0x220) //SBOX output voltage + { + datalayer.shunt.measured_outvoltage_mV==((rx_frame.data.u8[2]<<24)| (rx_frame.data.u8[1]<<16)| (rx_frame.data.u8[0]<<8))/256; + } +} + +void send_can_shunt() { + // First check if we have any active errors, incase we do, turn off the battery + if (datalayer.battery.status.bms_status == FAULT) { + timeSpentInFaultedMode++; + } else { + timeSpentInFaultedMode = 0; + } + + //handle contactor control SHUTDOWN_REQUESTED + if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) { + contactorStatus = SHUTDOWN_REQUESTED; + SBOX_100.data.u8[0]=0x55; // All open + } + + if (contactorStatus == SHUTDOWN_REQUESTED) { + datalayer.shunt.contactors_engaged = false; + return; // A fault scenario latches the contactor control. It is not possible to recover without a powercycle (and investigation why fault occured) + } + + // After that, check if we are OK to start turning on the battery + if (contactorStatus == DISCONNECTED) { + datalayer.shunt.contactors_engaged = false; + SBOX_100.data.u8[0]=0x55; // All open + if (datalayer.system.status.battery_allows_contactor_closing && + datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active) { + contactorStatus = PRECHARGE; + } + } + + // In case the inverter requests contactors to open, set the state accordingly + if (contactorStatus == COMPLETED) { + //Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable) + if (!datalayer.system.status.inverter_allows_contactor_closing || datalayer.system.settings.equipment_stop_active) { + contactorStatus = DISCONNECTED; + } + } + + unsigned long currentTime = millis(); + // Handle actual state machine. This first turns on Precharge, then Negative, then Positive, and finally turns OFF precharge + switch (contactorStatus) { + case PRECHARGE: + SBOX_100.data.u8[0]=0x86; // Precharge relay only + prechargeStartTime = currentTime; + contactorStatus = NEGATIVE; + break; + + case NEGATIVE: + if (currentTime - prechargeStartTime >= PRECHARGE_TIME_MS) { + SBOX_100.data.u8[0]=0xA6; // Precharge + Negative + negativeStartTime = currentTime; + contactorStatus = POSITIVE; + } + break; + + case POSITIVE: + if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) { + SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive + positiveStartTime = currentTime; + contactorStatus = PRECHARGE_OFF; + } + break; + + case PRECHARGE_OFF: + if (currentTime - positiveStartTime >= POSITIVE_CONTACTOR_TIME_MS) { + SBOX_100.data.u8[0]=0x6A; // Negative + Positive + contactorStatus = COMPLETED; + datalayer.shunt.contactors_engaged = true; + } + break; + case COMPLETED: + SBOX_100.data.u8[0]=0x6A; // Negative + Positive + default: + break; + } + + // Send 20ms CAN Message + if (currentTime - LastMsgTime >= INTERVAL_20_MS) { + LastMsgTime = currentTime; + CAN100_cnt++; + if (CAN100_cnt>0x0E) { + CAN100_cnt=0; + } + SBOX_100.data.u8[1]=CAN100_cnt<<4|0x01; + SBOX_100.data.u8[3]=0x00; + SBOX_100.data.u8[3]=calculateCRC(SBOX_100); + transmit_can(&SBOX_100, can_config.shunt); + transmit_can(&SBOX_300, can_config.shunt); + } +} + +void setup_can_shunt() { + datalayer.system.info.shunt_protocol[63] = 'BMW SBOX\0'; +} +#endif diff --git a/Software/src/battery/BMW-SBOX.h b/Software/src/battery/BMW-SBOX.h new file mode 100644 index 000000000..980d9f554 --- /dev/null +++ b/Software/src/battery/BMW-SBOX.h @@ -0,0 +1,7 @@ +#ifndef BMW_SBOX_CONTROL_H +#define BMW_SBOX_CONTROL_H +#include "../include.h" +#define CAN_SHUNT_SELECTED +void transmit_can(CAN_frame* tx_frame, int interface); + +#endif diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index e6de68ce0..453b03401 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -124,6 +124,14 @@ typedef struct { uint16_t measured_voltage_dV = 0; /** measured amperage in deciAmperes. 300 = 30.0 A */ uint16_t measured_amperage_dA = 0; + /** measured battery voltage in mV (S-BOX) **/ + uint32_t measured_voltage_mV = 0; + /** measured output voltage in mV (eg. S-BOX) **/ + uint32_t measured_outvoltage_mV = 0; + /** measured amperage in mA (eg. S-BOX) **/ + uint32_t measured_amperage_mA = 0; + /** True if the contactor controlled by battery-emulator is closed */ + bool contactors_engaged = false; } DATALAYER_SHUNT_TYPE; typedef struct { @@ -131,6 +139,8 @@ typedef struct { char battery_protocol[64] = {0}; /** array with type of inverter used, for displaying on webserver */ char inverter_protocol[64] = {0}; + /** array with type of battery used, for displaying on webserver */ + char shunt_protocol[64] = {0}; /** array with incoming CAN messages, for displaying on webserver */ char logged_can_messages[15000] = {0}; size_t logged_can_messages_offset = 0; diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 484e50210..90c83837f 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -41,6 +41,11 @@ String settings_processor(const String& var) { content += "

Inverter interface: RS485

"; #endif +#ifdef CAN_SHUNT_SELECTED + content += "

Shunt Interface: " + + String(getCANInterfaceName(can_config.shunt)) + "

"; +#endif //CAN_SHUNT_SELECTED + // Close the block content += "
"; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 227dee8c4..14ed3c924 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -552,6 +552,12 @@ String processor(const String& var) { } content += ""; +#ifdef CAN_SHUNT_SELECTED + content += "

Shunt protocol: "; + content += datalayer.system.info.shunt_protocol; + content += "

"; +#endif + #if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER content += "

Charger protocol: "; #ifdef CHEVYVOLT_CHARGER From 3e781999c07feee9554b614ee7bab681c457bddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 12 Dec 2024 12:02:32 +0200 Subject: [PATCH 039/225] Update scaling on real SOC There was one decimal too much --- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 5ad4220fb..eaa01bae9 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -118,7 +118,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.real_soc = estimateSOC(datalayer.battery.status.voltage_dV); SOC_method = ESTIMATED; #else // Pack is not crashed, we can use periodically transmitted SOC - datalayer.battery.status.real_soc = battery_highprecision_SOC * 100; + datalayer.battery.status.real_soc = battery_highprecision_SOC * 10; SOC_method = MEASURED; #endif From 62778628e5385823b2ee6d52b218f0d86d142a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 12 Dec 2024 22:36:34 +0200 Subject: [PATCH 040/225] Fix so PWM precharge works --- Software/Software.ino | 61 ++++++++++++++++++++-------------------- Software/USER_SETTINGS.h | 2 ++ 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index df46dca04..fa13d5cd8 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -115,7 +115,7 @@ MyTimer check_pause_2s(INTERVAL_2_S); // Contactor parameters #ifdef CONTACTOR_CONTROL -enum State { DISCONNECTED, PRECHARGE, NEGATIVE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED }; +enum State { DISCONNECTED, START_PRECHARGE, PRECHARGE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED }; State contactorStatus = DISCONNECTED; #define ON 1 @@ -126,30 +126,29 @@ State contactorStatus = DISCONNECTED; #define ON 0 #undef OFF #define OFF 1 -#endif +#endif //NC_CONTACTORS #define MAX_ALLOWED_FAULT_TICKS 1000 -/* NOTE: modify the precharge time constant below to account for the resistance and capacitance of the target system. - * t=3RC at minimum, t=5RC ideally - */ -#define PRECHARGE_TIME_MS 160 -#define NEGATIVE_CONTACTOR_TIME_MS 1000 -#define POSITIVE_CONTACTOR_TIME_MS 2000 +#define NEGATIVE_CONTACTOR_TIME_MS \ + 500 // Time after negative contactor is turned on, to start precharge (not actual precharge time!) +#define PRECHARGE_COMPLETED_TIME_MS \ + 1000 // Time after precharge completed, that we should turn off the precharge resistor (and economize if PWM is on) #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 #define PWM_ON_DUTY 1023 -#define POSITIVE_PWM_Ch 0 -#define NEGATIVE_PWM_Ch 1 +#define PWM_Positive_Channel 0 +#define PWM_Negative_Channel 1 unsigned long prechargeStartTime = 0; unsigned long negativeStartTime = 0; +unsigned long prechargeCompletedTime = 0; unsigned long timeSpentInFaultedMode = 0; #endif -void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFFFFFFFF) { +void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) { #ifdef PWM_CONTACTOR_CONTROL - if (pwm_freq != 0xFFFFFFFFFF) { + if (pwm_freq != 0xFFFF) { ledcWrite(pin, pwm_freq); return; } @@ -518,23 +517,22 @@ void init_contactors() { // Init contactor pins #ifdef CONTACTOR_CONTROL #ifdef PWM_CONTACTOR_CONTROL - ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, - POSITIVE_PWM_Ch); // Setup PWM Channel Frequency and Resolution - ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, - NEGATIVE_PWM_Ch); // Setup PWM Channel Frequency and Resolution - ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY); // Set Positive PWM to 0% - ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY); // Set Negative PWM to 0% -#else //Normal CONTACTOR_CONTROL + // Setup PWM Channel Frequency and Resolution + ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Positive_Channel); + ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Negative_Channel); + // Set all pins OFF (0% PWM) + ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY); + ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY); +#else //Normal CONTACTOR_CONTROL pinMode(POSITIVE_CONTACTOR_PIN, OUTPUT); set(POSITIVE_CONTACTOR_PIN, OFF); pinMode(NEGATIVE_CONTACTOR_PIN, OUTPUT); set(NEGATIVE_CONTACTOR_PIN, OFF); -#endif +#endif // Precharge never has PWM regardless of setting pinMode(PRECHARGE_PIN, OUTPUT); set(PRECHARGE_PIN, OFF); #endif //CONTACTOR_CONTROL #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY - pinMode(SECOND_POSITIVE_CONTACTOR_PIN, OUTPUT); set(SECOND_POSITIVE_CONTACTOR_PIN, OFF); pinMode(SECOND_NEGATIVE_CONTACTOR_PIN, OUTPUT); @@ -814,7 +812,7 @@ void handle_contactors() { if (datalayer.system.status.battery_allows_contactor_closing && datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active) { - contactorStatus = PRECHARGE; + contactorStatus = START_PRECHARGE; } } @@ -829,31 +827,32 @@ void handle_contactors() { } unsigned long currentTime = millis(); - // Handle actual state machine. This first turns on Precharge, then Negative, then Positive, and finally turns OFF precharge + // Handle actual state machine. This first turns on Negative, then Precharge, then Positive, and finally turns OFF precharge switch (contactorStatus) { - case PRECHARGE: - set(PRECHARGE_PIN, ON); + case START_PRECHARGE: + set(NEGATIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY); prechargeStartTime = currentTime; - contactorStatus = NEGATIVE; + contactorStatus = PRECHARGE; break; - case NEGATIVE: - if (currentTime - prechargeStartTime >= PRECHARGE_TIME_MS) { - set(NEGATIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY); + case PRECHARGE: + if (currentTime - prechargeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) { + set(PRECHARGE_PIN, ON); negativeStartTime = currentTime; contactorStatus = POSITIVE; } break; case POSITIVE: - if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) { + if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) { set(POSITIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY); + prechargeCompletedTime = currentTime; contactorStatus = PRECHARGE_OFF; } break; case PRECHARGE_OFF: - if (currentTime - negativeStartTime >= POSITIVE_CONTACTOR_TIME_MS) { + if (currentTime - prechargeCompletedTime >= PRECHARGE_COMPLETED_TIME_MS) { set(PRECHARGE_PIN, OFF); set(NEGATIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY); set(POSITIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY); diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index c846aa095..3b4b92d43 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -58,6 +58,8 @@ //#define HW_3LB /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ +#define PRECHARGE_TIME_MS \ + 500 //Duration of precharge in milliseconds. Modify to account for the resistance and capacitance of the 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. From 30a6eef3269c169dacbe44edf57f603ef3ef24e8 Mon Sep 17 00:00:00 2001 From: lenvm Date: Thu, 12 Dec 2024 21:56:52 +0100 Subject: [PATCH 041/225] sort battery and inverter options lexicographically, and add missing options to workflows --- .github/workflows/compile-all-batteries.yml | 3 ++- .github/workflows/compile-all-combinations.yml | 16 +++++++++++++++- .github/workflows/compile-all-inverters.yml | 13 ++++--------- Software/USER_SETTINGS.h | 14 +++++++------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index 7f95c73de..49d083a0b 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -40,8 +40,8 @@ jobs: - CHADEMO_BATTERY - IMIEV_CZERO_ION_BATTERY - JAGUAR_IPACE_BATTERY - - KIA_HYUNDAI_64_BATTERY - KIA_E_GMP_BATTERY + - KIA_HYUNDAI_64_BATTERY - KIA_HYUNDAI_HYBRID_BATTERY - MEB_BATTERY - MG_5_BATTERY @@ -55,6 +55,7 @@ jobs: - RENAULT_ZOE_GEN2_BATTERY - SANTA_FE_PHEV_BATTERY - TESLA_MODEL_3Y_BATTERY + - TESLA_MODEL_SX_BATTERY - VOLVO_SPA_BATTERY - TEST_FAKE_BATTERY - SERIAL_LINK_RECEIVER diff --git a/.github/workflows/compile-all-combinations.yml b/.github/workflows/compile-all-combinations.yml index c194e97a3..91df0bbbb 100644 --- a/.github/workflows/compile-all-combinations.yml +++ b/.github/workflows/compile-all-combinations.yml @@ -37,29 +37,43 @@ jobs: # These are the batteries for which the code will be compiled. battery: - BMW_I3_BATTERY + - BMW_IX_BATTERY - BYD_ATTO_3_BATTERY + - CELLPOWER_BMS - CHADEMO_BATTERY - IMIEV_CZERO_ION_BATTERY + - JAGUAR_IPACE_BATTERY + - KIA_E_GMP_BATTERY - KIA_HYUNDAI_64_BATTERY - KIA_HYUNDAI_HYBRID_BATTERY + - MEB_BATTERY + - MG_5_BATTERY - NISSAN_LEAF_BATTERY - PYLON_BATTERY - RJXZS_BMS + - RANGE_ROVER_PHEV_BATTERY - RENAULT_KANGOO_BATTERY + - RENAULT_TWIZY_BATTERY - RENAULT_ZOE_GEN1_BATTERY - RENAULT_ZOE_GEN2_BATTERY + - SANTA_FE_PHEV_BATTERY - TESLA_MODEL_3Y_BATTERY + - TESLA_MODEL_SX_BATTERY - VOLVO_SPA_BATTERY - TEST_FAKE_BATTERY # These are the emulated inverter communication protocols for which the code will be compiled. inverter: + - AFORE_CAN - BYD_CAN - BYD_KOSTAL_RS485 - - BYD_SMA - BYD_MODBUS + - BYD_SMA - FOXESS_CAN - PYLON_CAN + - PYLON_LV_CAN + - SCHNEIDER_CAN - SMA_CAN + - SMA_LV_CAN - SMA_TRIPOWER_CAN - SOFAR_CAN - SOLAX_CAN diff --git a/.github/workflows/compile-all-inverters.yml b/.github/workflows/compile-all-inverters.yml index af2ce3794..fb4afbf3d 100644 --- a/.github/workflows/compile-all-inverters.yml +++ b/.github/workflows/compile-all-inverters.yml @@ -33,30 +33,25 @@ jobs: #- esp32:esp32:esp32s3 # These are the batteries for which the code will be compiled. battery: -# - BMW_I3_BATTERY -# - CHADEMO_BATTERY -# - IMIEV_CZERO_ION_BATTERY -# - KIA_HYUNDAI_64_BATTERY - NISSAN_LEAF_BATTERY -# - RENAULT_ZOE_BATTERY -# - TESLA_MODEL_3Y_BATTERY # These are the emulated inverter communication protocols for which the code will be compiled. inverter: - AFORE_CAN - BYD_CAN - BYD_KOSTAL_RS485 - - BYD_SMA - BYD_MODBUS + - BYD_SMA - FOXESS_CAN - - PYLON_LV_CAN - PYLON_CAN + - PYLON_LV_CAN - SCHNEIDER_CAN - SMA_CAN + - SMA_LV_CAN - SMA_TRIPOWER_CAN - SOFAR_CAN - SOLAX_CAN - SERIAL_LINK_TRANSMITTER - - NISSANLEAF_CHARGER # Last element is not an inverter, but good to also test if charger compiles + - NISSANLEAF_CHARGER # Last element is not an inverter, but good to also test if the charger compiles # This is the platform GitHub will use to run our workflow. runs-on: ubuntu-latest diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index c846aa095..fafc24922 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -16,8 +16,8 @@ //#define CHADEMO_BATTERY //NOTE: inherently enables CONTACTOR_CONTROL below //#define IMIEV_CZERO_ION_BATTERY //#define JAGUAR_IPACE_BATTERY -//#define KIA_HYUNDAI_64_BATTERY //#define KIA_E_GMP_BATTERY +//#define KIA_HYUNDAI_64_BATTERY //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MEB_BATTERY //#define MG_5_BATTERY @@ -30,18 +30,18 @@ //#define RENAULT_ZOE_GEN1_BATTERY //#define RENAULT_ZOE_GEN2_BATTERY //#define SANTA_FE_PHEV_BATTERY -//#define TESLA_MODEL_SX_BATTERY //#define TESLA_MODEL_3Y_BATTERY +//#define TESLA_MODEL_SX_BATTERY //#define VOLVO_SPA_BATTERY //#define TEST_FAKE_BATTERY //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires DUAL_CAN setup) /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/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_SMA //Enable this line to emulate a SMA compatible "BYD Battery-Box HVS 10.2KW battery" over CAN bus -//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU -//#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 +//#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_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 BYD_SMA //Enable this line to emulate a SMA compatible "BYD Battery-Box HVS 10.2KW battery" over CAN bus //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 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 From 3a4ea7066617a6f16b352b0e069efe99ef493c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 12 Dec 2024 23:48:21 +0200 Subject: [PATCH 042/225] Make webserver work with PWM --- Software/src/devboard/webserver/webserver.cpp | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 227dee8c4..cfdf29823 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -685,7 +685,7 @@ String processor(const String& var) { content += "

Power status: " + String(get_emulator_pause_status().c_str()) + "

"; #ifdef CONTACTOR_CONTROL - content += "

Contactors controlled by Battery-Emulator: "; + content += "

Contactors controlled by emulator, state: "; if (datalayer.system.status.contactors_engaged) { content += "ON"; } else { @@ -693,13 +693,21 @@ String processor(const String& var) { } content += "

"; - content += "

Pre Charge: "; - if (digitalRead(PRECHARGE_PIN) == HIGH) { - content += ""; + content += "

Precharge: ("; + content += PRECHARGE_TIME_MS; + content += " ms) Cont. Neg.: "; +#ifdef PWM_CONTACTOR_CONTROL + if (datalayer.system.status.contactors_engaged) { + content += "Economized"; + content += " Cont. Pos.: "; + content += "Economized"; } else { content += ""; + content += " Cont. Pos.: "; + content += ""; } - content += " Cont. Neg.: "; + +#else // No PWM_CONTACTOR_CONTROL , we can read the pin and see feedback. Helpful if channel overloaded if (digitalRead(NEGATIVE_CONTACTOR_PIN) == HIGH) { content += ""; } else { @@ -712,6 +720,7 @@ String processor(const String& var) { } else { content += ""; } +#endif //no PWM_CONTACTOR_CONTROL content += "

"; #endif @@ -816,7 +825,7 @@ String processor(const String& var) { content += "

Power status: " + String(get_emulator_pause_status().c_str()) + "

"; #ifdef CONTACTOR_CONTROL - content += "

Contactors controlled by Battery-Emulator: "; + content += "

Contactors controlled by emulator, state: "; if (datalayer.system.status.contactors_battery2_engaged) { content += "ON"; } else { @@ -824,13 +833,19 @@ String processor(const String& var) { } content += "

"; #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY - content += "

Pre Charge: "; - if (digitalRead(SECOND_PRECHARGE_PIN) == HIGH) { - content += ""; + content += "

Cont. Neg.: "; +#ifdef PWM_CONTACTOR_CONTROL + if (datalayer.system.status.contactors_battery2_engaged) { + content += "Economized"; + content += " Cont. Pos.: "; + content += "Economized"; } else { content += ""; + content += " Cont. Pos.: "; + content += ""; } - content += " Cont. Neg.: "; + +#else // No PWM_CONTACTOR_CONTROL , we can read the pin and see feedback. Helpful if channel overloaded if (digitalRead(SECOND_NEGATIVE_CONTACTOR_PIN) == HIGH) { content += ""; } else { @@ -843,6 +858,7 @@ String processor(const String& var) { } else { content += ""; } +#endif //no PWM_CONTACTOR_CONTROL content += "

"; #endif // CONTACTOR_CONTROL_DOUBLE_BATTERY #endif // CONTACTOR_CONTROL From 602fc6dc921968f0630d40d8a946694f8aba4711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 13 Dec 2024 23:12:19 +0200 Subject: [PATCH 043/225] Update comments to make them more clear --- Software/Software.ino | 2 +- Software/USER_SETTINGS.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index fa13d5cd8..d7efe9c16 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -132,7 +132,7 @@ State contactorStatus = DISCONNECTED; #define NEGATIVE_CONTACTOR_TIME_MS \ 500 // Time after negative contactor is turned on, to start precharge (not actual precharge time!) #define PRECHARGE_COMPLETED_TIME_MS \ - 1000 // Time after precharge completed, that we should turn off the precharge resistor (and economize if PWM is on) + 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 diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 3b4b92d43..a60545a5b 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -58,8 +58,7 @@ //#define HW_3LB /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ -#define PRECHARGE_TIME_MS \ - 500 //Duration of precharge in milliseconds. Modify to account for the resistance and capacitance of the inverter (See wiki for more info) +#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. From d4f04cea6ae378027ba286189e835ebf82c8ae24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 14 Dec 2024 15:29:20 +0200 Subject: [PATCH 044/225] Update Software.ino Update tag name for release --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index d7efe9c16..00230fc8d 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -53,7 +53,7 @@ Preferences settings; // Store user settings // The current software version, shown on webserver -const char* version_number = "8.0.dev"; +const char* version_number = "7.9.1"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From c7e0d968bb794c225bf061030ede7cdf6278371b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 14 Dec 2024 15:39:41 +0200 Subject: [PATCH 045/225] Update Software.ino Signal development version --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index 00230fc8d..d7efe9c16 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -53,7 +53,7 @@ Preferences settings; // Store user settings // The current software version, shown on webserver -const char* version_number = "7.9.1"; +const char* version_number = "8.0.dev"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From 3ac8d62f9201e21eaee56bf526117834f8bbda33 Mon Sep 17 00:00:00 2001 From: rha Date: Sun, 15 Dec 2024 11:14:48 +0200 Subject: [PATCH 046/225] relay control --- Software/src/battery/BMW-SBOX.cpp | 4 ++-- Software/src/battery/BMW-SBOX.h | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp index 5c8a7f21b..2712a9c17 100644 --- a/Software/src/battery/BMW-SBOX.cpp +++ b/Software/src/battery/BMW-SBOX.cpp @@ -103,7 +103,7 @@ void send_can_shunt() { datalayer.shunt.contactors_engaged = false; SBOX_100.data.u8[0]=0x55; // All open if (datalayer.system.status.battery_allows_contactor_closing && - datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active) { + datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active && ( measured_voltage_mV => MINIMUM_INPUT_VOLTAGE*1000)) { contactorStatus = PRECHARGE; } } @@ -134,7 +134,7 @@ void send_can_shunt() { break; case POSITIVE: - if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) { + if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS && (measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_RATIO < measured_outvoltage_mV)) { SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive positiveStartTime = currentTime; contactorStatus = PRECHARGE_OFF; diff --git a/Software/src/battery/BMW-SBOX.h b/Software/src/battery/BMW-SBOX.h index 980d9f554..293f16859 100644 --- a/Software/src/battery/BMW-SBOX.h +++ b/Software/src/battery/BMW-SBOX.h @@ -4,4 +4,11 @@ #define CAN_SHUNT_SELECTED void transmit_can(CAN_frame* tx_frame, int interface); +/** Minimum input voltage required to enable relay control **/ +#define MINIMUM_INPUT_VOLTAGE 250 + +/** Maximum allowable percentage of input voltage across the precharge resistor to close the positive relay **/ +#define MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT 96 + + #endif From 45586a2284fc84782644bb0e2315c64bf70d8400 Mon Sep 17 00:00:00 2001 From: rha Date: Sun, 15 Dec 2024 11:47:24 +0200 Subject: [PATCH 047/225] precharge boolean --- Software/USER_SETTINGS.h | 6 +++--- Software/src/battery/BMW-SBOX.cpp | 2 ++ Software/src/datalayer/datalayer.h | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 045d3ff22..73e534e1d 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -33,7 +33,7 @@ //#define TESLA_MODEL_SX_BATTERY //#define TESLA_MODEL_3Y_BATTERY //#define VOLVO_SPA_BATTERY -//#define TEST_FAKE_BATTERY +#define TEST_FAKE_BATTERY //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires DUAL_CAN setup) /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ @@ -64,12 +64,12 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! /* Shunt/Contactor settings */ -//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement +#define BMW_SBOX // SBOX relay control & battery current/voltage measurement /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) -//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting +//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to< be seated before starting //#define DUAL_CAN //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 //DUAL_CAN option, what is your MCP2515 add-on boards crystal frequency? //#define CAN_FD //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp index 2712a9c17..a88352f9b 100644 --- a/Software/src/battery/BMW-SBOX.cpp +++ b/Software/src/battery/BMW-SBOX.cpp @@ -130,6 +130,7 @@ void send_can_shunt() { SBOX_100.data.u8[0]=0xA6; // Precharge + Negative negativeStartTime = currentTime; contactorStatus = POSITIVE; + datalayer.shunt.precharging = true; } break; @@ -138,6 +139,7 @@ void send_can_shunt() { SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive positiveStartTime = currentTime; contactorStatus = PRECHARGE_OFF; + datalayer.shunt.precharging = false; } break; diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 453b03401..83ce189ef 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -130,6 +130,8 @@ typedef struct { uint32_t measured_outvoltage_mV = 0; /** measured amperage in mA (eg. S-BOX) **/ uint32_t measured_amperage_mA = 0; + /** True if contactors are precharging state */ + bool precharging = false; /** True if the contactor controlled by battery-emulator is closed */ bool contactors_engaged = false; } DATALAYER_SHUNT_TYPE; From 40d2d231403a698cf8fedb6b4fe8d6057a0b3683 Mon Sep 17 00:00:00 2001 From: rha Date: Sun, 15 Dec 2024 12:07:51 +0200 Subject: [PATCH 048/225] . --- Software/src/battery/BMW-SBOX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp index a88352f9b..85c9391be 100644 --- a/Software/src/battery/BMW-SBOX.cpp +++ b/Software/src/battery/BMW-SBOX.cpp @@ -103,7 +103,7 @@ void send_can_shunt() { datalayer.shunt.contactors_engaged = false; SBOX_100.data.u8[0]=0x55; // All open if (datalayer.system.status.battery_allows_contactor_closing && - datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active && ( measured_voltage_mV => MINIMUM_INPUT_VOLTAGE*1000)) { + datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active && ( datalayer.shunt.measured_voltage_mV => MINIMUM_INPUT_VOLTAGE*1000)) { contactorStatus = PRECHARGE; } } @@ -135,7 +135,7 @@ void send_can_shunt() { break; case POSITIVE: - if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS && (measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_RATIO < measured_outvoltage_mV)) { + if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS && (measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < dataalyer.shunt.measured_outvoltage_mV)) { SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive positiveStartTime = currentTime; contactorStatus = PRECHARGE_OFF; From 6ad5c41b0448f022422d933835395f4a326c9315 Mon Sep 17 00:00:00 2001 From: rha Date: Sun, 15 Dec 2024 12:12:45 +0200 Subject: [PATCH 049/225] . --- Software/src/battery/BMW-SBOX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp index 85c9391be..bb8ff0c1e 100644 --- a/Software/src/battery/BMW-SBOX.cpp +++ b/Software/src/battery/BMW-SBOX.cpp @@ -135,7 +135,7 @@ void send_can_shunt() { break; case POSITIVE: - if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS && (measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < dataalyer.shunt.measured_outvoltage_mV)) { + if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS && (datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < datalalyer.shunt.measured_outvoltage_mV)) { SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive positiveStartTime = currentTime; contactorStatus = PRECHARGE_OFF; From e71ca81feb688f4124200005d7ed6cd681fc919d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 15 Dec 2024 14:07:58 +0200 Subject: [PATCH 050/225] Add startup delay for contactors (#673) --- Software/Software.ino | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Software/Software.ino b/Software/Software.ino index d7efe9c16..6696ee029 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -827,6 +827,13 @@ void handle_contactors() { } unsigned long currentTime = millis(); + + if (currentTime < INTERVAL_10_S) { + // Skip running the state machine before system has started up. + // Gives the system some time to detect any faults from battery before blindly just engaging the contactors + return; + } + // Handle actual state machine. This first turns on Negative, then Precharge, then Positive, and finally turns OFF precharge switch (contactorStatus) { case START_PRECHARGE: From fb4d81b5557943edccbf04e48adbc8e18d8606b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 15 Dec 2024 14:10:12 +0200 Subject: [PATCH 051/225] Add messages needed for Solax X3 Ultra (#656) Ensures SOC is available in the Solax Ultra App --- Software/src/inverter/SOLAX-CAN.cpp | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp index 9bef56ec8..da036517e 100644 --- a/Software/src/inverter/SOLAX-CAN.cpp +++ b/Software/src/inverter/SOLAX-CAN.cpp @@ -64,6 +64,31 @@ CAN_frame SOLAX_1879 = {.FD = false, .DLC = 8, .ID = 0x1879, .data = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; +CAN_frame SOLAX_187E = {.FD = false, //Needed for Ultra + .ext_ID = true, + .DLC = 8, + .ID = 0x187E, + .data = {0x0, 0x2D, 0x0, 0x0, 0x0, 0x5F, 0x0, 0x0}}; +CAN_frame SOLAX_187D = {.FD = false, //Needed for Ultra + .ext_ID = true, + .DLC = 8, + .ID = 0x187D, + .data = {0x8B, 0x01, 0x0, 0x0, 0x8B, 0x1, 0x0, 0x0}}; +CAN_frame SOLAX_187C = {.FD = false, //Needed for Ultra + .ext_ID = true, + .DLC = 8, + .ID = 0x187C, + .data = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; +CAN_frame SOLAX_187B = {.FD = false, //Needed for Ultra + .ext_ID = true, + .DLC = 8, + .ID = 0x187B, + .data = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; +CAN_frame SOLAX_187A = {.FD = false, //Needed for Ultra + .ext_ID = true, + .DLC = 8, + .ID = 0x187A, + .data = {0x01, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; CAN_frame SOLAX_1881 = {.FD = false, .ext_ID = true, .DLC = 8, @@ -256,5 +281,12 @@ void setup_inverter(void) { // Performs one time setup at startup strncpy(datalayer.system.info.inverter_protocol, "SolaX Triple Power LFP over CAN bus", 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first + + // Sending these messages once towards the inverter makes SOC% work on the Ultra variant + transmit_can(&SOLAX_187E, can_config.inverter); + transmit_can(&SOLAX_187D, can_config.inverter); + transmit_can(&SOLAX_187C, can_config.inverter); + transmit_can(&SOLAX_187B, can_config.inverter); + transmit_can(&SOLAX_187A, can_config.inverter); } #endif From b35635676fe8e3860604a0b754a8464cb7d4038d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 15 Dec 2024 14:26:06 +0200 Subject: [PATCH 052/225] Add double battery support for Santa Fe PHEV (#596) --- .../src/battery/SANTA-FE-PHEV-BATTERY.cpp | 328 ++++++++++++++++-- 1 file changed, 299 insertions(+), 29 deletions(-) diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index e6f27accd..766a90941 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -18,6 +18,8 @@ static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send static unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was send static uint8_t poll_data_pid = 0; +static uint8_t counter_200 = 0; +static uint8_t checksum_200 = 0; static uint16_t SOC_Display = 0; static uint16_t batterySOH = 100; @@ -32,11 +34,27 @@ static int16_t leadAcidBatteryVoltage = 120; static int8_t temperatureMax = 0; static int8_t temperatureMin = 0; static int16_t batteryAmps = 0; -static uint8_t counter_200 = 0; -static uint8_t checksum_200 = 0; static uint8_t StatusBattery = 0; static uint16_t cellvoltages_mv[96]; +#ifdef DOUBLE_BATTERY +static uint16_t battery2_SOC_Display = 0; +static uint16_t battery2_SOH = 100; +static uint16_t battery2_CellVoltMax_mV = 3700; +static uint16_t battery2_CellVoltMin_mV = 3700; +static uint8_t battery2_CellVmaxNo = 0; +static uint8_t battery2_CellVminNo = 0; +static uint16_t battery2_allowedDischargePower = 0; +static uint16_t battery2_allowedChargePower = 0; +static uint16_t battery2_batteryVoltage = 0; +static int16_t battery2_leadAcidBatteryVoltage = 120; +static int8_t battery2_temperatureMax = 0; +static int8_t battery2_temperatureMin = 0; +static int16_t battery2_batteryAmps = 0; +static uint8_t battery2_StatusBattery = 0; +static uint16_t battery2_cellvoltages_mv[96]; +#endif //DOUBLE_BATTERY + CAN_frame SANTAFE_200 = {.FD = false, .ext_ID = false, .DLC = 8, @@ -96,10 +114,6 @@ void update_values_battery() { //This function maps all the values fetched via if (leadAcidBatteryVoltage < 110) { set_event(EVENT_12V_LOW, leadAcidBatteryVoltage); } - -#ifdef DEBUG_VIA_USB - -#endif } void receive_can_battery(CAN_frame rx_frame) { @@ -338,10 +352,13 @@ void send_can_battery() { SANTAFE_200.data.u8[7] = checksum_200; transmit_can(&SANTAFE_200, can_config.battery); - transmit_can(&SANTAFE_2A1, can_config.battery); - transmit_can(&SANTAFE_2F0, can_config.battery); +#ifdef DOUBLE_BATTERY + transmit_can(&SANTAFE_200, can_config.battery_double); + transmit_can(&SANTAFE_2A1, can_config.battery_double); + transmit_can(&SANTAFE_2F0, can_config.battery_double); +#endif //DOUBLE_BATTERY counter_200++; if (counter_200 > 0xF) { @@ -354,35 +371,278 @@ void send_can_battery() { previousMillis100 = currentMillis; transmit_can(&SANTAFE_523, can_config.battery); +#ifdef DOUBLE_BATTERY + transmit_can(&SANTAFE_523, can_config.battery_double); +#endif //DOUBLE_BATTERY } // Send 500ms CAN Message if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { previousMillis500 = currentMillis; - //PID data is polled after last message sent from battery: - if (poll_data_pid >= 5) { //polling one of 5 PIDs at 100ms, resolution = 500ms - poll_data_pid = 0; - } - poll_data_pid++; - if (poll_data_pid == 1) { - SANTAFE_7E4_poll.data.u8[3] = 0x01; - transmit_can(&SANTAFE_7E4_poll, can_config.battery); - } else if (poll_data_pid == 2) { - SANTAFE_7E4_poll.data.u8[3] = 0x02; - transmit_can(&SANTAFE_7E4_poll, can_config.battery); - } else if (poll_data_pid == 3) { - SANTAFE_7E4_poll.data.u8[3] = 0x03; - transmit_can(&SANTAFE_7E4_poll, can_config.battery); - } else if (poll_data_pid == 4) { - SANTAFE_7E4_poll.data.u8[3] = 0x04; - transmit_can(&SANTAFE_7E4_poll, can_config.battery); - } else if (poll_data_pid == 5) { - SANTAFE_7E4_poll.data.u8[3] = 0x05; - transmit_can(&SANTAFE_7E4_poll, can_config.battery); - } + // PID data is polled after last message sent from battery: + poll_data_pid = (poll_data_pid % 5) + 1; + SANTAFE_7E4_poll.data.u8[3] = (uint8_t)poll_data_pid; + transmit_can(&SANTAFE_7E4_poll, can_config.battery); +#ifdef DOUBLE_BATTERY + transmit_can(&SANTAFE_7E4_poll, can_config.battery_double); +#endif //DOUBLE_BATTERY + } +} + +#ifdef DOUBLE_BATTERY +void update_values_battery2() { //This function maps all the values fetched via CAN to the correct parameters used for modbus + + datalayer.battery2.status.real_soc = (battery2_SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00 + + datalayer.battery2.status.soh_pptt = (battery2_SOH * 100); //Increase decimals from 100% -> 100.00% + + datalayer.battery2.status.voltage_dV = battery2_batteryVoltage; + + datalayer.battery2.status.current_dA = -battery2_batteryAmps; + + datalayer.battery2.status.remaining_capacity_Wh = static_cast( + (static_cast(datalayer.battery2.status.real_soc) / 10000) * datalayer.battery2.info.total_capacity_Wh); + + datalayer.battery2.status.max_discharge_power_W = battery2_allowedDischargePower * 10; + + datalayer.battery2.status.max_charge_power_W = battery2_allowedChargePower * 10; + + //Power in watts, Negative = charging batt + datalayer.battery2.status.active_power_W = + ((datalayer.battery2.status.voltage_dV * datalayer.battery2.status.current_dA) / 100); + + datalayer.battery2.status.cell_max_voltage_mV = battery2_CellVoltMax_mV; + + datalayer.battery2.status.cell_min_voltage_mV = battery2_CellVoltMin_mV; + + datalayer.battery2.status.temperature_min_dC = battery2_temperatureMin * 10; //Increase decimals, 17C -> 17.0C + + datalayer.battery2.status.temperature_max_dC = battery2_temperatureMax * 10; //Increase decimals, 18C -> 18.0C + + if (battery2_leadAcidBatteryVoltage < 110) { + set_event(EVENT_12V_LOW, battery2_leadAcidBatteryVoltage); + } +} + +void receive_can_battery2(CAN_frame rx_frame) { + switch (rx_frame.ID) { + case 0x1FF: + datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery2_StatusBattery = (rx_frame.data.u8[0] & 0x0F); + break; + case 0x4D5: + break; + case 0x4DD: + break; + case 0x4DE: + datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x4E0: + break; + case 0x542: + datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery2_SOC_Display = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]) / 2; + break; + case 0x588: + datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery2_batteryVoltage = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]); + break; + case 0x597: + break; + case 0x5A6: + break; + case 0x5A7: + break; + case 0x5AD: + datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery2_batteryAmps = (rx_frame.data.u8[3] << 8) + rx_frame.data.u8[2]; + break; + case 0x5AE: + break; + case 0x5F1: + break; + case 0x620: + datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery2_leadAcidBatteryVoltage = rx_frame.data.u8[1]; + battery2_temperatureMin = rx_frame.data.u8[6]; //Lowest temp in battery + battery2_temperatureMax = rx_frame.data.u8[7]; //Highest temp in battery + break; + case 0x670: + datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery2_allowedChargePower = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + battery2_allowedDischargePower = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); + break; + case 0x671: + datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x7EC: //Data From polled PID group, BigEndian + switch (rx_frame.data.u8[0]) { + case 0x10: //"PID Header" + if (rx_frame.data.u8[4] == poll_data_pid) { + transmit_can(&SANTAFE_7E4_ack, + can_config.battery_double); //Send ack to BMS if the same frame is sent as polled + } + break; + case 0x21: //First frame in PID group + if (poll_data_pid == 1) { + } else if (poll_data_pid == 2) { + battery2_cellvoltages_mv[0] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[1] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[2] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[3] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[4] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[5] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 3) { + battery2_cellvoltages_mv[32] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[33] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[34] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[35] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[36] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[37] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 4) { + battery2_cellvoltages_mv[64] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[65] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[66] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[67] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[68] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[69] = (rx_frame.data.u8[7] * 20); + } + break; + case 0x22: //Second datarow in PID group + if (poll_data_pid == 2) { + battery2_cellvoltages_mv[6] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[7] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[8] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[9] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[10] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[11] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[12] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 3) { + battery2_cellvoltages_mv[38] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[39] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[40] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[41] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[42] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[43] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[44] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 4) { + battery2_cellvoltages_mv[70] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[71] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[72] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[73] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[74] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[75] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[76] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 6) { + } + break; + case 0x23: //Third datarow in PID group + if (poll_data_pid == 1) { + battery2_CellVoltMax_mV = (rx_frame.data.u8[7] * 20); //(volts *50) *20 =mV + } else if (poll_data_pid == 2) { + battery2_cellvoltages_mv[13] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[14] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[15] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[16] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[17] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[18] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[19] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 3) { + battery2_cellvoltages_mv[45] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[46] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[47] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[48] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[49] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[50] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[51] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 4) { + battery2_cellvoltages_mv[77] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[78] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[79] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[80] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[81] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[82] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[83] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 5) { + if (rx_frame.data.u8[6] > 0) { + battery2_SOH = rx_frame.data.u8[6]; + } + if (battery2_SOH > 100) { + battery2_SOH = 100; + } + } + break; + case 0x24: //Fourth datarow in PID group + if (poll_data_pid == 1) { + battery2_CellVmaxNo = rx_frame.data.u8[1]; + battery2_CellVminNo = rx_frame.data.u8[3]; + CellVoltMin_mV = (rx_frame.data.u8[2] * 20); //(volts *50) *20 =mV + } else if (poll_data_pid == 2) { + battery2_cellvoltages_mv[20] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[21] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[22] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[23] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[24] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[25] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[26] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 3) { + battery2_cellvoltages_mv[52] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[53] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[54] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[55] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[56] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[57] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[58] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 4) { + battery2_cellvoltages_mv[84] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[85] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[86] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[87] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[88] = (rx_frame.data.u8[5] * 20); + battery2_cellvoltages_mv[89] = (rx_frame.data.u8[6] * 20); + battery2_cellvoltages_mv[90] = (rx_frame.data.u8[7] * 20); + } else if (poll_data_pid == 5) { + } + break; + case 0x25: //Fifth datarow in PID group + if (poll_data_pid == 2) { + battery2_cellvoltages_mv[27] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[28] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[29] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[30] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[31] = (rx_frame.data.u8[5] * 20); + } else if (poll_data_pid == 3) { + battery2_cellvoltages_mv[59] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[60] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[61] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[62] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[63] = (rx_frame.data.u8[5] * 20); + } else if (poll_data_pid == 4) { + battery2_cellvoltages_mv[91] = (rx_frame.data.u8[1] * 20); + battery2_cellvoltages_mv[92] = (rx_frame.data.u8[2] * 20); + battery2_cellvoltages_mv[93] = (rx_frame.data.u8[3] * 20); + battery2_cellvoltages_mv[94] = (rx_frame.data.u8[4] * 20); + battery2_cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20); + + //Map all cell voltages to the global array, we have sampled them all! + memcpy(datalayer.battery2.status.cell_voltages_mV, battery2_cellvoltages_mv, 96 * sizeof(uint16_t)); + } else if (poll_data_pid == 5) { + } + break; + case 0x26: //Sixth datarow in PID group + break; + case 0x27: //Seventh datarow in PID group + break; + case 0x28: //Eighth datarow in PID group + break; + } + break; + default: + break; } } +#endif //DOUBLE_BATTERY uint8_t CalculateCRC8(CAN_frame rx_frame) { int crc = 0; @@ -409,6 +669,16 @@ void setup_battery(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.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; + +#ifdef DOUBLE_BATTERY + datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells; + datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV; + datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV; + datalayer.battery2.info.max_cell_voltage_mV = datalayer.battery.info.max_cell_voltage_mV; + datalayer.battery2.info.min_cell_voltage_mV = datalayer.battery.info.min_cell_voltage_mV; + datalayer.battery2.info.max_cell_voltage_deviation_mV = datalayer.battery.info.max_cell_voltage_deviation_mV; +#endif //DOUBLE_BATTERY } #endif From 3653ff6449e5b9ac9571460fd7983f64f6fced2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 28 Nov 2024 23:34:25 +0200 Subject: [PATCH 053/225] Add target voltage setting, configurable --- Software/Software.ino | 74 ++++++++++++++----- Software/USER_SETTINGS.h | 10 ++- Software/src/datalayer/datalayer.h | 10 +++ Software/src/devboard/utils/events.cpp | 3 + Software/src/devboard/utils/events.h | 3 +- .../src/devboard/webserver/settings_html.cpp | 46 +++++++++++- Software/src/devboard/webserver/webserver.cpp | 42 +++++++++++ Software/src/inverter/BYD-CAN.cpp | 24 ++++-- 8 files changed, 184 insertions(+), 28 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 6696ee029..8394317f5 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -388,7 +388,7 @@ void init_stored_settings() { //always save the equipment stop status settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active); -#endif +#endif //LOAD_SAVED_SETTINGS_ON_BOOT #ifdef WIFI @@ -404,7 +404,7 @@ void init_stored_settings() { password = tempPasswordString; } else { // Reading from settings failed. Do nothing with SSID. Raise event? } -#endif +#endif //WIFI temp = settings.getUInt("BATTERY_WH_MAX", false); if (temp != 0) { @@ -425,10 +425,20 @@ void init_stored_settings() { temp = settings.getUInt("MAXDISCHARGEAMP", false); if (temp != 0) { datalayer.battery.settings.max_user_set_discharge_dA = temp; - temp = settings.getBool("USE_SCALED_SOC", false); - datalayer.battery.settings.soc_scaling_active = temp; //This bool needs to be checked inside the temp!= block - } // No way to know if it wasnt reset otherwise + } + datalayer.battery.settings.soc_scaling_active = settings.getBool("USE_SCALED_SOC", false); + settings.end(); + settings.begin("batteryExtra", false); + temp = settings.getUInt("TARGETCHARGEVOLTAGE", false); + if (temp != 0) { + datalayer.battery.settings.max_user_set_charge_voltage_dV = temp; + } + temp = settings.getUInt("TARGETDISCHARGEVOLTAGE", false); + if (temp != 0) { + datalayer.battery.settings.max_user_set_discharge_voltage_dV = temp; + } + datalayer.battery.settings.user_set_voltage_limits_active = settings.getBool("USE_VOLTAGE_LIMITS", false); settings.end(); } @@ -1049,20 +1059,48 @@ void store_settings_equipment_stop() { } void storeSettings() { - settings.begin("batterySettings", false); + if (!settings.begin("batterySettings", false)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 0); + return; + } + #ifdef WIFI - settings.putString("SSID", String(ssid.c_str())); - settings.putString("PASSWORD", String(password.c_str())); -#endif - settings.putUInt("BATTERY_WH_MAX", datalayer.battery.info.total_capacity_Wh); - settings.putUInt("MAXPERCENTAGE", - datalayer.battery.settings.max_percentage / 10); // Divide by 10 for backwards compatibility - settings.putUInt("MINPERCENTAGE", - datalayer.battery.settings.min_percentage / 10); // Divide by 10 for backwards compatibility - settings.putUInt("MAXCHARGEAMP", datalayer.battery.settings.max_user_set_charge_dA); - settings.putUInt("MAXDISCHARGEAMP", datalayer.battery.settings.max_user_set_discharge_dA); - settings.putBool("USE_SCALED_SOC", datalayer.battery.settings.soc_scaling_active); - settings.end(); + if (!settings.putString("SSID", String(ssid.c_str()))) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 1); + } + if (!settings.putString("PASSWORD", String(password.c_str()))) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 2); + } +#endif + + if (!settings.putUInt("BATTERY_WH_MAX", datalayer.battery.info.total_capacity_Wh)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 3); + } + if (!settings.putBool("USE_SCALED_SOC", datalayer.battery.settings.soc_scaling_active)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 4); + } + if (!settings.putUInt("MAXPERCENTAGE", datalayer.battery.settings.max_percentage / 10)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 5); + } + if (!settings.putUInt("MINPERCENTAGE", datalayer.battery.settings.min_percentage / 10)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 6); + } + if (!settings.putUInt("MAXCHARGEAMP", datalayer.battery.settings.max_user_set_charge_dA)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 7); + } + if (!settings.putUInt("MAXDISCHARGEAMP", datalayer.battery.settings.max_user_set_discharge_dA)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 8); + } + if (!settings.putBool("USE_VOLTAGE_LIMITS", datalayer.battery.settings.user_set_voltage_limits_active)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 9); + } + if (!settings.putUInt("TARGETCHARGEVOLTAGE", datalayer.battery.settings.max_user_set_charge_voltage_dV)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 10); + } + if (!settings.putUInt("TARGETDISCHARGEVOLTAGE", datalayer.battery.settings.max_user_set_discharge_voltage_dV)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 11); + } + settings.end(); // Close preferences handle } /** Reset reason numbering and description diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 2f2cf3fea..792db0bf0 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -125,10 +125,16 @@ #define BATTERY_MAXTEMPERATURE 500 // -250 = -25.0 °C , Min temperature (Will produce a battery frozen event if below) #define BATTERY_MINTEMPERATURE -250 -// 300 = 30.0A , BYD CAN specific setting, Max charge in Amp (Some inverters needs to be limited) +// 300 = 30.0A , Max charge in Amp (Some inverters needs to be limited) #define BATTERY_MAX_CHARGE_AMP 300 -// 300 = 30.0A , BYD CAN specific setting, Max discharge in Amp (Some inverters needs to be limited) +// 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 unless you are sure what you are doing */ /* Only change battery specific settings in "USER_SETTINGS.h" */ diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index e6de68ce0..6064aa153 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -107,10 +107,20 @@ typedef struct { * you want the inverter to be able to use. At this real SOC, the inverter * will "see" 100% */ uint16_t max_percentage = BATTERY_MAXPERCENTAGE; + /** The user specified maximum allowed charge rate, in deciAmpere. 300 = 30.0 A */ uint16_t max_user_set_charge_dA = BATTERY_MAX_CHARGE_AMP; /** The user specified maximum allowed discharge rate, in deciAmpere. 300 = 30.0 A */ uint16_t max_user_set_discharge_dA = BATTERY_MAX_DISCHARGE_AMP; + + /** 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; + /** 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; + /** 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; + } DATALAYER_BATTERY_SETTINGS_TYPE; typedef struct { diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index b0c3e2853..d51bd1c4d 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -191,6 +191,7 @@ void init_events(void) { events.entries[EVENT_DUMMY_DEBUG].level = EVENT_LEVEL_DEBUG; events.entries[EVENT_DUMMY_WARNING].level = EVENT_LEVEL_WARNING; events.entries[EVENT_DUMMY_ERROR].level = EVENT_LEVEL_ERROR; + events.entries[EVENT_PERSISTENT_SAVE_INFO].level = EVENT_LEVEL_INFO; events.entries[EVENT_SERIAL_RX_WARNING].level = EVENT_LEVEL_WARNING; events.entries[EVENT_SERIAL_RX_FAILURE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_SERIAL_TX_FAILURE].level = EVENT_LEVEL_ERROR; @@ -368,6 +369,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) { return "The dummy warning event was set!"; // Don't change this event message! case EVENT_DUMMY_ERROR: return "The dummy error event was set!"; // Don't change this event message! + case EVENT_PERSISTENT_SAVE_INFO: + return "Info: Failed to save user settings. Namespace full?"; case EVENT_SERIAL_RX_WARNING: return "Error in serial function: No data received for some time, see data for minutes"; case EVENT_SERIAL_RX_FAILURE: diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index b50d7de4f..d410d66f5 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -6,7 +6,7 @@ // #define INCLUDE_EVENTS_TEST // Enable to run an event test loop, see events_test_on_target.cpp -#define EE_MAGIC_HEADER_VALUE 0x0017 // 0x0000 to 0xFFFF +#define EE_MAGIC_HEADER_VALUE 0x0018 // 0x0000 to 0xFFFF #define GENERATE_ENUM(ENUM) ENUM, #define GENERATE_STRING(STRING) #STRING, @@ -79,6 +79,7 @@ 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) \ diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 484e50210..5a26b745b 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -67,6 +67,21 @@ String settings_processor(const String& var) { content += "

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

"; + content += "

Manual charge voltage limits: " + + String(datalayer.battery.settings.user_set_voltage_limits_active + ? "" + : "") + + "

"; + content += + "

Target charge voltage: " + String(datalayer.battery.settings.max_user_set_charge_voltage_dV / 10.0, 1) + + " V

"; + content += "

Target discharge voltage: " + + String(datalayer.battery.settings.max_user_set_discharge_voltage_dV / 10.0, 1) + + " V

"; // Close the block content += ""; @@ -130,7 +145,9 @@ String settings_processor(const String& var) { "updateBatterySize?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value between 1 " "and 120000.');}}}"; content += - "function editUseScaledSOC(){var value=prompt('Should SOC% be scaled? (0 = No, 1 = " + "function editUseScaledSOC(){var value=prompt('Extends battery life by rescaling the SOC within the configured " + "minimum " + "and maximum percentage. Should SOC scaling be applied? (0 = No, 1 = " "Yes):');if(value!==null){if(value==0||value==1){var xhr=new " "XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/" "updateUseScaledSOC?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value between 0 " @@ -161,6 +178,33 @@ String settings_processor(const String& var) { "XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/" "updateMaxDischargeA?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value between 0 " "and 1000.0');}}}"; + content += + "function editUseVoltageLimit(){var value=prompt('Enable this option to manually restrict charge/discharge to " + "a specific voltage set below." + "If disabled the emulator automatically determines this based on battery limits. Restrict manually? (0 = No, 1 " + "= Yes)" + ":');if(value!==null){if(value==0||value==1){var xhr=new " + "XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/" + "updateUseVoltageLimit?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value between " + "0 " + "and 1.');}}}"; + content += + "function editMaxChargeVoltage(){var value=prompt('Some inverters needs to be artificially limited. Enter new " + "voltage setpoint batttery should charge to (0-1000.0):');if(value!==null){if(value>=0&&value<=1000){var " + "xhr=new " + "XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/" + "updateMaxChargeVoltage?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value " + "between 0 " + "and 1000.0');}}}"; + content += + "function editMaxDischargeVoltage(){var value=prompt('Some inverters needs to be artificially limited. Enter " + "new " + "voltage setpoint batttery should discharge to (0-1000.0):');if(value!==null){if(value>=0&&value<=1000){var " + "xhr=new " + "XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/" + "updateMaxDischargeVoltage?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value " + "between 0 " + "and 1000.0');}}}"; #ifdef TEST_FAKE_BATTERY content += diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index cfdf29823..ff7770eea 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -272,6 +272,48 @@ void init_webserver() { } }); + // Route for editing BATTERY_USE_VOLTAGE_LIMITS + server.on("/updateUseVoltageLimit", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) + return request->requestAuthentication(); + if (request->hasParam("value")) { + String value = request->getParam("value")->value(); + datalayer.battery.settings.user_set_voltage_limits_active = value.toInt(); + storeSettings(); + request->send(200, "text/plain", "Updated successfully"); + } else { + request->send(400, "text/plain", "Bad Request"); + } + }); + + // Route for editing MaxChargeVoltage + server.on("/updateMaxChargeVoltage", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) + return request->requestAuthentication(); + if (request->hasParam("value")) { + String value = request->getParam("value")->value(); + datalayer.battery.settings.max_user_set_charge_voltage_dV = static_cast(value.toFloat() * 10); + storeSettings(); + request->send(200, "text/plain", "Updated successfully"); + } else { + request->send(400, "text/plain", "Bad Request"); + } + }); + + // Route for editing MaxDischargeVoltage + server.on("/updateMaxDischargeVoltage", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) + return request->requestAuthentication(); + if (request->hasParam("value")) { + String value = request->getParam("value")->value(); + datalayer.battery.settings.max_user_set_discharge_voltage_dV = static_cast(value.toFloat() * 10); + storeSettings(); + request->send(200, "text/plain", "Updated successfully"); + } else { + request->send(400, "text/plain", "Bad Request"); + } + }); + // Route for resetting SOH on Nissan LEAF batteries server.on("/resetSOH", HTTP_GET, [](AsyncWebServerRequest* request) { if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 4ffa7b204..d7a4028ff 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -8,6 +8,8 @@ static unsigned long previousMillis2s = 0; // will store last time a 2s CAN Me static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send +#define VOLTAGE_OFFSET_DV 20 + CAN_frame BYD_250 = {.FD = false, .ext_ID = false, .DLC = 8, @@ -98,12 +100,22 @@ void update_values_can_inverter() { //This function maps all the values fetched } //Map values to CAN messages - //Maxvoltage (eg 400.0V = 4000 , 16bits long) - BYD_110.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); - BYD_110.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); - //Minvoltage (eg 300.0V = 3000 , 16bits long) - BYD_110.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); - BYD_110.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); + if (datalayer.battery.settings.user_set_voltage_limits_active) { //If user is requesting a specific voltage + //Target charge voltage (eg 400.0V = 4000 , 16bits long) + BYD_110.data.u8[0] = (datalayer.battery.settings.max_user_set_charge_voltage_dV >> 8); + BYD_110.data.u8[1] = (datalayer.battery.settings.max_user_set_charge_voltage_dV & 0x00FF); + //Target discharge voltage (eg 300.0V = 3000 , 16bits long) + BYD_110.data.u8[2] = (datalayer.battery.settings.max_user_set_discharge_voltage_dV >> 8); + BYD_110.data.u8[3] = (datalayer.battery.settings.max_user_set_discharge_voltage_dV & 0x00FF); + } else { //Use the voltage based on battery reported design voltage +- offset to avoid triggering events + //Target charge voltage (eg 400.0V = 4000 , 16bits long) + BYD_110.data.u8[0] = ((datalayer.battery.info.max_design_voltage_dV - VOLTAGE_OFFSET_DV) >> 8); + BYD_110.data.u8[1] = ((datalayer.battery.info.max_design_voltage_dV - VOLTAGE_OFFSET_DV) & 0x00FF); + //Target discharge voltage (eg 300.0V = 3000 , 16bits long) + BYD_110.data.u8[2] = ((datalayer.battery.info.min_design_voltage_dV + VOLTAGE_OFFSET_DV) >> 8); + BYD_110.data.u8[3] = ((datalayer.battery.info.min_design_voltage_dV + VOLTAGE_OFFSET_DV) & 0x00FF); + } + //Maximum discharge power allowed (Unit: A+1) BYD_110.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); BYD_110.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); From 8dbc50be3ede4b27e910806cb7c902db0ef78b5d Mon Sep 17 00:00:00 2001 From: mvgalen Date: Sun, 15 Dec 2024 14:22:39 +0100 Subject: [PATCH 054/225] Reduce preferences key length to max 15 characters. Add notes about this limitation. --- Software/Software.ino | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 8394317f5..fc734e0f3 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -374,6 +374,7 @@ void init_serial() { void init_stored_settings() { static uint32_t temp = 0; + // ATTENTION ! The maximum length for settings keys is 15 characters settings.begin("batterySettings", false); // Always get the equipment stop status @@ -430,15 +431,15 @@ void init_stored_settings() { settings.end(); settings.begin("batteryExtra", false); - temp = settings.getUInt("TARGETCHARGEVOLTAGE", false); + temp = settings.getUInt("TARGETCHVOLT", false); if (temp != 0) { datalayer.battery.settings.max_user_set_charge_voltage_dV = temp; } - temp = settings.getUInt("TARGETDISCHARGEVOLTAGE", false); + temp = settings.getUInt("TARGETDISCHVOLT", false); if (temp != 0) { datalayer.battery.settings.max_user_set_discharge_voltage_dV = temp; } - datalayer.battery.settings.user_set_voltage_limits_active = settings.getBool("USE_VOLTAGE_LIMITS", false); + datalayer.battery.settings.user_set_voltage_limits_active = settings.getBool("USEVOLTLIMITS", false); settings.end(); } @@ -1059,6 +1060,7 @@ void store_settings_equipment_stop() { } void storeSettings() { + // ATTENTION ! The maximum length for settings keys is 15 characters if (!settings.begin("batterySettings", false)) { set_event(EVENT_PERSISTENT_SAVE_INFO, 0); return; @@ -1091,13 +1093,13 @@ void storeSettings() { if (!settings.putUInt("MAXDISCHARGEAMP", datalayer.battery.settings.max_user_set_discharge_dA)) { set_event(EVENT_PERSISTENT_SAVE_INFO, 8); } - if (!settings.putBool("USE_VOLTAGE_LIMITS", datalayer.battery.settings.user_set_voltage_limits_active)) { + if (!settings.putBool("USEVOLTLIMITS", datalayer.battery.settings.user_set_voltage_limits_active)) { set_event(EVENT_PERSISTENT_SAVE_INFO, 9); } - if (!settings.putUInt("TARGETCHARGEVOLTAGE", datalayer.battery.settings.max_user_set_charge_voltage_dV)) { + if (!settings.putUInt("TARGETCHVOLT", datalayer.battery.settings.max_user_set_charge_voltage_dV)) { set_event(EVENT_PERSISTENT_SAVE_INFO, 10); } - if (!settings.putUInt("TARGETDISCHARGEVOLTAGE", datalayer.battery.settings.max_user_set_discharge_voltage_dV)) { + if (!settings.putUInt("TARGETDISCHVOLT", datalayer.battery.settings.max_user_set_discharge_voltage_dV)) { set_event(EVENT_PERSISTENT_SAVE_INFO, 11); } settings.end(); // Close preferences handle From 005f3e6e7d4442a1fff17d7b6bb89443a8e25223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 15 Dec 2024 16:24:59 +0200 Subject: [PATCH 055/225] Make parameter saving work --- Software/Software.ino | 3 --- 1 file changed, 3 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index fc734e0f3..1712c70fa 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -428,9 +428,6 @@ void init_stored_settings() { datalayer.battery.settings.max_user_set_discharge_dA = temp; } datalayer.battery.settings.soc_scaling_active = settings.getBool("USE_SCALED_SOC", false); - settings.end(); - - settings.begin("batteryExtra", false); temp = settings.getUInt("TARGETCHVOLT", false); if (temp != 0) { datalayer.battery.settings.max_user_set_charge_voltage_dV = temp; From f8140b19f159943d3768e7834c3ee7163bb1450a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 15 Dec 2024 16:43:35 +0200 Subject: [PATCH 056/225] Update version number for release --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index 1712c70fa..26ff18db4 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -53,7 +53,7 @@ Preferences settings; // Store user settings // The current software version, shown on webserver -const char* version_number = "8.0.dev"; +const char* version_number = "7.9.2"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From 4fef40b2a37bb382df0060352732f717e3f3ac07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 15 Dec 2024 17:05:20 +0200 Subject: [PATCH 057/225] Update version number to signal dev --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index 26ff18db4..1712c70fa 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -53,7 +53,7 @@ Preferences settings; // Store user settings // The current software version, shown on webserver -const char* version_number = "7.9.2"; +const char* version_number = "8.0.dev"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From 7fe5dcb0b8efc4fa9fac14ff00185f3e93274ea2 Mon Sep 17 00:00:00 2001 From: lenvm Date: Fri, 13 Dec 2024 14:58:09 +0100 Subject: [PATCH 058/225] update DUAL_CAN to CAN_ADDON and update CAN_FD to CANFD_ADDON --- .github/ISSUE_TEMPLATE.md | 2 +- Software/Software.ino | 36 +++++++++---------- Software/USER_SETTINGS.cpp | 2 +- Software/USER_SETTINGS.h | 26 +++++++------- Software/src/devboard/hal/hw_3LB.h | 16 ++++----- Software/src/devboard/hal/hw_lilygo.h | 16 ++++----- Software/src/devboard/hal/hw_stark.h | 2 +- .../src/devboard/webserver/settings_html.cpp | 2 +- Software/src/include.h | 6 ++-- 9 files changed, 54 insertions(+), 54 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 22f260e78..71921d60c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -23,6 +23,6 @@ - Inverter communication protocol: `` - Hardware used for Battery-Emulator: `HW_LILYGO, HW_STARK, Custom` - CONTACTOR_CONTROL: `yes/no` -- DUAL_CAN: `yes/no` +- CAN_ADDON: `yes/no` - WEBSERVER: `yes/no` - MQTT: `yes/no` diff --git a/Software/Software.ino b/Software/Software.ino index 1712c70fa..f94d6d2e6 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -65,16 +65,16 @@ CAN_device_t CAN_cfg; // CAN Config const int rx_queue_size = 10; // Receive Queue size volatile bool send_ok = 0; -#ifdef DUAL_CAN +#ifdef CAN_ADDON #include "src/lib/pierremolinaro-acan2515/ACAN2515.h" static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT); static ACAN2515_Buffer16 gBuffer; -#endif //DUAL_CAN -#ifdef CAN_FD +#endif //CAN_ADDON +#ifdef CANFD_ADDON #include "src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); -#endif //CAN_FD +#endif //CANFD_ADDON // ModbusRTU parameters #ifdef MODBUS_INVERTER_SELECTED @@ -276,10 +276,10 @@ void core_loop(void* task_time_us) { // Input, Runs as fast as possible receive_can_native(); // Receive CAN messages from native CAN port -#ifdef CAN_FD +#ifdef CANFD_ADDON receive_canfd(); // Receive CAN-FD messages. #endif -#ifdef DUAL_CAN +#ifdef CAN_ADDON receive_can_addonMCP2515(); // Receive CAN messages on add-on MCP2515 chip #endif #ifdef RS485_INVERTER_SELECTED @@ -456,7 +456,7 @@ void init_CAN() { // Init CAN Module ESP32Can.CANInit(); -#ifdef DUAL_CAN +#ifdef CAN_ADDON #ifdef DEBUG_VIA_USB Serial.println("Dual CAN Bus (ESP32+MCP2515) selected"); #endif @@ -478,12 +478,12 @@ void init_CAN() { } #endif -#ifdef CAN_FD +#ifdef CANFD_ADDON #ifdef DEBUG_VIA_USB Serial.println("CAN FD add-on (ESP32+MCP2517) selected"); #endif SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); - ACAN2517FDSettings settings(CAN_FD_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, + ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN settings.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD @@ -683,7 +683,7 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { } } -#ifdef CAN_FD +#ifdef CANFD_ADDON // Functions void receive_canfd() { // This section checks if we have a complete CAN-FD message incoming CANFDMessage frame; @@ -697,7 +697,7 @@ void receive_canfd() { // This section checks if we have a complete CAN-FD mess rx_frame.DLC = frame.len; memcpy(rx_frame.data.u8, frame.data, MIN(rx_frame.DLC, 64)); //message incoming, pass it on to the handler - receive_can(&rx_frame, CAN_ADDON_FD_MCP2518); + receive_can(&rx_frame, CANFD_ADDON_MCP2518); receive_can(&rx_frame, CANFD_NATIVE); } } @@ -738,7 +738,7 @@ void send_can() { #endif // CHARGER_SELECTED } -#ifdef DUAL_CAN +#ifdef CAN_ADDON void receive_can_addonMCP2515() { // This section checks if we have a complete CAN message incoming on add-on CAN port CAN_frame rx_frame; // Struct with our CAN format CANMessage MCP2515Frame; // Struct with ACAN2515 library format, needed to use the MCP2515 library @@ -757,7 +757,7 @@ void receive_can_addonMCP2515() { // This section checks if we have a complete receive_can(&rx_frame, CAN_ADDON_MCP2515); } } -#endif // DUAL_CAN +#endif // CAN_ADDON #ifdef DOUBLE_BATTERY void check_interconnect_available() { @@ -1198,7 +1198,7 @@ void transmit_can(CAN_frame* tx_frame, int interface) { ESP32Can.CANWriteFrame(&frame); break; case CAN_ADDON_MCP2515: { -#ifdef DUAL_CAN +#ifdef CAN_ADDON //Struct with ACAN2515 library format, needed to use the MCP2515 library for CAN2 CANMessage MCP2515Frame; MCP2515Frame.id = tx_frame->ID; @@ -1211,11 +1211,11 @@ void transmit_can(CAN_frame* tx_frame, int interface) { can.tryToSend(MCP2515Frame); #else // Interface not compiled, and settings try to use it set_event(EVENT_INTERFACE_MISSING, interface); -#endif //DUAL_CAN +#endif //CAN_ADDON } break; case CANFD_NATIVE: - case CAN_ADDON_FD_MCP2518: { -#ifdef CAN_FD + case CANFD_ADDON_MCP2518: { +#ifdef CANFD_ADDON CANFDMessage MCP2518Frame; if (tx_frame->FD) { MCP2518Frame.type = CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH; @@ -1234,7 +1234,7 @@ void transmit_can(CAN_frame* tx_frame, int interface) { } #else // Interface not compiled, and settings try to use it set_event(EVENT_INTERFACE_MISSING, interface); -#endif //CAN_FD +#endif //CANFD_ADDON } break; default: // Invalid interface sent with function call. TODO: Raise event that coders messed up diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 7e916e68e..7c2309b4a 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -9,7 +9,7 @@ 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 -CAN_ADDON_FD_MCP2518 = Add-on CAN-FD MCP2518 connected to GPIO pins +CANFD_ADDON_MCP2518 = Add-on CAN-FD MCP2518 connected to GPIO pins */ volatile CAN_Configuration can_config = { diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 792db0bf0..d31582dd4 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -34,7 +34,7 @@ //#define TESLA_MODEL_SX_BATTERY //#define VOLVO_SPA_BATTERY //#define TEST_FAKE_BATTERY -//#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires DUAL_CAN setup) +//#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires CAN_ADDON setup) /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus @@ -65,17 +65,17 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! /* Other options */ -//#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -//#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) -//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting -//#define DUAL_CAN //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 //DUAL_CAN option, what is your MCP2515 add-on boards crystal frequency? -//#define CAN_FD //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board -#ifdef CAN_FD // CAN_FD additional options if enabled -#define CAN_FD_CRYSTAL_FREQUENCY_MHZ \ - ACAN2517FDSettings:: \ - OSC_40MHz //CAN_FD option, what is your MCP2518 add-on boards crystal frequency? (Default OSC_40MHz) -#endif +//#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) +//#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) +//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting +//#define 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 +#ifdef CANFD_ADDON // CANFD_ADDON additional options if enabled +#define CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ \ + ACAN2517FDSettings:: \ + OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency? (Default OSC_40MHz) +#endif // CANFD_ADDON //#define USE_CANFD_INTERFACE_AS_CLASSIC_CAN // Enable this line if you intend to use the CANFD as normal CAN //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) @@ -138,7 +138,7 @@ /* 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" */ -typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CAN_ADDON_FD_MCP2518 = 3 } CAN_Interface; +typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CANFD_ADDON_MCP2518 = 3 } CAN_Interface; typedef struct { CAN_Interface battery; CAN_Interface inverter; diff --git a/Software/src/devboard/hal/hw_3LB.h b/Software/src/devboard/hal/hw_3LB.h index a54de2a47..f4883be78 100644 --- a/Software/src/devboard/hal/hw_3LB.h +++ b/Software/src/devboard/hal/hw_3LB.h @@ -26,14 +26,14 @@ // CAN2 defines below -// DUAL_CAN defines +// CAN_ADDON defines #define MCP2515_SCK 12 // SCK input of MCP2515 #define MCP2515_MOSI 5 // SDI input of MCP2515 #define MCP2515_MISO 34 // SDO output of MCP2515 | Pin 34 is input only, without pullup/down resistors #define MCP2515_CS 18 // CS input of MCP2515 #define MCP2515_INT 35 // INT output of MCP2515 | | Pin 35 is input only, without pullup/down resistors -// CAN_FD defines +// CANFD_ADDON defines #define MCP2517_SCK 17 // SCK input of MCP2517 #define MCP2517_SDI 23 // SDI input of MCP2517 #define MCP2517_SDO 39 // SDO output of MCP2517 @@ -80,17 +80,17 @@ #endif #ifdef CHADEMO_BATTERY -#ifdef DUAL_CAN -#error CHADEMO and DUAL_CAN cannot coexist due to overlapping GPIO pin usage +#ifdef CAN_ADDON +#error CHADEMO and CAN_ADDON cannot coexist due to overlapping GPIO pin usage #endif #endif #ifdef EQUIPMENT_STOP_BUTTON -#ifdef DUAL_CAN -#error EQUIPMENT_STOP_BUTTON and DUAL_CAN cannot coexist due to overlapping GPIO pin usage +#ifdef CAN_ADDON +#error EQUIPMENT_STOP_BUTTON and CAN_ADDON cannot coexist due to overlapping GPIO pin usage #endif -#ifdef CAN_FD -#error EQUIPMENT_STOP_BUTTON and CAN_FD cannot coexist due to overlapping GPIO pin usage +#ifdef CANFD_ADDON +#error EQUIPMENT_STOP_BUTTON and CANFD_ADDON cannot coexist due to overlapping GPIO pin usage #endif #ifdef CHADEMO_BATTERY #error EQUIPMENT_STOP_BUTTON and CHADEMO_BATTERY cannot coexist due to overlapping GPIO pin usage diff --git a/Software/src/devboard/hal/hw_lilygo.h b/Software/src/devboard/hal/hw_lilygo.h index d4d7ce2c7..2ea8d2608 100644 --- a/Software/src/devboard/hal/hw_lilygo.h +++ b/Software/src/devboard/hal/hw_lilygo.h @@ -26,14 +26,14 @@ // CAN2 defines below -// DUAL_CAN defines +// CAN_ADDON defines #define MCP2515_SCK 12 // SCK input of MCP2515 #define MCP2515_MOSI 5 // SDI input of MCP2515 #define MCP2515_MISO 34 // SDO output of MCP2515 | Pin 34 is input only, without pullup/down resistors #define MCP2515_CS 18 // CS input of MCP2515 #define MCP2515_INT 35 // INT output of MCP2515 | | Pin 35 is input only, without pullup/down resistors -// CAN_FD defines +// CANFD_ADDON defines #define MCP2517_SCK 12 // SCK input of MCP2517 #define MCP2517_SDI 5 // SDI input of MCP2517 #define MCP2517_SDO 34 // SDO output of MCP2517 @@ -76,17 +76,17 @@ #endif #ifdef CHADEMO_BATTERY -#ifdef DUAL_CAN -#error CHADEMO and DUAL_CAN cannot coexist due to overlapping GPIO pin usage +#ifdef CAN_ADDON +#error CHADEMO and CAN_ADDON cannot coexist due to overlapping GPIO pin usage #endif #endif #ifdef EQUIPMENT_STOP_BUTTON -#ifdef DUAL_CAN -#error EQUIPMENT_STOP_BUTTON and DUAL_CAN cannot coexist due to overlapping GPIO pin usage +#ifdef CAN_ADDON +#error EQUIPMENT_STOP_BUTTON and CAN_ADDON cannot coexist due to overlapping GPIO pin usage #endif -#ifdef CAN_FD -#error EQUIPMENT_STOP_BUTTON and CAN_FD cannot coexist due to overlapping GPIO pin usage +#ifdef CANFD_ADDON +#error EQUIPMENT_STOP_BUTTON and CANFD_ADDON cannot coexist due to overlapping GPIO pin usage #endif #ifdef CHADEMO_BATTERY #error EQUIPMENT_STOP_BUTTON and CHADEMO_BATTERY cannot coexist due to overlapping GPIO pin usage diff --git a/Software/src/devboard/hal/hw_stark.h b/Software/src/devboard/hal/hw_stark.h index 5e26f559f..f12ea84ac 100644 --- a/Software/src/devboard/hal/hw_stark.h +++ b/Software/src/devboard/hal/hw_stark.h @@ -38,7 +38,7 @@ GPIOs on extra header #define CAN_RX_PIN GPIO_NUM_26 // #define CAN_SE_PIN 23 // (No function, GPIO 23 used instead as MCP_SCK) -// CAN_FD defines +// CANFD_ADDON defines #define MCP2517_SCK 17 // SCK input of MCP2517 #define MCP2517_SDI 5 // SDI input of MCP2517 #define MCP2517_SDO 34 // SDO output of MCP2517 diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 5a26b745b..e21ec7229 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -271,7 +271,7 @@ const char* getCANInterfaceName(CAN_Interface interface) { #endif case CAN_ADDON_MCP2515: return "Add-on CAN via GPIO MCP2515"; - case CAN_ADDON_FD_MCP2518: + case CANFD_ADDON_MCP2518: #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN return "Add-on CAN-FD via GPIO MCP2518 (Classic CAN)"; #else diff --git a/Software/src/include.h b/Software/src/include.h index f00e23825..901056972 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -22,15 +22,15 @@ #error You must select a HW to run on! #endif -#if defined(DUAL_CAN) && defined(CAN_FD) +#if defined(CAN_ADDON) && defined(CANFD_ADDON) // Check that user did not try to use dual can and fd-can on same hardware pins #error CAN-FD AND DUAL-CAN CANNOT BE USED SIMULTANEOUSLY #endif #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN -#if !defined(CAN_FD) +#if !defined(CANFD_ADDON) // Check that user did not try to use classic CAN over FD, without FD component -#error PLEASE ENABLE CAN_FD TO USE CLASSIC CAN OVER CANFD INTERFACE +#error PLEASE ENABLE CANFD_ADDON TO USE CLASSIC CAN OVER CANFD INTERFACE #endif #endif From b512c17504396958d9c2a11a65924eaaf9973602 Mon Sep 17 00:00:00 2001 From: lenvm Date: Fri, 13 Dec 2024 15:16:17 +0100 Subject: [PATCH 059/225] add comments for #endif statements --- Software/Software.ino | 115 ++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index f94d6d2e6..a4e1e77f0 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -277,23 +277,23 @@ void core_loop(void* task_time_us) { // Input, Runs as fast as possible receive_can_native(); // Receive CAN messages from native CAN port #ifdef CANFD_ADDON - receive_canfd(); // Receive CAN-FD messages. -#endif + receive_canfd_addon(); // Receive CAN-FD messages. +#endif // CANFD_ADDON #ifdef CAN_ADDON - receive_can_addonMCP2515(); // Receive CAN messages on add-on MCP2515 chip -#endif + receive_can_addon(); // Receive CAN messages on add-on MCP2515 chip +#endif // CAN_ADDON #ifdef RS485_INVERTER_SELECTED receive_RS485(); // Process serial2 RS485 interface -#endif +#endif // RS485_INVERTER_SELECTED #if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) runSerialDataLink(); -#endif +#endif // SERIAL_LINK_RECEIVER || SERIAL_LINK_TRANSMITTER END_TIME_MEASUREMENT_MAX(comm, datalayer.system.status.time_comm_us); #ifdef WEBSERVER START_TIME_MEASUREMENT(ota); ElegantOTA.loop(); END_TIME_MEASUREMENT_MAX(ota, datalayer.system.status.time_ota_us); -#endif +#endif // WEBSERVER START_TIME_MEASUREMENT(time_10ms); // Process @@ -311,12 +311,12 @@ void core_loop(void* task_time_us) { #ifdef DOUBLE_BATTERY update_values_battery2(); check_interconnect_available(); -#endif +#endif // DOUBLE_BATTERY update_calculated_values(); #ifndef SERIAL_LINK_RECEIVER update_machineryprotection(); // Check safeties (Not on serial link reciever board) -#endif - update_values_inverter(); // Update values heading towards inverter +#endif // SERIAL_LINK_RECEIVER + update_values_inverter(); // Update values heading towards inverter if (DUMMY_EVENT_ENABLED) { set_event(EVENT_DUMMY_ERROR, (uint8_t)millis()); } @@ -330,7 +330,6 @@ void core_loop(void* task_time_us) { END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us); END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us); #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; @@ -352,8 +351,7 @@ void core_loop(void* task_time_us) { datalayer.system.status.time_cantx_us = 0; datalayer.system.status.core_task_10s_max_us = 0; } - -#endif +#endif // FUNCTION_TIME_MEASUREMENT if (check_pause_2s.elapsed()) { emulator_pause_state_send_CAN_battery(); } @@ -369,7 +367,7 @@ void init_serial() { while (!Serial) {} #ifdef DEBUG_VIA_USB Serial.println("__ OK __"); -#endif +#endif // DEBUG_VIA_USB } void init_stored_settings() { @@ -388,11 +386,14 @@ void init_stored_settings() { //always save the equipment stop status settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active); +<<<<<<< HEAD #endif //LOAD_SAVED_SETTINGS_ON_BOOT +======= +#endif // LOAD_SAVED_SETTINGS_ON_BOOT +>>>>>>> f4051ff (add comments for #endif statements) #ifdef WIFI - char tempSSIDstring[63]; // Allocate buffer with sufficient size size_t lengthSSID = settings.getString("SSID", tempSSIDstring, sizeof(tempSSIDstring)); if (lengthSSID > 0) { // Successfully read the string from memory. Set it to SSID! @@ -405,7 +406,7 @@ void init_stored_settings() { password = tempPasswordString; } else { // Reading from settings failed. Do nothing with SSID. Raise event? } -#endif //WIFI +#endif // WIFI temp = settings.getUInt("BATTERY_WH_MAX", false); if (temp != 0) { @@ -445,11 +446,11 @@ void init_CAN() { #ifdef CAN_SE_PIN pinMode(CAN_SE_PIN, OUTPUT); digitalWrite(CAN_SE_PIN, LOW); -#endif +#endif // CAN_SE_PIN CAN_cfg.speed = CAN_SPEED_500KBPS; #ifdef NATIVECAN_250KBPS // Some component is requesting lower CAN speed CAN_cfg.speed = CAN_SPEED_250KBPS; -#endif +#endif // NATIVECAN_250KBPS CAN_cfg.tx_pin_id = CAN_TX_PIN; CAN_cfg.rx_pin_id = CAN_RX_PIN; CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t)); @@ -459,7 +460,7 @@ void init_CAN() { #ifdef CAN_ADDON #ifdef DEBUG_VIA_USB Serial.println("Dual CAN Bus (ESP32+MCP2515) selected"); -#endif +#endif // DEBUG_VIA_USB gBuffer.initWithSize(25); SPI.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); ACAN2515Settings settings(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s @@ -468,28 +469,28 @@ void init_CAN() { if (errorCodeMCP == 0) { #ifdef DEBUG_VIA_USB Serial.println("Can ok"); -#endif +#endif // DEBUG_VIA_USB } else { #ifdef DEBUG_VIA_USB Serial.print("Error Can: 0x"); Serial.println(errorCodeMCP, HEX); -#endif +#endif // DEBUG_VIA_USB set_event(EVENT_CANMCP_INIT_FAILURE, (uint8_t)errorCodeMCP); } -#endif +#endif // CAN_ADDON #ifdef CANFD_ADDON #ifdef DEBUG_VIA_USB Serial.println("CAN FD add-on (ESP32+MCP2517) selected"); -#endif +#endif // DEBUG_VIA_USB SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN settings.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD -#else +#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN settings.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD -#endif +#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN const uint32_t errorCode = canfd.begin(settings, [] { canfd.isr(); }); canfd.poll(); if (errorCode == 0) { @@ -510,15 +511,15 @@ void init_CAN() { Serial.print("Arbitration Sample point: "); Serial.print(settings.arbitrationSamplePointFromBitStart()); Serial.println("%"); -#endif +#endif // DEBUG_VIA_USB } else { #ifdef DEBUG_VIA_USB Serial.print("CAN-FD Configuration error 0x"); Serial.println(errorCode, HEX); -#endif +#endif // DEBUG_VIA_USB set_event(EVENT_CANFD_INIT_FAILURE, (uint8_t)errorCode); } -#endif +#endif // CANFD_ADDON } void init_contactors() { @@ -539,18 +540,18 @@ void init_contactors() { #endif // Precharge never has PWM regardless of setting pinMode(PRECHARGE_PIN, OUTPUT); set(PRECHARGE_PIN, OFF); -#endif //CONTACTOR_CONTROL +#endif // CONTACTOR_CONTROL #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY pinMode(SECOND_POSITIVE_CONTACTOR_PIN, OUTPUT); set(SECOND_POSITIVE_CONTACTOR_PIN, OFF); pinMode(SECOND_NEGATIVE_CONTACTOR_PIN, OUTPUT); set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); -#endif //CONTACTOR_CONTROL_DOUBLE_BATTERY +#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY // Init BMS contactor #ifdef HW_STARK // TODO: Rewrite this so LilyGo can also handle this BMS contactor pinMode(BMS_POWER, OUTPUT); digitalWrite(BMS_POWER, HIGH); -#endif //HW_STARK +#endif // HW_STARK } void init_rs485() { @@ -558,24 +559,23 @@ void init_rs485() { #ifdef RS485_EN_PIN pinMode(RS485_EN_PIN, OUTPUT); digitalWrite(RS485_EN_PIN, HIGH); -#endif +#endif // RS485_EN_PIN #ifdef RS485_SE_PIN pinMode(RS485_SE_PIN, OUTPUT); digitalWrite(RS485_SE_PIN, HIGH); -#endif +#endif // RS485_SE_PIN #ifdef PIN_5V_EN pinMode(PIN_5V_EN, OUTPUT); digitalWrite(PIN_5V_EN, HIGH); -#endif +#endif // PIN_5V_EN #ifdef RS485_INVERTER_SELECTED Serial2.begin(57600, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); -#endif +#endif // RS485_INVERTER_SELECTED #ifdef MODBUS_INVERTER_SELECTED #ifdef BYD_MODBUS // Init Static data to the RTU Modbus handle_static_data_modbus_byd(); -#endif - +#endif // BYD_MODBUS // Init Serial2 connected to the RTU Modbus RTUutils::prepareHardwareSerial(Serial2); Serial2.begin(9600, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); @@ -586,11 +586,10 @@ void init_rs485() { MBserver.registerWorker(MBTCP_ID, R_W_MULT_REGISTERS, &FC23); // Start ModbusRTU background task MBserver.begin(Serial2, MODBUS_CORE); -#endif +#endif // MODBUS_INVERTER_SELECTED } #ifdef EQUIPMENT_STOP_BUTTON - void monitor_equipment_stop_button() { ButtonState changed_state = debounceButton(equipment_stop_button, timeSincePress); @@ -623,8 +622,7 @@ void init_equipment_stop_button() { // Initialize the debounced button with NC switch type and equipment_button_debounce_duration debounce time initDebouncedButton(equipment_stop_button, EQUIPMENT_STOP_PIN, NC, equipment_button_debounce_duration); } - -#endif +#endif // EQUIPMENT_STOP_BUTTON enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 void print_can_frame(CAN_frame frame, frameDirection msgDir); @@ -645,7 +643,7 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { Serial.print(" "); } Serial.println(""); -#endif //#DEBUG_CAN_DATA +#endif // DEBUG_CAN_DATA if (datalayer.system.info.can_logging_active) { // If user clicked on CAN Logging page in webserver, start recording char* message_string = datalayer.system.info.logged_can_messages; @@ -685,7 +683,7 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { #ifdef CANFD_ADDON // Functions -void receive_canfd() { // This section checks if we have a complete CAN-FD message incoming +void receive_canfd_addon() { // This section checks if we have a complete CAN-FD message incoming CANFDMessage frame; int count = 0; while (canfd.available() && count++ < 16) { @@ -701,7 +699,7 @@ void receive_canfd() { // This section checks if we have a complete CAN-FD mess receive_can(&rx_frame, CANFD_NATIVE); } } -#endif +#endif // CANFD_ADDON void receive_can_native() { // This section checks if we have a complete CAN message incoming on native CAN port CAN_frame_t rx_frame_native; @@ -726,7 +724,6 @@ void send_can() { if (!allowed_to_send_CAN) { return; } - send_can_battery(); #ifdef CAN_INVERTER_SELECTED @@ -739,9 +736,9 @@ void send_can() { } #ifdef CAN_ADDON -void receive_can_addonMCP2515() { // This section checks if we have a complete CAN message incoming on add-on CAN port - CAN_frame rx_frame; // Struct with our CAN format - CANMessage MCP2515Frame; // Struct with ACAN2515 library format, needed to use the MCP2515 library +void receive_can_addon() { // This section checks if we have a complete CAN message incoming on add-on CAN port + CAN_frame rx_frame; // Struct with our CAN format + CANMessage MCP2515Frame; // Struct with ACAN2515 library format, needed to use the MCP2515 library if (can.available()) { can.receive(MCP2515Frame); @@ -779,16 +776,16 @@ void check_interconnect_available() { set_event(EVENT_VOLTAGE_DIFFERENCE, (uint8_t)(voltage_diff / 10)); } } -#endif //DOUBLE_BATTERY +#endif // DOUBLE_BATTERY void handle_contactors() { #ifdef BYD_SMA datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); -#endif +#endif // BYD_SMA #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY handle_contactors_battery2(); -#endif +#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY #ifdef CONTACTOR_CONTROL // First check if we have any active errors, incase we do, turn off the battery @@ -893,7 +890,7 @@ void handle_contactors_battery2() { datalayer.system.status.contactors_battery2_engaged = false; } } -#endif //CONTACTOR_CONTROL_DOUBLE_BATTERY +#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY void update_calculated_values() { /* Calculate allowed charge/discharge currents*/ @@ -983,7 +980,7 @@ void update_calculated_values() { } else { datalayer.battery2.status.reported_remaining_capacity_Wh = datalayer.battery2.status.remaining_capacity_Wh; } -#endif +#endif // DOUBLE_BATTERY } else { // soc_scaling_active == false. No SOC window wanted. Set scaled to same as real. datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc; @@ -1012,19 +1009,19 @@ void update_calculated_values() { datalayer.battery.status.reported_soc = datalayer.battery2.status.real_soc; datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery2.status.remaining_capacity_Wh; } -#endif //DOUBLE_BATTERY +#endif // DOUBLE_BATTERY } void update_values_inverter() { #ifdef CAN_INVERTER_SELECTED update_values_can_inverter(); -#endif +#endif // CAN_INVERTER_SELECTED #ifdef MODBUS_INVERTER_SELECTED update_modbus_registers_inverter(); -#endif +#endif // CAN_INVERTER_SELECTED #ifdef RS485_INVERTER_SELECTED update_RS485_registers_inverter(); -#endif +#endif // CAN_INVERTER_SELECTED } #if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) @@ -1042,12 +1039,12 @@ void runSerialDataLink() { #endif } } -#endif +#endif // SERIAL_LINK_RECEIVER || SERIAL_LINK_TRANSMITTER void init_serialDataLink() { #if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) Serial2.begin(SERIAL_LINK_BAUDRATE, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); -#endif +#endif // SERIAL_LINK_RECEIVER || SERIAL_LINK_TRANSMITTER } void store_settings_equipment_stop() { From 83764aa17f16ba0af21a31540fe3a07732e5f267 Mon Sep 17 00:00:00 2001 From: lenvm Date: Fri, 13 Dec 2024 15:23:00 +0100 Subject: [PATCH 060/225] move CAN related functions from Software.ino to can communication folder --- Software/Software.ino | 319 +------------------ Software/src/communication/can/comm_can.cpp | 324 ++++++++++++++++++++ Software/src/communication/can/comm_can.h | 42 +++ Software/src/include.h | 2 +- 4 files changed, 368 insertions(+), 319 deletions(-) create mode 100644 Software/src/communication/can/comm_can.cpp create mode 100644 Software/src/communication/can/comm_can.h diff --git a/Software/Software.ino b/Software/Software.ino index a4e1e77f0..7f7e3e57f 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -11,6 +11,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "src/charger/CHARGERS.h" +#include "src/communication/can/comm_can.h" #include "src/datalayer/datalayer.h" #include "src/devboard/utils/events.h" #include "src/devboard/utils/led_handler.h" @@ -60,22 +61,6 @@ uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update in unsigned long previousMillis10ms = 0; unsigned long previousMillisUpdateVal = 0; -// CAN parameters -CAN_device_t CAN_cfg; // CAN Config -const int rx_queue_size = 10; // Receive Queue size -volatile bool send_ok = 0; - -#ifdef CAN_ADDON -#include "src/lib/pierremolinaro-acan2515/ACAN2515.h" -static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h -ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT); -static ACAN2515_Buffer16 gBuffer; -#endif //CAN_ADDON -#ifdef CANFD_ADDON -#include "src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" -ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); -#endif //CANFD_ADDON - // ModbusRTU parameters #ifdef MODBUS_INVERTER_SELECTED #define MB_RTU_NUM_VALUES 13100 @@ -441,87 +426,6 @@ void init_stored_settings() { settings.end(); } -void init_CAN() { -// CAN pins -#ifdef CAN_SE_PIN - pinMode(CAN_SE_PIN, OUTPUT); - digitalWrite(CAN_SE_PIN, LOW); -#endif // CAN_SE_PIN - CAN_cfg.speed = CAN_SPEED_500KBPS; -#ifdef NATIVECAN_250KBPS // Some component is requesting lower CAN speed - CAN_cfg.speed = CAN_SPEED_250KBPS; -#endif // NATIVECAN_250KBPS - CAN_cfg.tx_pin_id = CAN_TX_PIN; - CAN_cfg.rx_pin_id = CAN_RX_PIN; - CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t)); - // Init CAN Module - ESP32Can.CANInit(); - -#ifdef CAN_ADDON -#ifdef DEBUG_VIA_USB - Serial.println("Dual CAN Bus (ESP32+MCP2515) selected"); -#endif // DEBUG_VIA_USB - gBuffer.initWithSize(25); - SPI.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); - ACAN2515Settings settings(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s - settings.mRequestedMode = ACAN2515Settings::NormalMode; - const uint16_t errorCodeMCP = can.begin(settings, [] { can.isr(); }); - if (errorCodeMCP == 0) { -#ifdef DEBUG_VIA_USB - Serial.println("Can ok"); -#endif // DEBUG_VIA_USB - } else { -#ifdef DEBUG_VIA_USB - Serial.print("Error Can: 0x"); - Serial.println(errorCodeMCP, HEX); -#endif // DEBUG_VIA_USB - set_event(EVENT_CANMCP_INIT_FAILURE, (uint8_t)errorCodeMCP); - } -#endif // CAN_ADDON - -#ifdef CANFD_ADDON -#ifdef DEBUG_VIA_USB - Serial.println("CAN FD add-on (ESP32+MCP2517) selected"); -#endif // DEBUG_VIA_USB - SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); - ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, - DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s -#ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN - settings.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD -#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN - settings.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD -#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN - const uint32_t errorCode = canfd.begin(settings, [] { canfd.isr(); }); - canfd.poll(); - if (errorCode == 0) { -#ifdef DEBUG_VIA_USB - Serial.print("Bit Rate prescaler: "); - Serial.println(settings.mBitRatePrescaler); - Serial.print("Arbitration Phase segment 1: "); - Serial.println(settings.mArbitrationPhaseSegment1); - Serial.print("Arbitration Phase segment 2: "); - Serial.println(settings.mArbitrationPhaseSegment2); - Serial.print("Arbitration SJW:"); - Serial.println(settings.mArbitrationSJW); - Serial.print("Actual Arbitration Bit Rate: "); - Serial.print(settings.actualArbitrationBitRate()); - Serial.println(" bit/s"); - Serial.print("Exact Arbitration Bit Rate ? "); - Serial.println(settings.exactArbitrationBitRate() ? "yes" : "no"); - Serial.print("Arbitration Sample point: "); - Serial.print(settings.arbitrationSamplePointFromBitStart()); - Serial.println("%"); -#endif // DEBUG_VIA_USB - } else { -#ifdef DEBUG_VIA_USB - Serial.print("CAN-FD Configuration error 0x"); - Serial.println(errorCode, HEX); -#endif // DEBUG_VIA_USB - set_event(EVENT_CANFD_INIT_FAILURE, (uint8_t)errorCode); - } -#endif // CANFD_ADDON -} - void init_contactors() { // Init contactor pins #ifdef CONTACTOR_CONTROL @@ -624,138 +528,6 @@ void init_equipment_stop_button() { } #endif // EQUIPMENT_STOP_BUTTON -enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 -void print_can_frame(CAN_frame frame, frameDirection msgDir); -void print_can_frame(CAN_frame frame, frameDirection msgDir) { -#ifdef DEBUG_CAN_DATA // If enabled in user settings, print out the CAN messages via USB - uint8_t i = 0; - Serial.print("("); - Serial.print(millis() / 1000.0); - (msgDir == MSG_RX) ? Serial.print(") RX0 ") : Serial.print(") TX1 "); - Serial.print(frame.ID, HEX); - Serial.print(" ["); - Serial.print(frame.DLC); - Serial.print("] "); - for (i = 0; i < frame.DLC; i++) { - Serial.print(frame.data.u8[i] < 16 ? "0" : ""); - Serial.print(frame.data.u8[i], HEX); - if (i < frame.DLC - 1) - Serial.print(" "); - } - Serial.println(""); -#endif // DEBUG_CAN_DATA - - if (datalayer.system.info.can_logging_active) { // If user clicked on CAN Logging page in webserver, start recording - 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); - - if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { - // Not enough space, reset and start from the beginning - offset = 0; - } - unsigned long currentTime = millis(); - // Add timestamp - 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 ID and DLC - offset += snprintf(message_string + offset, message_string_size - offset, "%X [%u] ", frame.ID, frame.DLC); - - // Add data bytes - for (uint8_t i = 0; i < frame.DLC; i++) { - if (i < frame.DLC - 1) { - offset += snprintf(message_string + offset, message_string_size - offset, "%02X ", frame.data.u8[i]); - } else { - offset += snprintf(message_string + offset, message_string_size - offset, "%02X", frame.data.u8[i]); - } - } - // Add linebreak - offset += snprintf(message_string + offset, message_string_size - offset, "\n"); - - datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer - } -} - -#ifdef CANFD_ADDON -// Functions -void receive_canfd_addon() { // This section checks if we have a complete CAN-FD message incoming - CANFDMessage frame; - int count = 0; - while (canfd.available() && count++ < 16) { - canfd.receive(frame); - - CAN_frame rx_frame; - rx_frame.ID = frame.id; - rx_frame.ext_ID = frame.ext; - rx_frame.DLC = frame.len; - memcpy(rx_frame.data.u8, frame.data, MIN(rx_frame.DLC, 64)); - //message incoming, pass it on to the handler - receive_can(&rx_frame, CANFD_ADDON_MCP2518); - receive_can(&rx_frame, CANFD_NATIVE); - } -} -#endif // CANFD_ADDON - -void receive_can_native() { // This section checks if we have a complete CAN message incoming on native CAN port - CAN_frame_t rx_frame_native; - if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame_native, 0) == pdTRUE) { - CAN_frame rx_frame; - rx_frame.ID = rx_frame_native.MsgID; - if (rx_frame_native.FIR.B.FF == CAN_frame_std) { - rx_frame.ext_ID = false; - } else { //CAN_frame_ext == 1 - rx_frame.ext_ID = true; - } - rx_frame.DLC = rx_frame_native.FIR.B.DLC; - for (uint8_t i = 0; i < rx_frame.DLC && i < 8; i++) { - rx_frame.data.u8[i] = rx_frame_native.data.u8[i]; - } - //message incoming, pass it on to the handler - receive_can(&rx_frame, CAN_NATIVE); - } -} - -void send_can() { - if (!allowed_to_send_CAN) { - return; - } - send_can_battery(); - -#ifdef CAN_INVERTER_SELECTED - send_can_inverter(); -#endif // CAN_INVERTER_SELECTED - -#ifdef CHARGER_SELECTED - send_can_charger(); -#endif // CHARGER_SELECTED -} - -#ifdef CAN_ADDON -void receive_can_addon() { // This section checks if we have a complete CAN message incoming on add-on CAN port - CAN_frame rx_frame; // Struct with our CAN format - CANMessage MCP2515Frame; // Struct with ACAN2515 library format, needed to use the MCP2515 library - - if (can.available()) { - can.receive(MCP2515Frame); - - rx_frame.ID = MCP2515Frame.id; - rx_frame.ext_ID = MCP2515Frame.ext ? CAN_frame_ext : CAN_frame_std; - rx_frame.DLC = MCP2515Frame.len; - for (uint8_t i = 0; i < MCP2515Frame.len && i < 8; i++) { - rx_frame.data.u8[i] = MCP2515Frame.data[i]; - } - - //message incoming, pass it on to the handler - receive_can(&rx_frame, CAN_ADDON_MCP2515); - } -} -#endif // CAN_ADDON - #ifdef DOUBLE_BATTERY void check_interconnect_available() { if (datalayer.battery.status.voltage_dV == 0 || datalayer.battery2.status.voltage_dV == 0) { @@ -1175,92 +947,3 @@ void check_reset_reason() { break; } } - -void transmit_can(CAN_frame* tx_frame, int interface) { - if (!allowed_to_send_CAN) { - return; - } - print_can_frame(*tx_frame, frameDirection(MSG_TX)); - - switch (interface) { - case CAN_NATIVE: - CAN_frame_t frame; - frame.MsgID = tx_frame->ID; - frame.FIR.B.FF = tx_frame->ext_ID ? CAN_frame_ext : CAN_frame_std; - frame.FIR.B.DLC = tx_frame->DLC; - frame.FIR.B.RTR = CAN_no_RTR; - for (uint8_t i = 0; i < tx_frame->DLC; i++) { - frame.data.u8[i] = tx_frame->data.u8[i]; - } - ESP32Can.CANWriteFrame(&frame); - break; - case CAN_ADDON_MCP2515: { -#ifdef CAN_ADDON - //Struct with ACAN2515 library format, needed to use the MCP2515 library for CAN2 - CANMessage MCP2515Frame; - MCP2515Frame.id = tx_frame->ID; - MCP2515Frame.ext = tx_frame->ext_ID ? CAN_frame_ext : CAN_frame_std; - MCP2515Frame.len = tx_frame->DLC; - MCP2515Frame.rtr = false; - for (uint8_t i = 0; i < MCP2515Frame.len; i++) { - MCP2515Frame.data[i] = tx_frame->data.u8[i]; - } - can.tryToSend(MCP2515Frame); -#else // Interface not compiled, and settings try to use it - set_event(EVENT_INTERFACE_MISSING, interface); -#endif //CAN_ADDON - } break; - case CANFD_NATIVE: - case CANFD_ADDON_MCP2518: { -#ifdef CANFD_ADDON - CANFDMessage MCP2518Frame; - if (tx_frame->FD) { - MCP2518Frame.type = CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH; - } else { //Classic CAN message - MCP2518Frame.type = CANFDMessage::CAN_DATA; - } - MCP2518Frame.id = tx_frame->ID; - MCP2518Frame.ext = tx_frame->ext_ID ? CAN_frame_ext : CAN_frame_std; - MCP2518Frame.len = tx_frame->DLC; - for (uint8_t i = 0; i < MCP2518Frame.len; i++) { - MCP2518Frame.data[i] = tx_frame->data.u8[i]; - } - send_ok = canfd.tryToSend(MCP2518Frame); - if (!send_ok) { - set_event(EVENT_CANFD_BUFFER_FULL, interface); - } -#else // Interface not compiled, and settings try to use it - set_event(EVENT_INTERFACE_MISSING, interface); -#endif //CANFD_ADDON - } break; - default: - // Invalid interface sent with function call. TODO: Raise event that coders messed up - break; - } -} -void receive_can(CAN_frame* rx_frame, int interface) { - - print_can_frame(*rx_frame, frameDirection(MSG_RX)); - - if (interface == can_config.battery) { - receive_can_battery(*rx_frame); -#ifdef CHADEMO_BATTERY - ISA_handleFrame(rx_frame); -#endif - } - if (interface == can_config.inverter) { -#ifdef CAN_INVERTER_SELECTED - receive_can_inverter(*rx_frame); -#endif - } - if (interface == can_config.battery_double) { -#ifdef DOUBLE_BATTERY - receive_can_battery2(*rx_frame); -#endif - } - if (interface == can_config.charger) { -#ifdef CHARGER_SELECTED - receive_can_charger(*rx_frame); -#endif - } -} diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp new file mode 100644 index 000000000..098d8cbe3 --- /dev/null +++ b/Software/src/communication/can/comm_can.cpp @@ -0,0 +1,324 @@ +#include "comm_can.h" +#include "../../include.h" + +// Parameters + +CAN_device_t CAN_cfg; // CAN Config +const int rx_queue_size = 10; // Receive Queue size +volatile bool send_ok = 0; + +#ifdef CAN_ADDON +static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h +ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT); +static ACAN2515_Buffer16 gBuffer; +#endif //CAN_ADDON +#ifdef CANFD_ADDON +ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); +#endif //CANFD_ADDON + +// Initialization functions + +void init_CAN() { +// CAN pins +#ifdef CAN_SE_PIN + pinMode(CAN_SE_PIN, OUTPUT); + digitalWrite(CAN_SE_PIN, LOW); +#endif // CAN_SE_PIN + CAN_cfg.speed = CAN_SPEED_500KBPS; +#ifdef NATIVECAN_250KBPS // Some component is requesting lower CAN speed + CAN_cfg.speed = CAN_SPEED_250KBPS; +#endif // NATIVECAN_250KBPS + CAN_cfg.tx_pin_id = CAN_TX_PIN; + CAN_cfg.rx_pin_id = CAN_RX_PIN; + CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t)); + // Init CAN Module + ESP32Can.CANInit(); + +#ifdef CAN_ADDON +#ifdef DEBUG_VIA_USB + Serial.println("Dual CAN Bus (ESP32+MCP2515) selected"); +#endif // DEBUG_VIA_USB + gBuffer.initWithSize(25); + SPI.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); + ACAN2515Settings settings(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s + settings.mRequestedMode = ACAN2515Settings::NormalMode; + const uint16_t errorCodeMCP = can.begin(settings, [] { can.isr(); }); + if (errorCodeMCP == 0) { +#ifdef DEBUG_VIA_USB + Serial.println("Can ok"); +#endif // DEBUG_VIA_USB + } else { +#ifdef DEBUG_VIA_USB + Serial.print("Error Can: 0x"); + Serial.println(errorCodeMCP, HEX); +#endif // DEBUG_VIA_USB + set_event(EVENT_CANMCP_INIT_FAILURE, (uint8_t)errorCodeMCP); + } +#endif // CAN_ADDON + +#ifdef CANFD_ADDON +#ifdef DEBUG_VIA_USB + Serial.println("CAN FD add-on (ESP32+MCP2517) selected"); +#endif // DEBUG_VIA_USB + SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); + ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, + DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s +#ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN + settings.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD +#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN + settings.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD +#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN + const uint32_t errorCode = canfd.begin(settings, [] { canfd.isr(); }); + canfd.poll(); + if (errorCode == 0) { +#ifdef DEBUG_VIA_USB + Serial.print("Bit Rate prescaler: "); + Serial.println(settings.mBitRatePrescaler); + Serial.print("Arbitration Phase segment 1: "); + Serial.println(settings.mArbitrationPhaseSegment1); + Serial.print("Arbitration Phase segment 2: "); + Serial.println(settings.mArbitrationPhaseSegment2); + Serial.print("Arbitration SJW:"); + Serial.println(settings.mArbitrationSJW); + Serial.print("Actual Arbitration Bit Rate: "); + Serial.print(settings.actualArbitrationBitRate()); + Serial.println(" bit/s"); + Serial.print("Exact Arbitration Bit Rate ? "); + Serial.println(settings.exactArbitrationBitRate() ? "yes" : "no"); + Serial.print("Arbitration Sample point: "); + Serial.print(settings.arbitrationSamplePointFromBitStart()); + Serial.println("%"); +#endif // DEBUG_VIA_USB + } else { +#ifdef DEBUG_VIA_USB + Serial.print("CAN-FD Configuration error 0x"); + Serial.println(errorCode, HEX); +#endif // DEBUG_VIA_USB + set_event(EVENT_CANFD_INIT_FAILURE, (uint8_t)errorCode); + } +#endif // CANFD_ADDON +} + +// Transmit functions + +void transmit_can(CAN_frame* tx_frame, int interface) { + if (!allowed_to_send_CAN) { + return; + } + print_can_frame(*tx_frame, frameDirection(MSG_TX)); + + switch (interface) { + case CAN_NATIVE: + CAN_frame_t frame; + frame.MsgID = tx_frame->ID; + frame.FIR.B.FF = tx_frame->ext_ID ? CAN_frame_ext : CAN_frame_std; + frame.FIR.B.DLC = tx_frame->DLC; + frame.FIR.B.RTR = CAN_no_RTR; + for (uint8_t i = 0; i < tx_frame->DLC; i++) { + frame.data.u8[i] = tx_frame->data.u8[i]; + } + ESP32Can.CANWriteFrame(&frame); + break; + case CAN_ADDON_MCP2515: { +#ifdef CAN_ADDON + //Struct with ACAN2515 library format, needed to use the MCP2515 library for CAN2 + CANMessage MCP2515Frame; + MCP2515Frame.id = tx_frame->ID; + MCP2515Frame.ext = tx_frame->ext_ID ? CAN_frame_ext : CAN_frame_std; + MCP2515Frame.len = tx_frame->DLC; + MCP2515Frame.rtr = false; + for (uint8_t i = 0; i < MCP2515Frame.len; i++) { + MCP2515Frame.data[i] = tx_frame->data.u8[i]; + } + can.tryToSend(MCP2515Frame); +#else // Interface not compiled, and settings try to use it + set_event(EVENT_INTERFACE_MISSING, interface); +#endif //CAN_ADDON + } break; + case CANFD_NATIVE: + case CANFD_ADDON_MCP2518: { +#ifdef CANFD_ADDON + CANFDMessage MCP2518Frame; + if (tx_frame->FD) { + MCP2518Frame.type = CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH; + } else { //Classic CAN message + MCP2518Frame.type = CANFDMessage::CAN_DATA; + } + MCP2518Frame.id = tx_frame->ID; + MCP2518Frame.ext = tx_frame->ext_ID ? CAN_frame_ext : CAN_frame_std; + MCP2518Frame.len = tx_frame->DLC; + for (uint8_t i = 0; i < MCP2518Frame.len; i++) { + MCP2518Frame.data[i] = tx_frame->data.u8[i]; + } + send_ok = canfd.tryToSend(MCP2518Frame); + if (!send_ok) { + set_event(EVENT_CANFD_BUFFER_FULL, interface); + } +#else // Interface not compiled, and settings try to use it + set_event(EVENT_INTERFACE_MISSING, interface); +#endif //CANFD_ADDON + } break; + default: + // Invalid interface sent with function call. TODO: Raise event that coders messed up + break; + } +} + +void send_can() { + if (!allowed_to_send_CAN) { + return; + } + send_can_battery(); + +#ifdef CAN_INVERTER_SELECTED + send_can_inverter(); +#endif // CAN_INVERTER_SELECTED + +#ifdef CHARGER_SELECTED + send_can_charger(); +#endif // CHARGER_SELECTED +} + +// Receive functions + +void receive_can(CAN_frame* rx_frame, int interface) { + print_can_frame(*rx_frame, frameDirection(MSG_RX)); + + if (interface == can_config.battery) { + receive_can_battery(*rx_frame); +#ifdef CHADEMO_BATTERY + ISA_handleFrame(rx_frame); +#endif + } + if (interface == can_config.inverter) { +#ifdef CAN_INVERTER_SELECTED + receive_can_inverter(*rx_frame); +#endif + } + if (interface == can_config.battery_double) { +#ifdef DOUBLE_BATTERY + receive_can_battery2(*rx_frame); +#endif + } + if (interface == can_config.charger) { +#ifdef CHARGER_SELECTED + receive_can_charger(*rx_frame); +#endif + } +} + +#ifdef CANFD_ADDON +// Functions +void receive_canfd_addon() { // This section checks if we have a complete CAN-FD message incoming + CANFDMessage frame; + int count = 0; + while (canfd.available() && count++ < 16) { + canfd.receive(frame); + + CAN_frame rx_frame; + rx_frame.ID = frame.id; + rx_frame.ext_ID = frame.ext; + rx_frame.DLC = frame.len; + memcpy(rx_frame.data.u8, frame.data, MIN(rx_frame.DLC, 64)); + //message incoming, pass it on to the handler + receive_can(&rx_frame, CANFD_ADDON_MCP2518); + receive_can(&rx_frame, CANFD_NATIVE); + } +} +#endif // CANFD_ADDON + +void receive_can_native() { // This section checks if we have a complete CAN message incoming on native CAN port + CAN_frame_t rx_frame_native; + if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame_native, 0) == pdTRUE) { + CAN_frame rx_frame; + rx_frame.ID = rx_frame_native.MsgID; + if (rx_frame_native.FIR.B.FF == CAN_frame_std) { + rx_frame.ext_ID = false; + } else { //CAN_frame_ext == 1 + rx_frame.ext_ID = true; + } + rx_frame.DLC = rx_frame_native.FIR.B.DLC; + for (uint8_t i = 0; i < rx_frame.DLC && i < 8; i++) { + rx_frame.data.u8[i] = rx_frame_native.data.u8[i]; + } + //message incoming, pass it on to the handler + receive_can(&rx_frame, CAN_NATIVE); + } +} + +#ifdef CAN_ADDON +void receive_can_addon() { // This section checks if we have a complete CAN message incoming on add-on CAN port + CAN_frame rx_frame; // Struct with our CAN format + CANMessage MCP2515Frame; // Struct with ACAN2515 library format, needed to use the MCP2515 library + + if (can.available()) { + can.receive(MCP2515Frame); + + rx_frame.ID = MCP2515Frame.id; + rx_frame.ext_ID = MCP2515Frame.ext ? CAN_frame_ext : CAN_frame_std; + rx_frame.DLC = MCP2515Frame.len; + for (uint8_t i = 0; i < MCP2515Frame.len && i < 8; i++) { + rx_frame.data.u8[i] = MCP2515Frame.data[i]; + } + + //message incoming, pass it on to the handler + receive_can(&rx_frame, CAN_ADDON_MCP2515); + } +} +#endif // CAN_ADDON + +// Support functions +void print_can_frame(CAN_frame frame, frameDirection msgDir) { +#ifdef DEBUG_CAN_DATA // If enabled in user settings, print out the CAN messages via USB + uint8_t i = 0; + Serial.print("("); + Serial.print(millis() / 1000.0); + (msgDir == MSG_RX) ? Serial.print(") RX0 ") : Serial.print(") TX1 "); + Serial.print(frame.ID, HEX); + Serial.print(" ["); + Serial.print(frame.DLC); + Serial.print("] "); + for (i = 0; i < frame.DLC; i++) { + Serial.print(frame.data.u8[i] < 16 ? "0" : ""); + Serial.print(frame.data.u8[i], HEX); + if (i < frame.DLC - 1) + Serial.print(" "); + } + Serial.println(""); +#endif // DEBUG_CAN_DATA + + if (datalayer.system.info.can_logging_active) { // If user clicked on CAN Logging page in webserver, start recording + 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); + + if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { + // Not enough space, reset and start from the beginning + offset = 0; + } + unsigned long currentTime = millis(); + // Add timestamp + 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 ID and DLC + offset += snprintf(message_string + offset, message_string_size - offset, "%X [%u] ", frame.ID, frame.DLC); + + // Add data bytes + for (uint8_t i = 0; i < frame.DLC; i++) { + if (i < frame.DLC - 1) { + offset += snprintf(message_string + offset, message_string_size - offset, "%02X ", frame.data.u8[i]); + } else { + offset += snprintf(message_string + offset, message_string_size - offset, "%02X", frame.data.u8[i]); + } + } + // Add linebreak + offset += snprintf(message_string + offset, message_string_size - offset, "\n"); + + datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer + } +} diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h new file mode 100644 index 000000000..81c046f11 --- /dev/null +++ b/Software/src/communication/can/comm_can.h @@ -0,0 +1,42 @@ +#ifndef _COMM_CAN_H_ +#define _COMM_CAN_H_ + +#include "../../include.h" + +#include "../../datalayer/datalayer.h" +#include "../../devboard/utils/events.h" +#include "../../devboard/utils/value_mapping.h" +#include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" +#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#ifdef CAN_ADDON +#include "../../lib/pierremolinaro-acan2515/ACAN2515.h" +#endif //CAN_ADDON +#ifdef CANFD_ADDON +#include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" +#endif //CANFD_ADDON + +/** + * @brief Initialization function for CAN. + * + * @param[in] void + * + * @return void + */ +void init_CAN(); + +void transmit_can(); + +void send_can(); + +void receive_can(); + +void receive_canfd_addon(); + +void receive_can_native(); + +void receive_can_addon(); + +enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 +void print_can_frame(CAN_frame frame, frameDirection msgDir); + +#endif diff --git a/Software/src/include.h b/Software/src/include.h index 901056972..5d5520d88 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -24,7 +24,7 @@ #if defined(CAN_ADDON) && defined(CANFD_ADDON) // Check that user did not try to use dual can and fd-can on same hardware pins -#error CAN-FD AND DUAL-CAN CANNOT BE USED SIMULTANEOUSLY +#error CAN_ADDON AND CANFD_ADDON CANNOT BE USED SIMULTANEOUSLY #endif #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN From df6145f210552f35b8aa67fea4af2278b656ef07 Mon Sep 17 00:00:00 2001 From: lenvm Date: Fri, 13 Dec 2024 16:06:03 +0100 Subject: [PATCH 061/225] move RS485 related functions to rs485 folder and move Serial Link related function to seriallink folder --- Software/Software.ino | 71 +------------------ .../src/communication/rs485/comm_rs485.cpp | 51 +++++++++++++ Software/src/communication/rs485/comm_rs485.h | 12 ++++ .../seriallink/comm_seriallink.cpp | 35 +++++++++ .../seriallink/comm_seriallink.h | 10 +++ 5 files changed, 110 insertions(+), 69 deletions(-) create mode 100644 Software/src/communication/rs485/comm_rs485.cpp create mode 100644 Software/src/communication/rs485/comm_rs485.h create mode 100644 Software/src/communication/seriallink/comm_seriallink.cpp create mode 100644 Software/src/communication/seriallink/comm_seriallink.h diff --git a/Software/Software.ino b/Software/Software.ino index 7f7e3e57f..66a8614a1 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -12,6 +12,8 @@ #include "freertos/task.h" #include "src/charger/CHARGERS.h" #include "src/communication/can/comm_can.h" +#include "src/communication/rs485/comm_rs485.h" +#include "src/communication/seriallink/comm_seriallink.h" #include "src/datalayer/datalayer.h" #include "src/devboard/utils/events.h" #include "src/devboard/utils/led_handler.h" @@ -61,17 +63,6 @@ uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update in unsigned long previousMillis10ms = 0; unsigned long previousMillisUpdateVal = 0; -// ModbusRTU parameters -#ifdef MODBUS_INVERTER_SELECTED -#define MB_RTU_NUM_VALUES 13100 -uint16_t mbPV[MB_RTU_NUM_VALUES]; // Process variable memory -// Create a ModbusRTU server instance listening on Serial2 with 2000ms timeout -ModbusServerRTU MBserver(Serial2, 2000); -#endif -#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) -#define SERIAL_LINK_BAUDRATE 112500 -#endif - // Common charger parameters volatile float charger_setpoint_HV_VDC = 0.0f; volatile float charger_setpoint_HV_IDC = 0.0f; @@ -458,41 +449,6 @@ void init_contactors() { #endif // HW_STARK } -void init_rs485() { -// Set up Modbus RTU Server -#ifdef RS485_EN_PIN - pinMode(RS485_EN_PIN, OUTPUT); - digitalWrite(RS485_EN_PIN, HIGH); -#endif // RS485_EN_PIN -#ifdef RS485_SE_PIN - pinMode(RS485_SE_PIN, OUTPUT); - digitalWrite(RS485_SE_PIN, HIGH); -#endif // RS485_SE_PIN -#ifdef PIN_5V_EN - pinMode(PIN_5V_EN, OUTPUT); - digitalWrite(PIN_5V_EN, HIGH); -#endif // PIN_5V_EN -#ifdef RS485_INVERTER_SELECTED - Serial2.begin(57600, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); -#endif // RS485_INVERTER_SELECTED -#ifdef MODBUS_INVERTER_SELECTED -#ifdef BYD_MODBUS - // Init Static data to the RTU Modbus - handle_static_data_modbus_byd(); -#endif // BYD_MODBUS - // Init Serial2 connected to the RTU Modbus - RTUutils::prepareHardwareSerial(Serial2); - Serial2.begin(9600, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); - // Register served function code worker for server - MBserver.registerWorker(MBTCP_ID, READ_HOLD_REGISTER, &FC03); - MBserver.registerWorker(MBTCP_ID, WRITE_HOLD_REGISTER, &FC06); - MBserver.registerWorker(MBTCP_ID, WRITE_MULT_REGISTERS, &FC16); - MBserver.registerWorker(MBTCP_ID, R_W_MULT_REGISTERS, &FC23); - // Start ModbusRTU background task - MBserver.begin(Serial2, MODBUS_CORE); -#endif // MODBUS_INVERTER_SELECTED -} - #ifdef EQUIPMENT_STOP_BUTTON void monitor_equipment_stop_button() { @@ -796,29 +752,6 @@ void update_values_inverter() { #endif // CAN_INVERTER_SELECTED } -#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) -void runSerialDataLink() { - static unsigned long updateTime = 0; - unsigned long currentMillis = millis(); - - if ((currentMillis - updateTime) > 1) { //Every 2ms - updateTime = currentMillis; -#ifdef SERIAL_LINK_RECEIVER - manageSerialLinkReceiver(); -#endif -#ifdef SERIAL_LINK_TRANSMITTER - manageSerialLinkTransmitter(); -#endif - } -} -#endif // SERIAL_LINK_RECEIVER || SERIAL_LINK_TRANSMITTER - -void init_serialDataLink() { -#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) - Serial2.begin(SERIAL_LINK_BAUDRATE, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); -#endif // SERIAL_LINK_RECEIVER || SERIAL_LINK_TRANSMITTER -} - void store_settings_equipment_stop() { settings.begin("batterySettings", false); settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active); diff --git a/Software/src/communication/rs485/comm_rs485.cpp b/Software/src/communication/rs485/comm_rs485.cpp new file mode 100644 index 000000000..feec33aa5 --- /dev/null +++ b/Software/src/communication/rs485/comm_rs485.cpp @@ -0,0 +1,51 @@ +#include "comm_rs485.h" +#include "../../include.h" + +// Parameters + +#ifdef MODBUS_INVERTER_SELECTED +#define MB_RTU_NUM_VALUES 13100 +uint16_t mbPV[MB_RTU_NUM_VALUES]; // Process variable memory +// Create a ModbusRTU server instance listening on Serial2 with 2000ms timeout +ModbusServerRTU MBserver(Serial2, 2000); +#endif +#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) +#define SERIAL_LINK_BAUDRATE 112500 +#endif + +// Initialization functions + +void init_rs485() { +// Set up Modbus RTU Server +#ifdef RS485_EN_PIN + pinMode(RS485_EN_PIN, OUTPUT); + digitalWrite(RS485_EN_PIN, HIGH); +#endif // RS485_EN_PIN +#ifdef RS485_SE_PIN + pinMode(RS485_SE_PIN, OUTPUT); + digitalWrite(RS485_SE_PIN, HIGH); +#endif // RS485_SE_PIN +#ifdef PIN_5V_EN + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, HIGH); +#endif // PIN_5V_EN +#ifdef RS485_INVERTER_SELECTED + Serial2.begin(57600, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); +#endif // RS485_INVERTER_SELECTED +#ifdef MODBUS_INVERTER_SELECTED +#ifdef BYD_MODBUS + // Init Static data to the RTU Modbus + handle_static_data_modbus_byd(); +#endif // BYD_MODBUS + // Init Serial2 connected to the RTU Modbus + RTUutils::prepareHardwareSerial(Serial2); + Serial2.begin(9600, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); + // Register served function code worker for server + MBserver.registerWorker(MBTCP_ID, READ_HOLD_REGISTER, &FC03); + MBserver.registerWorker(MBTCP_ID, WRITE_HOLD_REGISTER, &FC06); + MBserver.registerWorker(MBTCP_ID, WRITE_MULT_REGISTERS, &FC16); + MBserver.registerWorker(MBTCP_ID, R_W_MULT_REGISTERS, &FC23); + // Start ModbusRTU background task + MBserver.begin(Serial2, MODBUS_CORE); +#endif // MODBUS_INVERTER_SELECTED +} diff --git a/Software/src/communication/rs485/comm_rs485.h b/Software/src/communication/rs485/comm_rs485.h new file mode 100644 index 000000000..d4fd97c26 --- /dev/null +++ b/Software/src/communication/rs485/comm_rs485.h @@ -0,0 +1,12 @@ +#ifndef _COMM_RS485_H_ +#define _COMM_RS485_H_ + +#include "../../include.h" + +#include "../../lib/eModbus-eModbus/Logging.h" +#include "../../lib/eModbus-eModbus/ModbusServerRTU.h" +#include "../../lib/eModbus-eModbus/scripts/mbServerFCs.h" + +void init_rs485(); + +#endif diff --git a/Software/src/communication/seriallink/comm_seriallink.cpp b/Software/src/communication/seriallink/comm_seriallink.cpp new file mode 100644 index 000000000..a08bb3c9d --- /dev/null +++ b/Software/src/communication/seriallink/comm_seriallink.cpp @@ -0,0 +1,35 @@ +#include "comm_seriallink.h" +#include "../../include.h" + +// Parameters + +#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) +#define SERIAL_LINK_BAUDRATE 112500 +#endif + +// Initialization functions + +void init_serialDataLink() { +#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) + Serial2.begin(SERIAL_LINK_BAUDRATE, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); +#endif // SERIAL_LINK_RECEIVER || SERIAL_LINK_TRANSMITTER +} + +// Main functions + +#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) +void runSerialDataLink() { + static unsigned long updateTime = 0; + unsigned long currentMillis = millis(); + + if ((currentMillis - updateTime) > 1) { //Every 2ms + updateTime = currentMillis; +#ifdef SERIAL_LINK_RECEIVER + manageSerialLinkReceiver(); +#endif +#ifdef SERIAL_LINK_TRANSMITTER + manageSerialLinkTransmitter(); +#endif + } +} +#endif // SERIAL_LINK_RECEIVER || SERIAL_LINK_TRANSMITTER diff --git a/Software/src/communication/seriallink/comm_seriallink.h b/Software/src/communication/seriallink/comm_seriallink.h new file mode 100644 index 000000000..277165aa0 --- /dev/null +++ b/Software/src/communication/seriallink/comm_seriallink.h @@ -0,0 +1,10 @@ +#ifndef _COMM_SERIALLINK_H_ +#define _COMM_SERIALLINK_H_ + +#include "../../include.h" + +void init_serialDataLink(); + +void runSerialDataLink(); + +#endif From 624926b552a5ab31cd06cd676af3f62a65cce252 Mon Sep 17 00:00:00 2001 From: lenvm Date: Fri, 13 Dec 2024 16:35:42 +0100 Subject: [PATCH 062/225] move contactor control related functions from Software.ino to comm_contactorcontrol folder --- Software/Software.ino | 204 +----------------- .../comm_contactorcontrol.cpp | 204 ++++++++++++++++++ .../contactorcontrol/comm_contactorcontrol.h | 15 ++ 3 files changed, 220 insertions(+), 203 deletions(-) create mode 100644 Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp create mode 100644 Software/src/communication/contactorcontrol/comm_contactorcontrol.h diff --git a/Software/Software.ino b/Software/Software.ino index 66a8614a1..b49422211 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -12,6 +12,7 @@ #include "freertos/task.h" #include "src/charger/CHARGERS.h" #include "src/communication/can/comm_can.h" +#include "src/communication/contactorcontrol/comm_contactorcontrol.h" #include "src/communication/rs485/comm_rs485.h" #include "src/communication/seriallink/comm_seriallink.h" #include "src/datalayer/datalayer.h" @@ -44,12 +45,6 @@ #endif // MQTT #endif // WIFI -#ifndef CONTACTOR_CONTROL -#ifdef PWM_CONTACTOR_CONTROL -#error CONTACTOR_CONTROL needs to be enabled for PWM_CONTACTOR_CONTROL -#endif -#endif - #ifdef EQUIPMENT_STOP_BUTTON #include "src/devboard/utils/debounce_button.h" #endif @@ -89,52 +84,6 @@ MyTimer loop_task_timer_10s(INTERVAL_10_S); MyTimer check_pause_2s(INTERVAL_2_S); -// Contactor parameters -#ifdef CONTACTOR_CONTROL -enum State { DISCONNECTED, START_PRECHARGE, PRECHARGE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED }; -State contactorStatus = DISCONNECTED; - -#define ON 1 -#define OFF 0 - -#ifdef NC_CONTACTORS //Normally closed contactors use inverted logic -#undef ON -#define ON 0 -#undef OFF -#define OFF 1 -#endif //NC_CONTACTORS - -#define MAX_ALLOWED_FAULT_TICKS 1000 -#define NEGATIVE_CONTACTOR_TIME_MS \ - 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 -#define PWM_ON_DUTY 1023 -#define PWM_Positive_Channel 0 -#define PWM_Negative_Channel 1 -unsigned long prechargeStartTime = 0; -unsigned long negativeStartTime = 0; -unsigned long prechargeCompletedTime = 0; -unsigned long timeSpentInFaultedMode = 0; -#endif - -void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) { -#ifdef PWM_CONTACTOR_CONTROL - if (pwm_freq != 0xFFFF) { - ledcWrite(pin, pwm_freq); - return; - } -#endif - if (direction == 1) { - digitalWrite(pin, HIGH); - } else { // 0 - digitalWrite(pin, LOW); - } -} #ifdef EQUIPMENT_STOP_BUTTON const unsigned long equipment_button_long_press_duration = @@ -362,12 +311,7 @@ void init_stored_settings() { //always save the equipment stop status settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active); -<<<<<<< HEAD - -#endif //LOAD_SAVED_SETTINGS_ON_BOOT -======= #endif // LOAD_SAVED_SETTINGS_ON_BOOT ->>>>>>> f4051ff (add comments for #endif statements) #ifdef WIFI char tempSSIDstring[63]; // Allocate buffer with sufficient size @@ -417,38 +361,6 @@ void init_stored_settings() { settings.end(); } -void init_contactors() { - // Init contactor pins -#ifdef CONTACTOR_CONTROL -#ifdef PWM_CONTACTOR_CONTROL - // Setup PWM Channel Frequency and Resolution - ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Positive_Channel); - ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Negative_Channel); - // Set all pins OFF (0% PWM) - ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY); - ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY); -#else //Normal CONTACTOR_CONTROL - pinMode(POSITIVE_CONTACTOR_PIN, OUTPUT); - set(POSITIVE_CONTACTOR_PIN, OFF); - pinMode(NEGATIVE_CONTACTOR_PIN, OUTPUT); - set(NEGATIVE_CONTACTOR_PIN, OFF); -#endif // Precharge never has PWM regardless of setting - pinMode(PRECHARGE_PIN, OUTPUT); - set(PRECHARGE_PIN, OFF); -#endif // CONTACTOR_CONTROL -#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY - pinMode(SECOND_POSITIVE_CONTACTOR_PIN, OUTPUT); - set(SECOND_POSITIVE_CONTACTOR_PIN, OFF); - pinMode(SECOND_NEGATIVE_CONTACTOR_PIN, OUTPUT); - set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); -#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY -// Init BMS contactor -#ifdef HW_STARK // TODO: Rewrite this so LilyGo can also handle this BMS contactor - pinMode(BMS_POWER, OUTPUT); - digitalWrite(BMS_POWER, HIGH); -#endif // HW_STARK -} - #ifdef EQUIPMENT_STOP_BUTTON void monitor_equipment_stop_button() { @@ -506,120 +418,6 @@ void check_interconnect_available() { } #endif // DOUBLE_BATTERY -void handle_contactors() { -#ifdef BYD_SMA - datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); -#endif // BYD_SMA - -#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY - handle_contactors_battery2(); -#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY - -#ifdef CONTACTOR_CONTROL - // First check if we have any active errors, incase we do, turn off the battery - if (datalayer.battery.status.bms_status == FAULT) { - timeSpentInFaultedMode++; - } else { - timeSpentInFaultedMode = 0; - } - - //handle contactor control SHUTDOWN_REQUESTED - if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) { - contactorStatus = SHUTDOWN_REQUESTED; - } - - if (contactorStatus == SHUTDOWN_REQUESTED) { - set(PRECHARGE_PIN, OFF); - set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY); - set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY); - set_event(EVENT_ERROR_OPEN_CONTACTOR, 0); - datalayer.system.status.contactors_engaged = false; - return; // A fault scenario latches the contactor control. It is not possible to recover without a powercycle (and investigation why fault occured) - } - - // After that, check if we are OK to start turning on the battery - if (contactorStatus == DISCONNECTED) { - set(PRECHARGE_PIN, OFF); - set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY); - set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY); - - if (datalayer.system.status.battery_allows_contactor_closing && - datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active) { - contactorStatus = START_PRECHARGE; - } - } - - // In case the inverter requests contactors to open, set the state accordingly - if (contactorStatus == COMPLETED) { - //Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable) - if (!datalayer.system.status.inverter_allows_contactor_closing || datalayer.system.settings.equipment_stop_active) { - contactorStatus = DISCONNECTED; - } - // Skip running the state machine below if it has already completed - return; - } - - unsigned long currentTime = millis(); - - if (currentTime < INTERVAL_10_S) { - // Skip running the state machine before system has started up. - // Gives the system some time to detect any faults from battery before blindly just engaging the contactors - return; - } - - // Handle actual state machine. This first turns on Negative, then Precharge, then Positive, and finally turns OFF precharge - switch (contactorStatus) { - case START_PRECHARGE: - set(NEGATIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY); - prechargeStartTime = currentTime; - contactorStatus = PRECHARGE; - break; - - case PRECHARGE: - if (currentTime - prechargeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) { - set(PRECHARGE_PIN, ON); - negativeStartTime = currentTime; - contactorStatus = POSITIVE; - } - break; - - case POSITIVE: - if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) { - set(POSITIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY); - prechargeCompletedTime = currentTime; - contactorStatus = PRECHARGE_OFF; - } - break; - - case PRECHARGE_OFF: - if (currentTime - prechargeCompletedTime >= PRECHARGE_COMPLETED_TIME_MS) { - set(PRECHARGE_PIN, OFF); - set(NEGATIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY); - set(POSITIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY); - contactorStatus = COMPLETED; - datalayer.system.status.contactors_engaged = true; - } - break; - default: - break; - } -#endif // CONTACTOR_CONTROL -} - -#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY -void handle_contactors_battery2() { - if ((contactorStatus == COMPLETED) && datalayer.system.status.battery2_allows_contactor_closing) { - set(SECOND_NEGATIVE_CONTACTOR_PIN, ON); - set(SECOND_POSITIVE_CONTACTOR_PIN, ON); - datalayer.system.status.contactors_battery2_engaged = true; - } else { // Closing contactors on secondary battery not allowed - set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); - set(SECOND_POSITIVE_CONTACTOR_PIN, OFF); - datalayer.system.status.contactors_battery2_engaged = false; - } -} -#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY - void update_calculated_values() { /* Calculate allowed charge/discharge currents*/ if (datalayer.battery.status.voltage_dV > 10) { diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp new file mode 100644 index 000000000..c09e6c171 --- /dev/null +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -0,0 +1,204 @@ +#include "comm_contactorcontrol.h" +#include "../../include.h" + +// Parameters +#ifndef CONTACTOR_CONTROL +#ifdef PWM_CONTACTOR_CONTROL +#error CONTACTOR_CONTROL needs to be enabled for PWM_CONTACTOR_CONTROL +#endif +#endif + +#ifdef CONTACTOR_CONTROL +enum State { DISCONNECTED, START_PRECHARGE, PRECHARGE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED }; +State contactorStatus = DISCONNECTED; + +#define ON 1 +#define OFF 0 + +#ifdef NC_CONTACTORS //Normally closed contactors use inverted logic +#undef ON +#define ON 0 +#undef OFF +#define OFF 1 +#endif //NC_CONTACTORS + +#define MAX_ALLOWED_FAULT_TICKS 1000 +#define NEGATIVE_CONTACTOR_TIME_MS \ + 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 +#define PWM_ON_DUTY 1023 +#define PWM_Positive_Channel 0 +#define PWM_Negative_Channel 1 +unsigned long prechargeStartTime = 0; +unsigned long negativeStartTime = 0; +unsigned long prechargeCompletedTime = 0; +unsigned long timeSpentInFaultedMode = 0; +#endif + +void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) { +#ifdef PWM_CONTACTOR_CONTROL + if (pwm_freq != 0xFFFF) { + ledcWrite(pin, pwm_freq); + return; + } +#endif + if (direction == 1) { + digitalWrite(pin, HIGH); + } else { // 0 + digitalWrite(pin, LOW); + } +} + +// Initialization functions + +void init_contactors() { + // Init contactor pins +#ifdef CONTACTOR_CONTROL +#ifdef PWM_CONTACTOR_CONTROL + // Setup PWM Channel Frequency and Resolution + ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Positive_Channel); + ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Negative_Channel); + // Set all pins OFF (0% PWM) + ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY); + ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY); +#else //Normal CONTACTOR_CONTROL + pinMode(POSITIVE_CONTACTOR_PIN, OUTPUT); + set(POSITIVE_CONTACTOR_PIN, OFF); + pinMode(NEGATIVE_CONTACTOR_PIN, OUTPUT); + set(NEGATIVE_CONTACTOR_PIN, OFF); +#endif // Precharge never has PWM regardless of setting + pinMode(PRECHARGE_PIN, OUTPUT); + set(PRECHARGE_PIN, OFF); +#endif // CONTACTOR_CONTROL +#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY + pinMode(SECOND_POSITIVE_CONTACTOR_PIN, OUTPUT); + set(SECOND_POSITIVE_CONTACTOR_PIN, OFF); + pinMode(SECOND_NEGATIVE_CONTACTOR_PIN, OUTPUT); + set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); +#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY +// Init BMS contactor +#ifdef HW_STARK // TODO: Rewrite this so LilyGo can also handle this BMS contactor + pinMode(BMS_POWER, OUTPUT); + digitalWrite(BMS_POWER, HIGH); +#endif // HW_STARK +} + +// Main functions +void handle_contactors() { +#ifdef BYD_SMA + datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); +#endif // BYD_SMA + +#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY + handle_contactors_battery2(); +#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY + +#ifdef CONTACTOR_CONTROL + // First check if we have any active errors, incase we do, turn off the battery + if (datalayer.battery.status.bms_status == FAULT) { + timeSpentInFaultedMode++; + } else { + timeSpentInFaultedMode = 0; + } + + //handle contactor control SHUTDOWN_REQUESTED + if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) { + contactorStatus = SHUTDOWN_REQUESTED; + } + + if (contactorStatus == SHUTDOWN_REQUESTED) { + set(PRECHARGE_PIN, OFF); + set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY); + set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY); + set_event(EVENT_ERROR_OPEN_CONTACTOR, 0); + datalayer.system.status.contactors_engaged = false; + return; // A fault scenario latches the contactor control. It is not possible to recover without a powercycle (and investigation why fault occured) + } + + // After that, check if we are OK to start turning on the battery + if (contactorStatus == DISCONNECTED) { + set(PRECHARGE_PIN, OFF); + set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY); + set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY); + + if (datalayer.system.status.battery_allows_contactor_closing && + datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active) { + contactorStatus = START_PRECHARGE; + } + } + + // In case the inverter requests contactors to open, set the state accordingly + if (contactorStatus == COMPLETED) { + //Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable) + if (!datalayer.system.status.inverter_allows_contactor_closing || datalayer.system.settings.equipment_stop_active) { + contactorStatus = DISCONNECTED; + } + // Skip running the state machine below if it has already completed + return; + } + + unsigned long currentTime = millis(); + + if (currentTime < INTERVAL_10_S) { + // Skip running the state machine before system has started up. + // Gives the system some time to detect any faults from battery before blindly just engaging the contactors + return; + } + + // Handle actual state machine. This first turns on Negative, then Precharge, then Positive, and finally turns OFF precharge + switch (contactorStatus) { + case START_PRECHARGE: + set(NEGATIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY); + prechargeStartTime = currentTime; + contactorStatus = PRECHARGE; + break; + + case PRECHARGE: + if (currentTime - prechargeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) { + set(PRECHARGE_PIN, ON); + negativeStartTime = currentTime; + contactorStatus = POSITIVE; + } + break; + + case POSITIVE: + if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) { + set(POSITIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY); + prechargeCompletedTime = currentTime; + contactorStatus = PRECHARGE_OFF; + } + break; + + case PRECHARGE_OFF: + if (currentTime - prechargeCompletedTime >= PRECHARGE_COMPLETED_TIME_MS) { + set(PRECHARGE_PIN, OFF); + set(NEGATIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY); + set(POSITIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY); + contactorStatus = COMPLETED; + datalayer.system.status.contactors_engaged = true; + } + break; + default: + break; + } +#endif // CONTACTOR_CONTROL +} + +#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY +void handle_contactors_battery2() { + if ((contactorStatus == COMPLETED) && datalayer.system.status.battery2_allows_contactor_closing) { + set(SECOND_NEGATIVE_CONTACTOR_PIN, ON); + set(SECOND_POSITIVE_CONTACTOR_PIN, ON); + datalayer.system.status.contactors_battery2_engaged = true; + } else { // Closing contactors on secondary battery not allowed + set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); + set(SECOND_POSITIVE_CONTACTOR_PIN, OFF); + datalayer.system.status.contactors_battery2_engaged = false; + } +} +#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h new file mode 100644 index 000000000..1e7cf0f5a --- /dev/null +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h @@ -0,0 +1,15 @@ +#ifndef _COMM_CONTACTORCONTROL_H_ +#define _COMM_CONTACTORCONTROL_H_ + +#include "../../include.h" + +#include "../../datalayer/datalayer.h" +#include "../../devboard/utils/events.h" + +void init_contactors(); + +void handle_contactors(); + +void handle_contactors_battery2(); + +#endif From 6aa4a4ef95249c50d8ab15a05da31cdd07755223 Mon Sep 17 00:00:00 2001 From: lenvm Date: Fri, 13 Dec 2024 16:48:02 +0100 Subject: [PATCH 063/225] move equipment stop button related functions from Software.ino to equipmentstopbutton folder --- Software/Software.ino | 49 +----------------- .../comm_equipmentstopbutton.cpp | 51 +++++++++++++++++++ .../comm_equipmentstopbutton.h | 14 +++++ 3 files changed, 66 insertions(+), 48 deletions(-) create mode 100644 Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp create mode 100644 Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.h diff --git a/Software/Software.ino b/Software/Software.ino index b49422211..327e0704f 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -13,6 +13,7 @@ #include "src/charger/CHARGERS.h" #include "src/communication/can/comm_can.h" #include "src/communication/contactorcontrol/comm_contactorcontrol.h" +#include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h" #include "src/communication/rs485/comm_rs485.h" #include "src/communication/seriallink/comm_seriallink.h" #include "src/datalayer/datalayer.h" @@ -45,10 +46,6 @@ #endif // MQTT #endif // WIFI -#ifdef EQUIPMENT_STOP_BUTTON -#include "src/devboard/utils/debounce_button.h" -#endif - Preferences settings; // Store user settings // The current software version, shown on webserver const char* version_number = "8.0.dev"; @@ -84,15 +81,6 @@ MyTimer loop_task_timer_10s(INTERVAL_10_S); MyTimer check_pause_2s(INTERVAL_2_S); - -#ifdef EQUIPMENT_STOP_BUTTON -const unsigned long equipment_button_long_press_duration = - 15000; // 15 seconds for long press in case of MOMENTARY_SWITCH -const unsigned long equipment_button_debounce_duration = 200; // 250ms for debouncing the button -unsigned long timeSincePress = 0; // Variable to store the time since the last press -DebouncedButton equipment_stop_button; // Debounced button object -#endif - TaskHandle_t main_loop_task; TaskHandle_t connectivity_loop_task; @@ -361,41 +349,6 @@ void init_stored_settings() { settings.end(); } -#ifdef EQUIPMENT_STOP_BUTTON -void monitor_equipment_stop_button() { - - ButtonState changed_state = debounceButton(equipment_stop_button, timeSincePress); - - if (equipment_stop_behavior == LATCHING_SWITCH) { - if (changed_state == PRESSED) { - // Changed to ON – initiating equipment stop. - setBatteryPause(true, false, true); - } else if (changed_state == RELEASED) { - // Changed to OFF – ending equipment stop. - setBatteryPause(false, false, false); - } - } else if (equipment_stop_behavior == MOMENTARY_SWITCH) { - if (changed_state == RELEASED) { // button is released - - if (timeSincePress < equipment_button_long_press_duration) { - // Short press detected, trigger equipment stop - setBatteryPause(true, false, true); - } else { - // Long press detected, reset equipment stop state - setBatteryPause(false, false, false); - } - } - } -} - -void init_equipment_stop_button() { - //using external pullup resistors NC - pinMode(EQUIPMENT_STOP_PIN, INPUT); - // Initialize the debounced button with NC switch type and equipment_button_debounce_duration debounce time - initDebouncedButton(equipment_stop_button, EQUIPMENT_STOP_PIN, NC, equipment_button_debounce_duration); -} -#endif // EQUIPMENT_STOP_BUTTON - #ifdef DOUBLE_BATTERY void check_interconnect_available() { if (datalayer.battery.status.voltage_dV == 0 || datalayer.battery2.status.voltage_dV == 0) { diff --git a/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp new file mode 100644 index 000000000..2a6a3d7da --- /dev/null +++ b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.cpp @@ -0,0 +1,51 @@ +#include "comm_equipmentstopbutton.h" +#include "../../include.h" + +// Parameters +#ifdef EQUIPMENT_STOP_BUTTON +const unsigned long equipment_button_long_press_duration = + 15000; // 15 seconds for long press in case of MOMENTARY_SWITCH +const unsigned long equipment_button_debounce_duration = 200; // 200ms for debouncing the button +unsigned long timeSincePress = 0; // Variable to store the time since the last press +DebouncedButton equipment_stop_button; // Debounced button object +#endif // EQUIPMENT_STOP_BUTTON + +// Initialization functions +#ifdef EQUIPMENT_STOP_BUTTON +void init_equipment_stop_button() { + //using external pullup resistors NC + pinMode(EQUIPMENT_STOP_PIN, INPUT); + // Initialize the debounced button with NC switch type and equipment_button_debounce_duration debounce time + initDebouncedButton(equipment_stop_button, EQUIPMENT_STOP_PIN, NC, equipment_button_debounce_duration); +} +#endif // EQUIPMENT_STOP_BUTTON + +// Main functions + +#ifdef EQUIPMENT_STOP_BUTTON +void monitor_equipment_stop_button() { + + ButtonState changed_state = debounceButton(equipment_stop_button, timeSincePress); + + if (equipment_stop_behavior == LATCHING_SWITCH) { + if (changed_state == PRESSED) { + // Changed to ON – initiating equipment stop. + setBatteryPause(true, false, true); + } else if (changed_state == RELEASED) { + // Changed to OFF – ending equipment stop. + setBatteryPause(false, false, false); + } + } else if (equipment_stop_behavior == MOMENTARY_SWITCH) { + if (changed_state == RELEASED) { // button is released + + if (timeSincePress < equipment_button_long_press_duration) { + // Short press detected, trigger equipment stop + setBatteryPause(true, false, true); + } else { + // Long press detected, reset equipment stop state + setBatteryPause(false, false, false); + } + } + } +} +#endif // EQUIPMENT_STOP_BUTTON diff --git a/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.h b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.h new file mode 100644 index 000000000..543c4182c --- /dev/null +++ b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.h @@ -0,0 +1,14 @@ +#ifndef _COMM_EQUIPMENTSTOPBUTTON_H_ +#define _COMM_EQUIPMENTSTOPBUTTON_H_ + +#include "../../include.h" + +#ifdef EQUIPMENT_STOP_BUTTON +#include "../../devboard/utils/debounce_button.h" +#endif + +void init_equipment_stop_button(); + +void monitor_equipment_stop_button(); + +#endif From 4c4b4eef81c14a0335c2ed4a63c4ba9bb0e67018 Mon Sep 17 00:00:00 2001 From: lenvm Date: Fri, 13 Dec 2024 17:02:34 +0100 Subject: [PATCH 064/225] move setting storage related settings from Software.ino to nvme folder --- Software/Software.ino | 120 +------------------ Software/src/communication/nvm/comm_nvm.cpp | 125 ++++++++++++++++++++ Software/src/communication/nvm/comm_nvm.h | 16 +++ 3 files changed, 142 insertions(+), 119 deletions(-) create mode 100644 Software/src/communication/nvm/comm_nvm.cpp create mode 100644 Software/src/communication/nvm/comm_nvm.h diff --git a/Software/Software.ino b/Software/Software.ino index 327e0704f..75edee020 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -14,6 +14,7 @@ #include "src/communication/can/comm_can.h" #include "src/communication/contactorcontrol/comm_contactorcontrol.h" #include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h" +#include "src/communication/nvm/comm_nvm.h" #include "src/communication/rs485/comm_rs485.h" #include "src/communication/seriallink/comm_seriallink.h" #include "src/datalayer/datalayer.h" @@ -46,7 +47,6 @@ #endif // MQTT #endif // WIFI -Preferences settings; // Store user settings // The current software version, shown on webserver const char* version_number = "8.0.dev"; @@ -283,72 +283,6 @@ void init_serial() { #endif // DEBUG_VIA_USB } -void init_stored_settings() { - static uint32_t temp = 0; - // ATTENTION ! The maximum length for settings keys is 15 characters - settings.begin("batterySettings", false); - - // Always get the equipment stop status - datalayer.system.settings.equipment_stop_active = settings.getBool("EQUIPMENT_STOP", false); - if (datalayer.system.settings.equipment_stop_active) { - 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 - -#ifdef WIFI - char tempSSIDstring[63]; // Allocate buffer with sufficient size - size_t lengthSSID = settings.getString("SSID", tempSSIDstring, sizeof(tempSSIDstring)); - if (lengthSSID > 0) { // Successfully read the string from memory. Set it to SSID! - ssid = tempSSIDstring; - } else { // Reading from settings failed. Do nothing with SSID. Raise event? - } - char tempPasswordString[63]; // Allocate buffer with sufficient size - size_t lengthPassword = settings.getString("PASSWORD", tempPasswordString, sizeof(tempPasswordString)); - if (lengthPassword > 7) { // Successfully read the string from memory. Set it to password! - password = tempPasswordString; - } else { // Reading from settings failed. Do nothing with SSID. Raise event? - } -#endif // WIFI - - temp = settings.getUInt("BATTERY_WH_MAX", false); - if (temp != 0) { - datalayer.battery.info.total_capacity_Wh = temp; - } - temp = settings.getUInt("MAXPERCENTAGE", false); - if (temp != 0) { - datalayer.battery.settings.max_percentage = temp * 10; // Multiply by 10 for backwards compatibility - } - temp = settings.getUInt("MINPERCENTAGE", false); - if (temp != 0) { - datalayer.battery.settings.min_percentage = temp * 10; // Multiply by 10 for backwards compatibility - } - temp = settings.getUInt("MAXCHARGEAMP", false); - if (temp != 0) { - datalayer.battery.settings.max_user_set_charge_dA = temp; - } - temp = settings.getUInt("MAXDISCHARGEAMP", false); - if (temp != 0) { - datalayer.battery.settings.max_user_set_discharge_dA = temp; - } - datalayer.battery.settings.soc_scaling_active = settings.getBool("USE_SCALED_SOC", false); - temp = settings.getUInt("TARGETCHVOLT", false); - if (temp != 0) { - datalayer.battery.settings.max_user_set_charge_voltage_dV = temp; - } - temp = settings.getUInt("TARGETDISCHVOLT", false); - if (temp != 0) { - datalayer.battery.settings.max_user_set_discharge_voltage_dV = temp; - } - datalayer.battery.settings.user_set_voltage_limits_active = settings.getBool("USEVOLTLIMITS", false); - settings.end(); -} - #ifdef DOUBLE_BATTERY void check_interconnect_available() { if (datalayer.battery.status.voltage_dV == 0 || datalayer.battery2.status.voltage_dV == 0) { @@ -503,58 +437,6 @@ void update_values_inverter() { #endif // CAN_INVERTER_SELECTED } -void store_settings_equipment_stop() { - settings.begin("batterySettings", false); - settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active); - settings.end(); -} - -void storeSettings() { - // ATTENTION ! The maximum length for settings keys is 15 characters - if (!settings.begin("batterySettings", false)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 0); - return; - } - -#ifdef WIFI - if (!settings.putString("SSID", String(ssid.c_str()))) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 1); - } - if (!settings.putString("PASSWORD", String(password.c_str()))) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 2); - } -#endif - - if (!settings.putUInt("BATTERY_WH_MAX", datalayer.battery.info.total_capacity_Wh)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 3); - } - if (!settings.putBool("USE_SCALED_SOC", datalayer.battery.settings.soc_scaling_active)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 4); - } - if (!settings.putUInt("MAXPERCENTAGE", datalayer.battery.settings.max_percentage / 10)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 5); - } - if (!settings.putUInt("MINPERCENTAGE", datalayer.battery.settings.min_percentage / 10)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 6); - } - if (!settings.putUInt("MAXCHARGEAMP", datalayer.battery.settings.max_user_set_charge_dA)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 7); - } - if (!settings.putUInt("MAXDISCHARGEAMP", datalayer.battery.settings.max_user_set_discharge_dA)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 8); - } - if (!settings.putBool("USEVOLTLIMITS", datalayer.battery.settings.user_set_voltage_limits_active)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 9); - } - if (!settings.putUInt("TARGETCHVOLT", datalayer.battery.settings.max_user_set_charge_voltage_dV)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 10); - } - if (!settings.putUInt("TARGETDISCHVOLT", datalayer.battery.settings.max_user_set_discharge_voltage_dV)) { - set_event(EVENT_PERSISTENT_SAVE_INFO, 11); - } - settings.end(); // Close preferences handle -} - /** Reset reason numbering and description * typedef enum { diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp new file mode 100644 index 000000000..32f9f931c --- /dev/null +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -0,0 +1,125 @@ +#include "comm_nvm.h" +#include "../../include.h" + +// Parameters +Preferences settings; // Store user settings + +// Initialization functions + +void init_stored_settings() { + static uint32_t temp = 0; + // ATTENTION ! The maximum length for settings keys is 15 characters + settings.begin("batterySettings", false); + + // Always get the equipment stop status + datalayer.system.settings.equipment_stop_active = settings.getBool("EQUIPMENT_STOP", false); + if (datalayer.system.settings.equipment_stop_active) { + 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 + +#ifdef WIFI + char tempSSIDstring[63]; // Allocate buffer with sufficient size + size_t lengthSSID = settings.getString("SSID", tempSSIDstring, sizeof(tempSSIDstring)); + if (lengthSSID > 0) { // Successfully read the string from memory. Set it to SSID! + ssid = tempSSIDstring; + } else { // Reading from settings failed. Do nothing with SSID. Raise event? + } + char tempPasswordString[63]; // Allocate buffer with sufficient size + size_t lengthPassword = settings.getString("PASSWORD", tempPasswordString, sizeof(tempPasswordString)); + if (lengthPassword > 7) { // Successfully read the string from memory. Set it to password! + password = tempPasswordString; + } else { // Reading from settings failed. Do nothing with SSID. Raise event? + } +#endif // WIFI + + temp = settings.getUInt("BATTERY_WH_MAX", false); + if (temp != 0) { + datalayer.battery.info.total_capacity_Wh = temp; + } + temp = settings.getUInt("MAXPERCENTAGE", false); + if (temp != 0) { + datalayer.battery.settings.max_percentage = temp * 10; // Multiply by 10 for backwards compatibility + } + temp = settings.getUInt("MINPERCENTAGE", false); + if (temp != 0) { + datalayer.battery.settings.min_percentage = temp * 10; // Multiply by 10 for backwards compatibility + } + temp = settings.getUInt("MAXCHARGEAMP", false); + if (temp != 0) { + datalayer.battery.settings.max_user_set_charge_dA = temp; + } + temp = settings.getUInt("MAXDISCHARGEAMP", false); + if (temp != 0) { + datalayer.battery.settings.max_user_set_discharge_dA = temp; + } + datalayer.battery.settings.soc_scaling_active = settings.getBool("USE_SCALED_SOC", false); + temp = settings.getUInt("TARGETCHVOLT", false); + if (temp != 0) { + datalayer.battery.settings.max_user_set_charge_voltage_dV = temp; + } + temp = settings.getUInt("TARGETDISCHVOLT", false); + if (temp != 0) { + datalayer.battery.settings.max_user_set_discharge_voltage_dV = temp; + } + datalayer.battery.settings.user_set_voltage_limits_active = settings.getBool("USEVOLTLIMITS", false); + settings.end(); +} + +void store_settings_equipment_stop() { + settings.begin("batterySettings", false); + settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active); + settings.end(); +} + +void storeSettings() { + // ATTENTION ! The maximum length for settings keys is 15 characters + if (!settings.begin("batterySettings", false)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 0); + return; + } + +#ifdef WIFI + if (!settings.putString("SSID", String(ssid.c_str()))) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 1); + } + if (!settings.putString("PASSWORD", String(password.c_str()))) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 2); + } +#endif + + if (!settings.putUInt("BATTERY_WH_MAX", datalayer.battery.info.total_capacity_Wh)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 3); + } + if (!settings.putBool("USE_SCALED_SOC", datalayer.battery.settings.soc_scaling_active)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 4); + } + if (!settings.putUInt("MAXPERCENTAGE", datalayer.battery.settings.max_percentage / 10)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 5); + } + if (!settings.putUInt("MINPERCENTAGE", datalayer.battery.settings.min_percentage / 10)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 6); + } + if (!settings.putUInt("MAXCHARGEAMP", datalayer.battery.settings.max_user_set_charge_dA)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 7); + } + if (!settings.putUInt("MAXDISCHARGEAMP", datalayer.battery.settings.max_user_set_discharge_dA)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 8); + } + if (!settings.putBool("USEVOLTLIMITS", datalayer.battery.settings.user_set_voltage_limits_active)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 9); + } + if (!settings.putUInt("TARGETCHVOLT", datalayer.battery.settings.max_user_set_charge_voltage_dV)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 10); + } + if (!settings.putUInt("TARGETDISCHVOLT", datalayer.battery.settings.max_user_set_discharge_voltage_dV)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 11); + } + settings.end(); // Close preferences handle +} diff --git a/Software/src/communication/nvm/comm_nvm.h b/Software/src/communication/nvm/comm_nvm.h new file mode 100644 index 000000000..eaeafca59 --- /dev/null +++ b/Software/src/communication/nvm/comm_nvm.h @@ -0,0 +1,16 @@ +#ifndef _COMM_NVM_H_ +#define _COMM_NVM_H_ + +#include "../../include.h" + +#include "../../datalayer/datalayer.h" +#include "../../devboard/utils/events.h" +#include "../../devboard/wifi/wifi.h" + +void init_stored_settings(); + +void store_settings_equipment_stop(); + +void storeSettings(); + +#endif From 4e3dcf159b756b44c7669519edd65233489f9c98 Mon Sep 17 00:00:00 2001 From: lenvm Date: Fri, 13 Dec 2024 17:31:19 +0100 Subject: [PATCH 065/225] add doxygen style comments to functions, and change function names for consistency --- Software/Software.ino | 2 +- Software/src/communication/can/comm_can.cpp | 40 ++++++------- Software/src/communication/can/comm_can.h | 57 ++++++++++++++++++- .../contactorcontrol/comm_contactorcontrol.h | 21 +++++++ .../comm_equipmentstopbutton.h | 14 +++++ Software/src/communication/nvm/comm_nvm.cpp | 2 +- Software/src/communication/nvm/comm_nvm.h | 23 +++++++- Software/src/communication/rs485/comm_rs485.h | 7 +++ .../seriallink/comm_seriallink.cpp | 2 +- .../seriallink/comm_seriallink.h | 9 ++- Software/src/devboard/webserver/webserver.cpp | 22 +++---- Software/src/devboard/webserver/webserver.h | 2 +- 12 files changed, 161 insertions(+), 40 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 75edee020..efcb4051b 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -199,7 +199,7 @@ void core_loop(void* task_time_us) { receive_RS485(); // Process serial2 RS485 interface #endif // RS485_INVERTER_SELECTED #if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) - runSerialDataLink(); + run_serialDataLink(); #endif // SERIAL_LINK_RECEIVER || SERIAL_LINK_TRANSMITTER END_TIME_MEASUREMENT_MAX(comm, datalayer.system.status.time_comm_us); #ifdef WEBSERVER diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index 098d8cbe3..8d7923fda 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -207,26 +207,6 @@ void receive_can(CAN_frame* rx_frame, int interface) { } } -#ifdef CANFD_ADDON -// Functions -void receive_canfd_addon() { // This section checks if we have a complete CAN-FD message incoming - CANFDMessage frame; - int count = 0; - while (canfd.available() && count++ < 16) { - canfd.receive(frame); - - CAN_frame rx_frame; - rx_frame.ID = frame.id; - rx_frame.ext_ID = frame.ext; - rx_frame.DLC = frame.len; - memcpy(rx_frame.data.u8, frame.data, MIN(rx_frame.DLC, 64)); - //message incoming, pass it on to the handler - receive_can(&rx_frame, CANFD_ADDON_MCP2518); - receive_can(&rx_frame, CANFD_NATIVE); - } -} -#endif // CANFD_ADDON - void receive_can_native() { // This section checks if we have a complete CAN message incoming on native CAN port CAN_frame_t rx_frame_native; if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame_native, 0) == pdTRUE) { @@ -267,6 +247,26 @@ void receive_can_addon() { // This section checks if we have a complete CAN mes } #endif // CAN_ADDON +#ifdef CANFD_ADDON +// Functions +void receive_canfd_addon() { // This section checks if we have a complete CAN-FD message incoming + CANFDMessage frame; + int count = 0; + while (canfd.available() && count++ < 16) { + canfd.receive(frame); + + CAN_frame rx_frame; + rx_frame.ID = frame.id; + rx_frame.ext_ID = frame.ext; + rx_frame.DLC = frame.len; + memcpy(rx_frame.data.u8, frame.data, MIN(rx_frame.DLC, 64)); + //message incoming, pass it on to the handler + receive_can(&rx_frame, CANFD_ADDON_MCP2518); + receive_can(&rx_frame, CANFD_NATIVE); + } +} +#endif // CANFD_ADDON + // Support functions void print_can_frame(CAN_frame frame, frameDirection msgDir) { #ifdef DEBUG_CAN_DATA // If enabled in user settings, print out the CAN messages via USB diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h index 81c046f11..48e3c9c38 100644 --- a/Software/src/communication/can/comm_can.h +++ b/Software/src/communication/can/comm_can.h @@ -15,6 +15,8 @@ #include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" #endif //CANFD_ADDON +enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 + /** * @brief Initialization function for CAN. * @@ -24,19 +26,68 @@ */ void init_CAN(); +/** + * @brief Transmit one CAN frame + * + * @param[in] CAN_frame* tx_frame + * @param[in] int interface + * + * @return void + */ void transmit_can(); +/** + * @brief Send CAN messages to all components + * + * @param[in] void + * + * @return void + */ void send_can(); +/** + * @brief Receive CAN messages from all interfaces + * + * @param[in] void + * + * @return void + */ void receive_can(); -void receive_canfd_addon(); - +/** + * @brief Receive CAN messages from CAN tranceiver natively installed on Lilygo hardware + * + * @param[in] void + * + * @return void + */ void receive_can_native(); +/** + * @brief Receive CAN messages from CAN addon chip + * + * @param[in] void + * + * @return void + */ void receive_can_addon(); -enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 +/** + * @brief Receive CAN messages from CANFD addon chip + * + * @param[in] void + * + * @return void + */ +void receive_canfd_addon(); + +/** + * @brief print CAN frames via USB + * + * @param[in] void + * + * @return void + */ void print_can_frame(CAN_frame frame, frameDirection msgDir); #endif diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h index 1e7cf0f5a..2f4e1e0cb 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h @@ -6,10 +6,31 @@ #include "../../datalayer/datalayer.h" #include "../../devboard/utils/events.h" +/** + * @brief Contactor initialization + * + * @param[in] void + * + * @return void + */ void init_contactors(); +/** + * @brief Handle contactors + * + * @param[in] void + * + * @return void + */ void handle_contactors(); +/** + * @brief Handle contactors of battery 2 + * + * @param[in] void + * + * @return void + */ void handle_contactors_battery2(); #endif diff --git a/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.h b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.h index 543c4182c..f4f5a989b 100644 --- a/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.h +++ b/Software/src/communication/equipmentstopbutton/comm_equipmentstopbutton.h @@ -7,8 +7,22 @@ #include "../../devboard/utils/debounce_button.h" #endif +/** + * @brief Initialization of equipment stop button + * + * @param[in] void + * + * @return void + */ void init_equipment_stop_button(); +/** + * @brief Monitor equipment stop button + * + * @param[in] void + * + * @return void + */ void monitor_equipment_stop_button(); #endif diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 32f9f931c..03afbee07 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -78,7 +78,7 @@ void store_settings_equipment_stop() { settings.end(); } -void storeSettings() { +void store_settings() { // ATTENTION ! The maximum length for settings keys is 15 characters if (!settings.begin("batterySettings", false)) { set_event(EVENT_PERSISTENT_SAVE_INFO, 0); diff --git a/Software/src/communication/nvm/comm_nvm.h b/Software/src/communication/nvm/comm_nvm.h index eaeafca59..eb624e899 100644 --- a/Software/src/communication/nvm/comm_nvm.h +++ b/Software/src/communication/nvm/comm_nvm.h @@ -7,10 +7,31 @@ #include "../../devboard/utils/events.h" #include "../../devboard/wifi/wifi.h" +/** + * @brief Initialization of setting storage + * + * @param[in] void + * + * @return void + */ void init_stored_settings(); +/** + * @brief Store settings of equipment stop button + * + * @param[in] void + * + * @return void + */ void store_settings_equipment_stop(); -void storeSettings(); +/** + * @brief Store settings + * + * @param[in] void + * + * @return void + */ +void store_settings(); #endif diff --git a/Software/src/communication/rs485/comm_rs485.h b/Software/src/communication/rs485/comm_rs485.h index d4fd97c26..b4077dd48 100644 --- a/Software/src/communication/rs485/comm_rs485.h +++ b/Software/src/communication/rs485/comm_rs485.h @@ -7,6 +7,13 @@ #include "../../lib/eModbus-eModbus/ModbusServerRTU.h" #include "../../lib/eModbus-eModbus/scripts/mbServerFCs.h" +/** + * @brief Initialization of RS485 + * + * @param[in] void + * + * @return void + */ void init_rs485(); #endif diff --git a/Software/src/communication/seriallink/comm_seriallink.cpp b/Software/src/communication/seriallink/comm_seriallink.cpp index a08bb3c9d..b355ae973 100644 --- a/Software/src/communication/seriallink/comm_seriallink.cpp +++ b/Software/src/communication/seriallink/comm_seriallink.cpp @@ -18,7 +18,7 @@ void init_serialDataLink() { // Main functions #if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) -void runSerialDataLink() { +void run_serialDataLink() { static unsigned long updateTime = 0; unsigned long currentMillis = millis(); diff --git a/Software/src/communication/seriallink/comm_seriallink.h b/Software/src/communication/seriallink/comm_seriallink.h index 277165aa0..c88b34373 100644 --- a/Software/src/communication/seriallink/comm_seriallink.h +++ b/Software/src/communication/seriallink/comm_seriallink.h @@ -3,8 +3,15 @@ #include "../../include.h" +/** + * @brief Initialization of serial data link + * + * @param[in] void + * + * @return void + */ void init_serialDataLink(); -void runSerialDataLink(); +void run_serialDataLink(); #endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index ff7770eea..5468c7049 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -131,7 +131,7 @@ void init_webserver() { String value = request->getParam("value")->value(); if (value.length() <= 63) { // Check if SSID is within the allowable length ssid = value.c_str(); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "SSID must be 63 characters or less"); @@ -148,7 +148,7 @@ void init_webserver() { String value = request->getParam("value")->value(); if (value.length() > 8) { // Check if password is within the allowable length password = value.c_str(); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Password must be atleast 8 characters"); @@ -165,7 +165,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.info.total_capacity_Wh = value.toInt(); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); @@ -179,7 +179,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.settings.soc_scaling_active = value.toInt(); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); @@ -193,7 +193,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.settings.max_percentage = static_cast(value.toFloat() * 100); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); @@ -237,7 +237,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.settings.min_percentage = static_cast(value.toFloat() * 100); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); @@ -251,7 +251,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.settings.max_user_set_charge_dA = static_cast(value.toFloat() * 10); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); @@ -265,7 +265,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.settings.max_user_set_discharge_dA = static_cast(value.toFloat() * 10); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); @@ -279,7 +279,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.settings.user_set_voltage_limits_active = value.toInt(); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); @@ -293,7 +293,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.settings.max_user_set_charge_voltage_dV = static_cast(value.toFloat() * 10); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); @@ -307,7 +307,7 @@ void init_webserver() { if (request->hasParam("value")) { String value = request->getParam("value")->value(); datalayer.battery.settings.max_user_set_discharge_voltage_dV = static_cast(value.toFloat() * 10); - storeSettings(); + store_settings(); request->send(200, "text/plain", "Updated successfully"); } else { request->send(400, "text/plain", "Bad Request"); diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h index 21416850b..a75ef8fb6 100644 --- a/Software/src/devboard/webserver/webserver.h +++ b/Software/src/devboard/webserver/webserver.h @@ -104,7 +104,7 @@ void onOTAEnd(bool success); template String formatPowerValue(String label, T value, String unit, int precision, String color = "white"); -extern void storeSettings(); +extern void store_settings(); void ota_monitor(); From bc5ef7c69cc00b0991e5ad5f23a838cc537b0625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 15 Dec 2024 22:43:34 +0200 Subject: [PATCH 066/225] Add more info about which CAN messages are present --- .../src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index ef9f54f82..899331911 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -13,6 +13,8 @@ Still TODO: - Fix the missing cell96 issue (Only cells 1-95 is shown) - Find current sensor value (OVMS code reads this from inverter, which we dont have) - Figure out why SOH% is not read (low prio) + - Most likely relates to the CAN message not being present on 41kWh packs +- Automatically detect if we are on 22 or 41kWh battery /* /* Do not change code below unless you are sure what you are doing */ @@ -152,22 +154,52 @@ void update_values_battery() { //This function maps all the values fetched via } void receive_can_battery(CAN_frame rx_frame) { - datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { - case 0x427: + case 0x155: //10ms - Unknown content + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x427: // NOTE: Not present on 41kWh battery! + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; LB_Charge_Power_W = rx_frame.data.u8[5] * 300; LB_kWh_Remaining = (((((rx_frame.data.u8[6] << 8) | (rx_frame.data.u8[7])) >> 6) & 0x3ff) * 0.1); break; - case 0x42E: //HV SOC & Battery Temp & Charging Power + case 0x42E: //NOTE: Not present on 41kWh battery! HV SOC & Battery Temp & Charging Power + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; LB_Battery_Voltage = (((((rx_frame.data.u8[3] << 8) | (rx_frame.data.u8[4])) >> 5) & 0x3ff) * 0.5); //0.5V/bit LB_Average_Temperature = (((((rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6])) >> 5) & 0x7F) - 40); break; + case 0x424: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + //Sent only? by 41kWh battery (potential use for detecting which generation we are on) + break; + case 0x425: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + //Sent only? by 41kWh battery (potential use for detecting which generation we are on) + break; + case 0x445: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + //Sent only? by 41kWh battery (potential use for detecting which generation we are on) + break; + case 0x4AE: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + //Sent only? by 41kWh battery (potential use for detecting which generation we are on) + break; + case 0x4AF: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + //Sent only? by 41kWh battery (potential use for detecting which generation we are on) + break; case 0x654: //SOC + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; LB_SOC = rx_frame.data.u8[3]; break; - case 0x658: //SOH + case 0x658: //SOH - NOTE: Not present on 41kWh battery! + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; LB_SOH = (rx_frame.data.u8[4] & 0x7F); break; + case 0x659: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + //Sent only? by 41kWh battery (potential use for detecting which generation we are on) + break; case 0x7BB: //Reply from active polling frame0 = rx_frame.data.u8[0]; From 0203a8549b86b9398ad20a72398e8eaf1d48fe0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 15 Dec 2024 23:19:02 +0200 Subject: [PATCH 067/225] Make startup less prone to throw Events --- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 3 +++ Software/src/devboard/safety/safety.cpp | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index eaa01bae9..74cca3802 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -419,6 +419,9 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; + datalayer.battery.status.voltage_dV = + MIN_PACK_VOLTAGE_DV + + 1; // Init values in datalayer too low, causes safeties to trigger before values are sampled #ifdef DOUBLE_BATTERY datalayer.battery2.info.number_of_cells = 126; datalayer.battery2.info.chemistry = battery_chemistry_enum::LFP; diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp index 4c5572468..39f4b1331 100644 --- a/Software/src/devboard/safety/safety.cpp +++ b/Software/src/devboard/safety/safety.cpp @@ -111,7 +111,8 @@ void update_machineryprotection() { #endif //NISSAN_LEAF_BATTERY // Check diff between highest and lowest cell - cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV); + cell_deviation_mV = + std::abs(datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV); if (cell_deviation_mV > datalayer.battery.info.max_cell_voltage_deviation_mV) { set_event(EVENT_CELL_DEVIATION_HIGH, (cell_deviation_mV / 20)); } else { From 22f3fddd3042d6f4161f1eb2b9bc1117451f6712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 16 Dec 2024 21:56:10 +0200 Subject: [PATCH 068/225] Update comment explaining voltage init --- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 74cca3802..f0f74da43 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -419,9 +419,9 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; - datalayer.battery.status.voltage_dV = - MIN_PACK_VOLTAGE_DV + - 1; // Init values in datalayer too low, causes safeties to trigger before values are sampled + //Due to the Datalayer having 370.0V as startup value, which is 10V lower than the Atto 3 min voltage 380.0V + //We now init the value to 380.1V to avoid false positive events. + datalayer.battery.status.voltage_dV = MIN_PACK_VOLTAGE_DV + 1; #ifdef DOUBLE_BATTERY datalayer.battery2.info.number_of_cells = 126; datalayer.battery2.info.chemistry = battery_chemistry_enum::LFP; From 2d36c9a2a27903b336f3c31aa0954c1500f1f53b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 16 Dec 2024 22:22:20 +0200 Subject: [PATCH 069/225] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e486e2a18..3d86f1202 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Here's how to wire up the communication between the components. Here's how to connect the high voltage lines ![HighVoltageWiring](https://github.com/dalathegreat/Battery-Emulator/assets/26695010/f70e6262-d630-4148-9a39-dad32e79b3d6) -For more examples showing wiring, see each battery types own Wiki page. For instance the [Nissan LEAF page](https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki/Nissan-LEAF-battery#wiring-diagram) +For more examples showing wiring, see each battery types own Wiki page. For instance the [Nissan LEAF page](https://github.com/dalathegreat/Battery-Emulator/wiki/Battery:-Nissan-LEAF---e%E2%80%90NV200) ## How to compile the software 💻 1. Download the Arduino IDE: https://www.arduino.cc/en/software From 0231b2230d0bf7b25035aed0a36dc6930bcf4da8 Mon Sep 17 00:00:00 2001 From: lenvm Date: Mon, 16 Dec 2024 21:36:10 +0100 Subject: [PATCH 070/225] add skip-duplicate-actions to batteries workflow --- .github/workflows/compile-all-batteries.yml | 24 +++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index 49d083a0b..4218eeeb4 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -9,12 +9,28 @@ on: - pull_request # This is the list of jobs that will be run concurrently. -# Since we use a build matrix, the actual number of jobs -# started depends on how many configurations the matrix -# will produce. jobs: - # This is the name of the job + # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request + pre_job: + runs-on: ubuntu-latest + # Map a step output to a job output + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # All of these options are optional, so you can remove them if you are happy with the defaults + concurrent_skipping: 'never' + skip_after_successful_duplicate: 'true' + do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' + + # Since we use a build matrix, the actual number of jobs + # started depends on how many configurations the matrix + # will produce. build-batteries: + needs: pre_job + if: needs.pre_job.outputs.should_skip != 'true' # Here we tell GitHub that the jobs must be determined # dynamically depending on a matrix configuration. From 1b21b13ef3e48ab3bf0e95a7e27f4a3fcb29024b Mon Sep 17 00:00:00 2001 From: lenvm Date: Mon, 16 Dec 2024 21:49:50 +0100 Subject: [PATCH 071/225] add skip-duplicate-actions to inverters workflow --- .github/workflows/compile-all-inverters.yml | 24 ++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile-all-inverters.yml b/.github/workflows/compile-all-inverters.yml index fb4afbf3d..03406aba4 100644 --- a/.github/workflows/compile-all-inverters.yml +++ b/.github/workflows/compile-all-inverters.yml @@ -9,12 +9,30 @@ on: - pull_request # This is the list of jobs that will be run concurrently. -# Since we use a build matrix, the actual number of jobs -# started depends on how many configurations the matrix -# will produce. jobs: + # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request + pre_job: + runs-on: ubuntu-latest + # Map a step output to a job output + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # All of these options are optional, so you can remove them if you are happy with the defaults + concurrent_skipping: 'never' + skip_after_successful_duplicate: 'true' + do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' + + # Since we use a build matrix, the actual number of jobs + # started depends on how many configurations the matrix + # will produce. + # This is the name of the job. build-inverters: + needs: pre_job + if: needs.pre_job.outputs.should_skip != 'true' # Here we tell GitHub that the jobs must be determined # dynamically depending on a matrix configuration. From cfe5f6e01771a8762ad0fa352db8ae8f81030058 Mon Sep 17 00:00:00 2001 From: lenvm Date: Mon, 16 Dec 2024 21:55:40 +0100 Subject: [PATCH 072/225] update name of pre_job to skip-duplicate-actions, and add skip-duplicate-actions to all combinations workflow --- .github/workflows/compile-all-batteries.yml | 6 ++--- .../workflows/compile-all-combinations.yml | 24 ++++++++++++++++--- .github/workflows/compile-all-inverters.yml | 6 ++--- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index 4218eeeb4..3e04e5d45 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -11,7 +11,7 @@ on: # This is the list of jobs that will be run concurrently. jobs: # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request - pre_job: + skip-duplicate-actions: runs-on: ubuntu-latest # Map a step output to a job output outputs: @@ -29,8 +29,8 @@ jobs: # started depends on how many configurations the matrix # will produce. build-batteries: - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' + needs: skip-duplicate-actions + if: needs.skip-duplicate-actions.outputs.should_skip != 'true' # Here we tell GitHub that the jobs must be determined # dynamically depending on a matrix configuration. diff --git a/.github/workflows/compile-all-combinations.yml b/.github/workflows/compile-all-combinations.yml index 91df0bbbb..23ff0b85e 100644 --- a/.github/workflows/compile-all-combinations.yml +++ b/.github/workflows/compile-all-combinations.yml @@ -12,12 +12,30 @@ on: types: [created, edited, prereleased, released, published] # This is the list of jobs that will be run concurrently. -# Since we use a build matrix, the actual number of jobs -# started depends on how many configurations the matrix -# will produce. jobs: + # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request + skip-duplicate-actions: + runs-on: ubuntu-latest + # Map a step output to a job output + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # All of these options are optional, so you can remove them if you are happy with the defaults + concurrent_skipping: 'never' + skip_after_successful_duplicate: 'true' + do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' + + # Since we use a build matrix, the actual number of jobs + # started depends on how many configurations the matrix + # will produce. + # This is the name of the job. build-matrix: + needs: skip-duplicate-actions + if: needs.skip-duplicate-actions.outputs.should_skip != 'true' # Here we tell GitHub that the jobs must be determined # dynamically depending on a matrix configuration. diff --git a/.github/workflows/compile-all-inverters.yml b/.github/workflows/compile-all-inverters.yml index 03406aba4..6723c8030 100644 --- a/.github/workflows/compile-all-inverters.yml +++ b/.github/workflows/compile-all-inverters.yml @@ -11,7 +11,7 @@ on: # This is the list of jobs that will be run concurrently. jobs: # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request - pre_job: + skip-duplicate-actions: runs-on: ubuntu-latest # Map a step output to a job output outputs: @@ -31,8 +31,8 @@ jobs: # This is the name of the job. build-inverters: - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' + needs: skip-duplicate-actions + if: needs.skip-duplicate-actions.outputs.should_skip != 'true' # Here we tell GitHub that the jobs must be determined # dynamically depending on a matrix configuration. From 320c58a22eaa3a99611bbec5881c009440223610 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 18 Dec 2024 20:47:24 +1300 Subject: [PATCH 073/225] Update TESLA-BATTERY.cpp Update all CAN ID's battery is sending, reorganize and add comments for reference. Change names to match DBC files. Need to update DOUBLE BATTERY. --- Software/src/battery/TESLA-BATTERY.cpp | 1016 +++++++++++++++++++++--- 1 file changed, 927 insertions(+), 89 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index f6db10a88..dd1273a11 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -8,7 +8,7 @@ /* Do not change code below unless you are sure what you are doing */ /* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */ -static unsigned long previousMillis30 = 0; // will store last time a 30ms CAN Message was send +static unsigned long previousMillis50 = 0; // will store last time a 30ms CAN Message was send CAN_frame TESLA_221_1 = { .FD = false, @@ -22,14 +22,16 @@ CAN_frame TESLA_221_2 = { .DLC = 8, .ID = 0x221, .data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive + + static uint16_t sendContactorClosingMessagesStill = 300; +static uint16_t battery_cell_max_v = 3700; +static uint16_t battery_cell_min_v = 3700; +static uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV +//0x3d2: 978 BMS_kwhCounter static uint32_t battery_total_discharge = 0; static uint32_t battery_total_charge = 0; -static uint16_t battery_volts = 0; // V -static int16_t battery_amps = 0; // A -static uint16_t battery_raw_amps = 0; // A -static int16_t battery_max_temp = 0; // C* -static int16_t battery_min_temp = 0; // C* +//0x352: 850 BMS_energyStatus static uint16_t battery_energy_buffer = 0; // kWh static uint16_t battery_energy_buffer_m1 = 0; // kWh static uint16_t battery_energy_to_charge_complete = 0; // kWh @@ -44,29 +46,50 @@ static uint16_t battery_nominal_energy_remaining = 0; // kWh static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh static uint16_t battery_nominal_full_pack_energy = 600; // Kwh static uint16_t battery_nominal_full_pack_energy_m0 = 600; // Kwh -static uint16_t battery_beginning_of_life = 600; // kWh +//0x132 306 HVBattAmpVolt +static uint16_t battery_volts = 0; // V +static int16_t battery_amps = 0; // A +static uint16_t battery_raw_amps = 0; // A static uint16_t battery_charge_time_remaining = 0; // Minutes -static uint16_t battery_regenerative_limit = 0; -static uint16_t battery_discharge_limit = 0; -static uint16_t battery_max_heat_park = 0; -static uint16_t battery_hvac_max_power = 0; +//0x252 594 BMS_powerAvailable +static uint16_t BMS_regenerative_limit = 0; //rename from battery_regenerative_limit +static uint16_t BMS_discharge_limit = 0; // rename from battery_discharge_limit +static uint16_t BMS_max_heat_park = 0; //rename from battery_max_heat_park +static uint16_t BMS_hvac_max_power = 0; //rename from battery_hvac_max_power +//0x2d2: 722 BMSVAlimits static uint16_t battery_max_discharge_current = 0; static uint16_t battery_max_charge_current = 0; static uint16_t battery_bms_max_voltage = 0; static uint16_t battery_bms_min_voltage = 0; +//0x2b4: 692 PCS_dcdcRailStatus static uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt static uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt -static uint16_t battery_dcdcLvOutputCurrent = - 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent +static uint16_t battery_dcdcLvOutputCurrent = 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent +//0x292: 658 BMS_socStatus +static uint16_t battery_beginning_of_life = 600; // kWh static uint16_t battery_soc_min = 0; static uint16_t battery_soc_max = 0; static uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui static uint16_t battery_soc_ave = 0; -static uint16_t battery_cell_max_v = 3700; -static uint16_t battery_cell_min_v = 3700; -static uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV -static uint8_t battery_max_vno = 0; -static uint8_t battery_min_vno = 0; +static uint8_t battery_battTempPct = 0; +//0x392: BMS_packConfig +static uint32_t battery_packMass = 0; +static uint32_t battery_platformMaxBusVoltage = 0; +static uint32_t battery_packConfigMultiplexer = 0; +static uint32_t battery_moduleType = 0; +static uint32_t battery_reservedConfig = 0; +//0x332: 818 BattBrickMinMax:BMS_bmbMinMax +static int16_t battery_max_temp = 0; // C* +static int16_t battery_min_temp = 0; // C* +static uint16_t battery_BrickVoltageMax = 0; +static uint16_t battery_BrickVoltageMin = 0; +static uint8_t battery_BrickTempMaxNum = 0; +static uint8_t battery_BrickTempMinNum = 0; +static uint8_t battery_BrickModelTMax = 0; +static uint8_t battery_BrickModelTMin = 0; +static uint8_t battery_BrickVoltageMaxNum = 0; //rename from battery_max_vno +static uint8_t battery_BrickVoltageMinNum = 0; //rename from battery_min_vno +//0x20A: 522 HVP_contactorState static uint8_t battery_contactor = 0; //State of contactor static uint8_t battery_hvil_status = 0; static uint8_t battery_packContNegativeState = 0; @@ -74,13 +97,159 @@ static uint8_t battery_packContPositiveState = 0; static uint8_t battery_packContactorSetState = 0; static uint8_t battery_packCtrsClosingAllowed = 0; static uint8_t battery_pyroTestInProgress = 0; -static uint8_t battery_battTempPct = 0; -static uint32_t battery_packMass = 0; -static uint32_t battery_platformMaxBusVoltage = 0; -static uint32_t battery_packConfigMultiplexer = 0; -static uint32_t battery_moduleType = 0; -static uint32_t battery_reservedConfig = 0; -//Fault codes +static uint8_t battery_packCtrsOpenNowRequested = 0; +static uint8_t battery_packCtrsOpenRequested = 0; +static uint8_t battery_packCtrsRequestStatus = 0; +static uint8_t battery_packCtrsResetRequestRequired = 0; +static uint8_t battery_dcLinkAllowedToEnergize = 0; +static uint8_t battery_fcContNegativeAuxOpen = 0; +static uint8_t battery_fcContNegativeState = 0; +static uint8_t battery_fcContPositiveAuxOpen = 0; +static uint8_t battery_fcContPositiveState = 0; +static uint8_t battery_fcContactorSetState = 0; +static uint8_t battery_fcCtrsClosingAllowed = 0; +static uint8_t battery_fcCtrsOpenNowRequested = 0; +static uint8_t battery_fcCtrsOpenRequested = 0; +static uint8_t battery_fcCtrsRequestStatus = 0; +static uint8_t battery_fcCtrsResetRequestRequired = 0; +static uint8_t battery_fcLinkAllowedToEnergize = 0; +//0x212: 530 BMS_status +static uint8_t battery_BMS_hvacPowerRequest = 0; +static uint8_t battery_BMS_notEnoughPowerForDrive = 0; +static uint8_t battery_BMS_notEnoughPowerForSupport = 0; +static uint8_t battery_BMS_preconditionAllowed = 0; +static uint8_t battery_BMS_updateAllowed = 0; +static uint8_t battery_BMS_activeHeatingWorthwhile = 0; +static uint8_t battery_BMS_cpMiaOnHvs = 0; +static uint8_t battery_BMS_contactorState = 0; +static uint8_t battery_BMS_state = 0; +static uint8_t battery_BMS_hvState = 0; +static uint16_t battery_BMS_isolationResistance = 0; +static uint8_t battery_BMS_chargeRequest = 0; +static uint8_t battery_BMS_keepWarmRequest = 0; +static uint8_t battery_BMS_uiChargeStatus = 0; +static uint8_t battery_BMS_diLimpRequest = 0; +static uint8_t battery_BMS_okToShipByAir = 0; +static uint8_t battery_BMS_okToShipByLand = 0; +static uint32_t battery_BMS_chgPowerAvailable = 0; +static uint8_t battery_BMS_chargeRetryCount = 0; +static uint8_t battery_BMS_pcsPwmEnabled = 0; +static uint8_t battery_BMS_ecuLogUploadRequest = 0; +static uint8_t battery_BMS_minPackTemperature = 0; +// 0x224:548 PCS_dcdcStatus +static uint8_t battery_PCS_dcdcPrechargeStatus = 0; +static uint8_t battery_PCS_dcdc12VSupportStatus = 0; +static uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0; +static uint16_t battery_PCS_dcdcMainState = 0; +static uint8_t battery_PCS_dcdcSubState = 0; +static uint8_t battery_PCS_dcdcFaulted = 0; +static uint8_t battery_PCS_dcdcOutputIsLimited = 0; +static uint32_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0; +static uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0; +static uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0; +static uint8_t battery_PCS_dcdcDischargeRtyCnt = 0; +static uint8_t battery_PCS_dcdcPwmEnableLine = 0; +static uint8_t battery_PCS_dcdcSupportingFixedLvTarget = 0; +static uint8_t battery_PCS_ecuLogUploadRequest = 0; +static uint8_t battery_PCS_dcdcPrechargeRestartCnt = 0; +static uint8_t battery_PCS_dcdcInitialPrechargeSubState = 0; +//0x312: 786 BMS_thermalStatus +static uint16_t BMS_powerDissipation = 0; +static uint16_t BMS_flowRequest = 0; +static uint16_t BMS_inletActiveCoolTargetT = 0; +static uint16_t BMS_inletPassiveTargetT = 0; +static uint16_t BMS_inletActiveHeatTargetT = 0; +static uint16_t BMS_packTMin = 0; +static uint16_t BMS_packTMax = 0; +static uint16_t BMS_pcsNoFlowRequest = 0; +static uint16_t BMS_noFlowRequest = 0; +//0x2A4; 676 PCS_thermalStatus +static uint16_t PCS_chgPhATemp = 0; +static uint16_t PCS_chgPhBTemp = 0; +static uint16_t PCS_chgPhCTemp = 0; +static uint16_t PCS_dcdcTemp = 0; +static uint16_t PCS_ambientTemp = 0; +//0x2C4; 708 PCS_logging +static uint16_t PCS_logMessageSelect = 0; +static uint16_t PCS_dcdcMaxLvOutputCurrent = 0; +static uint16_t PCS_dcdcCurrentLimit = 0; +static uint16_t PCS_dcdcLvOutputCurrentTempLimit = 0; +static uint16_t PCS_dcdcUnifiedCommand = 0; +static uint16_t PCS_dcdcCLAControllerOutput = 0; +static uint16_t PCS_dcdcTankVoltage = 0; +static uint16_t PCS_dcdcTankVoltageTarget = 0; +static uint16_t PCS_dcdcClaCurrentFreq = 0; +static uint16_t PCS_dcdcTCommMeasured = 0; +static uint16_t PCS_dcdcShortTimeUs = 0; +static uint16_t PCS_dcdcHalfPeriodUs = 0; +static uint16_t PCS_dcdcIntervalMaxFrequency = 0; +static uint16_t PCS_dcdcIntervalMaxHvBusVolt = 0; +static uint16_t PCS_dcdcIntervalMaxLvBusVolt = 0; +static uint16_t PCS_dcdcIntervalMaxLvOutputCurr = 0; +static uint16_t PCS_dcdcIntervalMinFrequency = 0; +static uint16_t PCS_dcdcIntervalMinHvBusVolt = 0; +static uint16_t PCS_dcdcIntervalMinLvBusVolt = 0; +static uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0; +static uint32_t PCS_dcdc12vSupportLifetimekWh = 0; +//0x7AA: //1962 HVP_debugMessage: +static uint8_t HVP_debugMessageMultiplexer = 0; +static uint8_t HVP_gpioPassivePyroDepl = 0; +static uint8_t HVP_gpioPyroIsoEn = 0; +static uint8_t HVP_gpioCpFaultIn = 0; +static uint8_t HVP_gpioPackContPowerEn = 0; +static uint8_t HVP_gpioHvCablesOk = 0; +static uint8_t HVP_gpioHvpSelfEnable = 0; +static uint8_t HVP_gpioLed = 0; +static uint8_t HVP_gpioCrashSignal = 0; +static uint8_t HVP_gpioShuntDataReady = 0; +static uint8_t HVP_gpioFcContPosAux = 0; +static uint8_t HVP_gpioFcContNegAux = 0; +static uint8_t HVP_gpioBmsEout = 0; +static uint8_t HVP_gpioCpFaultOut = 0; +static uint8_t HVP_gpioPyroPor = 0; +static uint8_t HVP_gpioShuntEn = 0; +static uint8_t HVP_gpioHvpVerEn = 0; +static uint8_t HVP_gpioPackCoontPosFlywheel = 0; +static uint8_t HVP_gpioCpLatchEnable = 0; +static uint8_t HVP_gpioPcsEnable = 0; +static uint8_t HVP_gpioPcsDcdcPwmEnable = 0; +static uint8_t HVP_gpioPcsChargePwmEnable = 0; +static uint8_t HVP_gpioFcContPowerEnable = 0; +static uint8_t HVP_gpioHvilEnable = 0; +static uint8_t HVP_gpioSecDrdy = 0; +static uint16_t HVP_hvp1v5Ref = 0; +static uint16_t HVP_shuntCurrentDebug = 0; +static uint8_t HVP_packCurrentMia = 0; +static uint8_t HVP_auxCurrentMia = 0; +static uint8_t HVP_currentSenseMia = 0; +static uint8_t HVP_shuntRefVoltageMismatch = 0; +static uint8_t HVP_shuntThermistorMia = 0; +static uint8_t HVP_shuntHwMia = 0; +static uint16_t HVP_dcLinkVoltage = 0; +static uint16_t HVP_packVoltage = 0; +static uint16_t HVP_fcLinkVoltage = 0; +static uint16_t HVP_packContVoltage = 0; +static uint16_t HVP_packNegativeV = 0; +static uint16_t HVP_packPositiveV = 0; +static uint16_t HVP_pyroAnalog = 0; +static uint16_t HVP_dcLinkNegativeV = 0; +static uint16_t HVP_dcLinkPositiveV = 0; +static uint16_t HVP_fcLinkNegativeV = 0; +static uint16_t HVP_fcContCoilCurrent = 0; +static uint16_t HVP_fcContVoltage = 0; +static uint16_t HVP_hvilInVoltage = 0; +static uint16_t HVP_hvilOutVoltage = 0; +static uint16_t HVP_fcLinkPositiveV = 0; +static uint16_t HVP_packContCoilCurrent = 0; +static uint16_t HVP_battery12V = 0; +static uint16_t HVP_shuntRefVoltageDbg = 0; +static uint16_t HVP_shuntAuxCurrentDbg = 0; +static uint16_t HVP_shuntBarTempDbg = 0; +static uint16_t HVP_shuntAsicTempDbg = 0; +static uint8_t HVP_shuntAuxCurrentStatus = 0; +static uint8_t HVP_shuntBarTempStatus = 0; +static uint8_t HVP_shuntAsicTempStatus = 0; +//0x3aa: HVP_alertMatrix1 Fault codes static uint8_t battery_WatchdogReset = 0; //Warns if the processor has experienced a reset due to watchdog reset. static uint8_t battery_PowerLossReset = 0; //Warns if the processor has experienced a reset due to power loss. static uint8_t battery_SwAssertion = 0; //An internal software assertion has failed. @@ -139,8 +308,102 @@ static uint8_t battery_logUploadRequest = 0; static uint8_t battery_packCtrCloseFailed = 0; static uint8_t battery_fcCtrCloseFailed = 0; static uint8_t battery_shuntThermistorMia = 0; - -#ifdef DOUBLE_BATTERY +//0x320: 800 BMS_alertMatrix +static uint8_t battery_BMS_matrixIndex = 4; +static uint8_t battery_BMS_a061_robinBrickOverVoltage = 1; +static uint8_t battery_BMS_a062_SW_BrickV_Imbalance = 1; +static uint8_t battery_BMS_a063_SW_ChargePort_Fault = 1; +static uint8_t battery_BMS_a064_SW_SOC_Imbalance = 1; +static uint8_t battery_BMS_a127_SW_shunt_SNA = 1; +static uint8_t battery_BMS_a128_SW_shunt_MIA = 1; +static uint8_t battery_BMS_a069_SW_Low_Power = 1; +static uint8_t battery_BMS_a130_IO_CAN_Error = 1; +static uint8_t battery_BMS_a071_SW_SM_TransCon_Not_Met = 1; +static uint8_t battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = 1; +static uint8_t battery_BMS_a134_SW_Delayed_Ctr_Off = 1; +static uint8_t battery_BMS_a075_SW_Chg_Disable_Failure = 1; +static uint8_t battery_BMS_a076_SW_Dch_While_Charging = 1; +static uint8_t battery_BMS_a017_SW_Brick_OV = 1; +static uint8_t battery_BMS_a018_SW_Brick_UV = 1; +static uint8_t battery_BMS_a019_SW_Module_OT = 1; +static uint8_t battery_BMS_a021_SW_Dr_Limits_Regulation = 1; +static uint8_t battery_BMS_a022_SW_Over_Current = 1; +static uint8_t battery_BMS_a023_SW_Stack_OV = 1; +static uint8_t battery_BMS_a024_SW_Islanded_Brick = 1; +static uint8_t battery_BMS_a025_SW_PwrBalance_Anomaly = 1; +static uint8_t battery_BMS_a026_SW_HFCurrent_Anomaly = 1; +static uint8_t battery_BMS_a087_SW_Feim_Test_Blocked = 1; +static uint8_t battery_BMS_a088_SW_VcFront_MIA_InDrive = 1; +static uint8_t battery_BMS_a089_SW_VcFront_MIA = 1; +static uint8_t battery_BMS_a090_SW_Gateway_MIA = 1; +static uint8_t battery_BMS_a091_SW_ChargePort_MIA = 1; +static uint8_t battery_BMS_a092_SW_ChargePort_Mia_On_Hv = 1; +static uint8_t battery_BMS_a034_SW_Passive_Isolation = 1; +static uint8_t battery_BMS_a035_SW_Isolation = 1; +static uint8_t battery_BMS_a036_SW_HvpHvilFault = 1; +static uint8_t battery_BMS_a037_SW_Flood_Port_Open = 1; +static uint8_t battery_BMS_a158_SW_HVP_HVI_Comms = 1; +static uint8_t battery_BMS_a039_SW_DC_Link_Over_Voltage = 1; +static uint8_t battery_BMS_a041_SW_Power_On_Reset = 1; +static uint8_t battery_BMS_a042_SW_MPU_Error = 1; +static uint8_t battery_BMS_a043_SW_Watch_Dog_Reset = 1; +static uint8_t battery_BMS_a044_SW_Assertion = 1; +static uint8_t battery_BMS_a045_SW_Exception = 1; +static uint8_t battery_BMS_a046_SW_Task_Stack_Usage = 1; +static uint8_t battery_BMS_a047_SW_Task_Stack_Overflow = 1; +static uint8_t battery_BMS_a048_SW_Log_Upload_Request = 1; +static uint8_t battery_BMS_a169_SW_FC_Pack_Weld = 1; +static uint8_t battery_BMS_a050_SW_Brick_Voltage_MIA = 1; +static uint8_t battery_BMS_a051_SW_HVC_Vref_Bad = 1; +static uint8_t battery_BMS_a052_SW_PCS_MIA = 1; +static uint8_t battery_BMS_a053_SW_ThermalModel_Sanity = 1; +static uint8_t battery_BMS_a054_SW_Ver_Supply_Fault = 1; +static uint8_t battery_BMS_a176_SW_GracefulPowerOff = 1; +static uint8_t battery_BMS_a059_SW_Pack_Voltage_Sensing = 1; +static uint8_t battery_BMS_a060_SW_Leakage_Test_Failure = 1; +static uint8_t battery_BMS_a077_SW_Charger_Regulation = 1; +static uint8_t battery_BMS_a081_SW_Ctr_Close_Blocked = 1; +static uint8_t battery_BMS_a082_SW_Ctr_Force_Open = 1; +static uint8_t battery_BMS_a083_SW_Ctr_Close_Failure = 1; +static uint8_t battery_BMS_a084_SW_Sleep_Wake_Aborted = 1; +static uint8_t battery_BMS_a094_SW_Drive_Inverter_MIA = 1; +static uint8_t battery_BMS_a099_SW_BMB_Communication = 1; +static uint8_t battery_BMS_a105_SW_One_Module_Tsense = 1; +static uint8_t battery_BMS_a106_SW_All_Module_Tsense = 1; +static uint8_t battery_BMS_a107_SW_Stack_Voltage_MIA = 1; +static uint8_t battery_BMS_a121_SW_NVRAM_Config_Error = 1; +static uint8_t battery_BMS_a122_SW_BMS_Therm_Irrational = 1; +static uint8_t battery_BMS_a123_SW_Internal_Isolation = 1; +static uint8_t battery_BMS_a129_SW_VSH_Failure = 1; +static uint8_t battery_BMS_a131_Bleed_FET_Failure = 1; +static uint8_t battery_BMS_a136_SW_Module_OT_Warning = 1; +static uint8_t battery_BMS_a137_SW_Brick_UV_Warning = 1; +static uint8_t battery_BMS_a138_SW_Brick_OV_Warning = 1; +static uint8_t battery_BMS_a139_SW_DC_Link_V_Irrational = 1; +static uint8_t battery_BMS_a141_SW_BMB_Status_Warning = 1; +static uint8_t battery_BMS_a144_Hvp_Config_Mismatch = 1; +static uint8_t battery_BMS_a145_SW_SOC_Change = 1; +static uint8_t battery_BMS_a146_SW_Brick_Overdischarged = 1; +static uint8_t battery_BMS_a149_SW_Missing_Config_Block = 1; +static uint8_t battery_BMS_a151_SW_external_isolation = 1; +static uint8_t battery_BMS_a156_SW_BMB_Vref_bad = 1; +static uint8_t battery_BMS_a157_SW_HVP_HVS_Comms = 1; +static uint8_t battery_BMS_a159_SW_HVP_ECU_Error = 1; +static uint8_t battery_BMS_a161_SW_DI_Open_Request = 1; +static uint8_t battery_BMS_a162_SW_No_Power_For_Support = 1; +static uint8_t battery_BMS_a163_SW_Contactor_Mismatch = 1; +static uint8_t battery_BMS_a164_SW_Uncontrolled_Regen = 1; +static uint8_t battery_BMS_a165_SW_Pack_Partial_Weld = 1; +static uint8_t battery_BMS_a166_SW_Pack_Full_Weld = 1; +static uint8_t battery_BMS_a167_SW_FC_Partial_Weld = 1; +static uint8_t battery_BMS_a168_SW_FC_Full_Weld = 1; +static uint8_t battery_BMS_a170_SW_Limp_Mode = 1; +static uint8_t battery_BMS_a171_SW_Stack_Voltage_Sense = 1; +static uint8_t battery_BMS_a174_SW_Charge_Failure = 1; +static uint8_t battery_BMS_a179_SW_Hvp_12V_Fault = 1; +static uint8_t battery_BMS_a180_SW_ECU_reset_blocked = 1; + +#ifdef DOUBLE_BATTERY //need to update for battery2 static uint32_t battery2_total_discharge = 0; static uint32_t battery2_total_charge = 0; static uint16_t battery2_volts = 0; // V @@ -368,6 +631,7 @@ void update_values_battery() { //This function maps all the values fetched via #endif // TESLA_MODEL_3Y_BATTERY // Update webserver datalayer + //0x20A datalayer_extended.tesla.status_contactor = battery_contactor; datalayer_extended.tesla.hvil_status = battery_hvil_status; datalayer_extended.tesla.packContNegativeState = battery_packContNegativeState; @@ -375,11 +639,16 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.packContactorSetState = battery_packContactorSetState; datalayer_extended.tesla.packCtrsClosingAllowed = battery_packCtrsClosingAllowed; datalayer_extended.tesla.pyroTestInProgress = battery_pyroTestInProgress; - datalayer_extended.tesla.battery_beginning_of_life = battery_beginning_of_life; //add from her down - datalayer_extended.tesla.battery_battTempPct = battery_battTempPct; + datalayer_extended.tesla.battery_packCtrsOpenNowRequested = battery_packCtrsOpenNowRequested; + datalayer_extended.tesla.battery_packCtrsOpenRequested = battery_packCtrsOpenRequested; + datalayer_extended.tesla.battery_packCtrsRequestStatus = battery_packCtrsRequestStatus; + datalayer_extended.tesla.battery_packCtrsResetRequestRequired = battery_packCtrsResetRequestRequired; + datalayer_extended.tesla.battery_dcLinkAllowedToEnergize = battery_dcLinkAllowedToEnergize; + //0x2B4 datalayer_extended.tesla.battery_dcdcLvBusVolt = battery_dcdcLvBusVolt; datalayer_extended.tesla.battery_dcdcHvBusVolt = battery_dcdcHvBusVolt; datalayer_extended.tesla.battery_dcdcLvOutputCurrent = battery_dcdcLvOutputCurrent; + //0x352 datalayer_extended.tesla.battery_nominal_full_pack_energy = battery_nominal_full_pack_energy; datalayer_extended.tesla.battery_nominal_full_pack_energy_m0 = battery_nominal_full_pack_energy_m0; datalayer_extended.tesla.battery_nominal_energy_remaining = battery_nominal_energy_remaining; @@ -394,19 +663,120 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.battery_total_discharge = battery_total_discharge; datalayer_extended.tesla.battery_total_charge = battery_total_charge; datalayer_extended.tesla.battery_fully_charged = battery_fully_charged; - datalayer_extended.tesla.battery_packConfigMultiplexer = battery_packConfigMultiplexer; + //0x392 datalayer_extended.tesla.battery_moduleType = battery_moduleType; - datalayer_extended.tesla.battery_reservedConfig = battery_reservedConfig; datalayer_extended.tesla.battery_packMass = battery_packMass; datalayer_extended.tesla.battery_platformMaxBusVoltage = battery_platformMaxBusVoltage; + //0x2D2 datalayer_extended.tesla.battery_bms_min_voltage = battery_bms_min_voltage; datalayer_extended.tesla.battery_bms_max_voltage = battery_bms_max_voltage; datalayer_extended.tesla.battery_max_charge_current = battery_max_charge_current; datalayer_extended.tesla.battery_max_discharge_current = battery_max_discharge_current; + //0x292 + datalayer_extended.tesla.battery_beginning_of_life = battery_beginning_of_life; + datalayer_extended.tesla.battery_battTempPct = battery_battTempPct; datalayer_extended.tesla.battery_soc_ave = battery_soc_ave; datalayer_extended.tesla.battery_soc_max = battery_soc_max; datalayer_extended.tesla.battery_soc_min = battery_soc_min; datalayer_extended.tesla.battery_soc_ui = battery_soc_ui; + //0x332 + datalayer_extended.tesla.battery_BrickVoltageMax = battery_BrickVoltageMax; + datalayer_extended.tesla.battery_BrickVoltageMin = battery_BrickVoltageMin; + datalayer_extended.tesla.battery_BrickTempMaxNum = battery_BrickTempMaxNum; + datalayer_extended.tesla.battery_BrickTempMinNum = battery_BrickTempMinNum; + datalayer_extended.tesla.battery_BrickModelTMax = battery_BrickModelTMax; + datalayer_extended.tesla.battery_BrickModelTMin = battery_BrickModelTMin; + //0x212 + datalayer_extended.tesla.battery_BMS_isolationResistance = battery_BMS_isolationResistance; + datalayer_extended.tesla.battery_BMS_contactorState = battery_BMS_contactorState; + datalayer_extended.tesla.battery_BMS_state = battery_BMS_state; + datalayer_extended.tesla.battery_BMS_hvState = battery_BMS_hvState; + datalayer_extended.tesla.battery_BMS_uiChargeStatus = battery_BMS_uiChargeStatus; + datalayer_extended.tesla.battery_BMS_diLimpRequest = battery_BMS_diLimpRequest; + datalayer_extended.tesla.battery_BMS_chgPowerAvailable = battery_BMS_chgPowerAvailable; + datalayer_extended.tesla.battery_BMS_pcsPwmEnabled = battery_BMS_pcsPwmEnabled; + //0x224 + datalayer_extended.tesla.battery_PCS_dcdcPrechargeStatus = battery_PCS_dcdcPrechargeStatus; + datalayer_extended.tesla.battery_PCS_dcdc12VSupportStatus = battery_PCS_dcdc12VSupportStatus; + datalayer_extended.tesla.battery_PCS_dcdcHvBusDischargeStatus = battery_PCS_dcdcHvBusDischargeStatus; + datalayer_extended.tesla.battery_PCS_dcdcMainState = battery_PCS_dcdcMainState; + datalayer_extended.tesla.battery_PCS_dcdcSubState = battery_PCS_dcdcSubState; + datalayer_extended.tesla.battery_PCS_dcdcFaulted = battery_PCS_dcdcFaulted; + datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited = battery_PCS_dcdcOutputIsLimited; + datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed = battery_PCS_dcdcMaxOutputCurrentAllowed; + datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt = battery_PCS_dcdcPrechargeRtyCnt; + datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt = battery_PCS_dcdc12VSupportRtyCnt; + datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt = battery_PCS_dcdcDischargeRtyCnt; + datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine = battery_PCS_dcdcPwmEnableLine; + datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget = battery_PCS_dcdcSupportingFixedLvTarget; + datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt = battery_PCS_dcdcPrechargeRestartCnt; + datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState = battery_PCS_dcdcInitialPrechargeSubState; + //0x252 + datalayer_extended.tesla.BMS_regenerative_limit = BMS_regenerative_limit; + datalayer_extended.tesla.BMS_discharge_limit = BMS_discharge_limit; + datalayer_extended.tesla.BMS_max_heat_park = BMS_max_heat_park; + datalayer_extended.tesla.BMS_hvac_max_power = BMS_hvac_max_power; + //0x312 + datalayer_extended.tesla.BMS_powerDissipation = BMS_powerDissipation; + datalayer_extended.tesla.BMS_flowRequest = BMS_flowRequest; + datalayer_extended.tesla.BMS_inletActiveCoolTargetT = BMS_inletActiveCoolTargetT; + datalayer_extended.tesla.BMS_inletPassiveTargetT = BMS_inletPassiveTargetT; + datalayer_extended.tesla.BMS_inletActiveHeatTargetT = BMS_inletActiveHeatTargetT; + datalayer_extended.tesla.BMS_packTMin = BMS_packTMin; + datalayer_extended.tesla.BMS_packTMax = BMS_packTMax; + datalayer_extended.tesla.BMS_pcsNoFlowRequest = BMS_pcsNoFlowRequest; + datalayer_extended.tesla.BMS_noFlowRequest = BMS_noFlowRequest; + //0x2A4 + datalayer_extended.tesla.PCS_dcdcTemp = PCS_dcdcTemp; + datalayer_extended.tesla.PCS_ambientTemp = PCS_ambientTemp; + //0x2C4 + datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent = PCS_dcdcMaxLvOutputCurrent; + datalayer_extended.tesla.PCS_dcdcCurrentLimit = PCS_dcdcCurrentLimit; + datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit = PCS_dcdcLvOutputCurrentTempLimit; + datalayer_extended.tesla.PCS_dcdcUnifiedCommand = PCS_dcdcUnifiedCommand; + datalayer_extended.tesla.PCS_dcdcCLAControllerOutput = PCS_dcdcCLAControllerOutput; + datalayer_extended.tesla.PCS_dcdcTankVoltage = PCS_dcdcTankVoltage; + datalayer_extended.tesla.PCS_dcdcTankVoltageTarget = PCS_dcdcTankVoltageTarget; + datalayer_extended.tesla.PCS_dcdcClaCurrentFreq = PCS_dcdcClaCurrentFreq; + datalayer_extended.tesla.PCS_dcdcTCommMeasured = PCS_dcdcTCommMeasured; + datalayer_extended.tesla.PCS_dcdcShortTimeUs = PCS_dcdcShortTimeUs; + datalayer_extended.tesla.PCS_dcdcHalfPeriodUs = PCS_dcdcHalfPeriodUs; + datalayer_extended.tesla.PCS_dcdcIntervalMaxFrequency = PCS_dcdcIntervalMaxFrequency; + datalayer_extended.tesla.PCS_dcdcIntervalMaxHvBusVolt = PCS_dcdcIntervalMaxHvBusVolt; + datalayer_extended.tesla.PCS_dcdcIntervalMaxLvBusVolt = PCS_dcdcIntervalMaxLvBusVolt; + datalayer_extended.tesla.PCS_dcdcIntervalMaxLvOutputCurr = PCS_dcdcIntervalMaxLvOutputCurr; + datalayer_extended.tesla.PCS_dcdcIntervalMinFrequency = PCS_dcdcIntervalMinFrequency; + datalayer_extended.tesla.PCS_dcdcIntervalMinHvBusVolt = PCS_dcdcIntervalMinHvBusVolt; + datalayer_extended.tesla.PCS_dcdcIntervalMinLvBusVolt = PCS_dcdcIntervalMinLvBusVolt; + datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr = PCS_dcdcIntervalMinLvOutputCurr; + datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh = PCS_dcdc12vSupportLifetimekWh; + //0x7AA + datalayer_extended.tesla.HVP_hvp1v5Ref = HVP_hvp1v5Ref; + datalayer_extended.tesla.HVP_shuntCurrentDebug = HVP_shuntCurrentDebug; + datalayer_extended.tesla.HVP_dcLinkVoltage = HVP_dcLinkVoltage; + datalayer_extended.tesla.HVP_packVoltage = HVP_packVoltage; + datalayer_extended.tesla.HVP_fcLinkVoltage = HVP_fcLinkVoltage; + datalayer_extended.tesla.HVP_packContVoltage = HVP_packContVoltage; + datalayer_extended.tesla.HVP_packNegativeV = HVP_packNegativeV; + datalayer_extended.tesla.HVP_packPositiveV = HVP_packPositiveV; + datalayer_extended.tesla.HVP_pyroAnalog = HVP_pyroAnalog; + datalayer_extended.tesla.HVP_dcLinkNegativeV = HVP_dcLinkNegativeV; + datalayer_extended.tesla.HVP_dcLinkPositiveV = HVP_dcLinkPositiveV; + datalayer_extended.tesla.HVP_fcLinkNegativeV = HVP_fcLinkNegativeV; + datalayer_extended.tesla.HVP_fcContCoilCurrent = HVP_fcContCoilCurrent; + datalayer_extended.tesla.HVP_fcContVoltage = HVP_fcContVoltage; + datalayer_extended.tesla.HVP_hvilInVoltage = HVP_hvilInVoltage; + datalayer_extended.tesla.HVP_hvilOutVoltage = HVP_hvilOutVoltage; + datalayer_extended.tesla.HVP_fcLinkPositiveV = HVP_fcLinkPositiveV; + datalayer_extended.tesla.HVP_packContCoilCurrent = HVP_packContCoilCurrent; + datalayer_extended.tesla.HVP_battery12V = HVP_battery12V; + datalayer_extended.tesla.HVP_shuntRefVoltageDbg = HVP_shuntRefVoltageDbg; + datalayer_extended.tesla.HVP_shuntAuxCurrentDbg = HVP_shuntAuxCurrentDbg; + datalayer_extended.tesla.HVP_shuntBarTempDbg = HVP_shuntBarTempDbg; + datalayer_extended.tesla.HVP_shuntAsicTempDbg = HVP_shuntAsicTempDbg; + datalayer_extended.tesla.HVP_shuntAuxCurrentStatus = HVP_shuntAuxCurrentStatus; + datalayer_extended.tesla.HVP_shuntBarTempStatus = HVP_shuntBarTempStatus; + datalayer_extended.tesla.HVP_shuntAsicTempStatus = HVP_shuntAsicTempStatus; #ifdef DEBUG_VIA_USB @@ -482,15 +852,21 @@ void receive_can_battery(CAN_frame rx_frame) { mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X if (mux == 0) { - //battery_nominal_full_pack_energy_m0 = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X - //battery_nominal_energy_remaining_m0 = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]); //BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X - //battery_ideal_energy_remaining_m0 = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); //BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X + battery_nominal_full_pack_energy_m0 = + ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //16|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended + battery_nominal_energy_remaining_m0 = + ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]); //32|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended + battery_ideal_energy_remaining_m0 = + ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); //48|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended } if (mux == 1) { - //battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X - //battery_energy_buffer_m1 = (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X - //battery_expected_energy_remaining_m1 = (rx_frame.data.u8[5] | rx_frame.data.u8[4]); //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X - //battery_energy_to_charge_complete_m1 = (rx_frame.data.u8[7] | rx_frame.data.u8[6]); //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //15|1@1+ (1,0) [0|1]//to datalayer_extended + battery_energy_buffer_m1 = + (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //16|16@1+ (0.01,0) [0|0] "kWh"//to datalayer_extended + battery_expected_energy_remaining_m1 = + (rx_frame.data.u8[5] | rx_frame.data.u8[4]); //32|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended + battery_energy_to_charge_complete_m1 = + (rx_frame.data.u8[7] | rx_frame.data.u8[6]); //48|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended } if (mux == 2) {} // Additional information needed on this mux, example frame: 02 26 02 20 02 80 00 00 doesn't change @@ -511,39 +887,112 @@ void receive_can_battery(CAN_frame rx_frame) { battery_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); ((rx_frame.data.u8[7] & 0x01) >> 7); break; - case 0x20A: //Contactor state //HVP_contactorState: - battery_packContNegativeState = (rx_frame.data.u8[0] & 0x07); //0|3@1+ (1,0) [0|7] "" - battery_packContPositiveState = (rx_frame.data.u8[0] & 0x38) >> 3; //3|3@1+ (1,0) [0|7] "" - battery_contactor = (rx_frame.data.u8[1] & 0x0F); //HVP_packContactorSetState : 8|4@1+ (1,0) [0|9] "" - battery_packContactorSetState = (rx_frame.data.u8[1] & 0x0F); //HVP_packContactorSetState : 8|4@1+ (1,0) [0|9] "" - battery_packCtrsClosingAllowed = (rx_frame.data.u8[4] & 0x08) >> 3; //35|1@1+ (1,0) [0|1] "" - battery_pyroTestInProgress = (rx_frame.data.u8[4] & 0x20) >> 5; //37|1@1+ (1,0) [0|1] "" - battery_hvil_status = (rx_frame.data.u8[5] & 0x0F); //40|4@1+ (1,0) [0|9] "" - //HVP_packCtrsOpenNowRequested : 33|1@1+ (1,0) [0|1] "" - //HVP_packCtrsOpenRequested : 34|1@1+ (1,0) [0|1] "" - //HVP_packCtrsRequestStatus : 30|2@1+ (1,0) [0|2] "" - //HVP_packCtrsResetRequestRequired : 32|1@1+ (1,0) [0|1] "" - //HVP_dcLinkAllowedToEnergize : 36|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContNegativeAuxOpen : 7|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContNegativeState : 12|3@1+ (1,0) [0|7] "" Receiver - //HVP_fcContPositiveAuxOpen : 6|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContPositiveState : 16|3@1+ (1,0) [0|7] "" Receiver - //HVP_fcContactorSetState : 19|4@1+ (1,0) [0|9] "" Receiver - //HVP_fcCtrsClosingAllowed : 29|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsOpenNowRequested : 27|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsOpenRequested : 28|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsRequestStatus : 24|2@1+ (1,0) [0|2] "" Receiver - //HVP_fcCtrsResetRequestRequired : 26|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcLinkAllowedToEnergize : 44|2@1+ (1,0) [0|2] "" Receiver + case 0x20A: //522 HVP_contactorState: + battery_packContNegativeState = + (rx_frame.data.u8[0] & 0x07); //(_d[0] & (0x07U)); 0|3@1+ (1,0) [0|7] //to datalayer_extended + battery_packContPositiveState = + (rx_frame.data.u8[0] & 0x38) >> 3; //((_d[0] >> 3) & (0x07U)); 3|3@1+ (1,0) [0|7] //to datalayer_extended + battery_contactor = (rx_frame.data.u8[1] & 0x0F); // 8|4@1+ (1,0) [0|9] //to datalayer_extended + battery_packContactorSetState = + (rx_frame.data.u8[1] & 0x0F); //(_d[1] & (0x0FU)); 8|4@1+ (1,0) [0|9] //to datalayer_extended + battery_packCtrsClosingAllowed = + (rx_frame.data.u8[4] & 0x08) >> 3; //((_d[4] >> 3) & (0x01U)); 35|1@1+ (1,0) [0|1] //to datalayer_extended + battery_pyroTestInProgress = + (rx_frame.data.u8[4] & 0x20) >> 5; //((_d[4] >> 5) & (0x01U));//37|1@1+ (1,0) [0|1] //to datalayer_extended + battery_hvil_status = + (rx_frame.data.u8[5] & 0x0F); //(_d[5] & (0x0FU)); //40|4@1+ (1,0) [0|9] //to datalayer_extended + battery_packCtrsOpenNowRequested = + ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|1] //to datalayer_extended + battery_packCtrsOpenRequested = + ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|1] //to datalayer_extended + battery_packCtrsRequestStatus = + ((rx_frame.data.u8[3] >> 6) & (0x03U)); //30|2@1+ (1,0) [0|2] //to datalayer_extended + battery_packCtrsResetRequestRequired = + (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|1] //to datalayer_extended + battery_dcLinkAllowedToEnergize = + ((rx_frame.data.u8[4] >> 4) & (0x01U)); //36|1@1+ (1,0) [0|1] //to datalayer_extended + battery_fcContNegativeAuxOpen = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|1] "" Receiver + battery_fcContNegativeState = ((rx_frame.data.u8[1] >> 4) & (0x07U)); //12|3@1+ (1,0) [0|7] "" Receiver + battery_fcContPositiveAuxOpen = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|1] "" Receiver + battery_fcContPositiveState = (rx_frame.data.u8[2] & (0x07U)); //16|3@1+ (1,0) [0|7] "" Receiver + battery_fcContactorSetState = ((rx_frame.data.u8[2] >> 3) & (0x0FU)); //19|4@1+ (1,0) [0|9] "" Receiver + battery_fcCtrsClosingAllowed = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|1] "" Receiver + battery_fcCtrsOpenNowRequested = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|1] "" Receiver + battery_fcCtrsOpenRequested = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|1] "" Receiver + battery_fcCtrsRequestStatus = (rx_frame.data.u8[3] & (0x03U)); //24|2@1+ (1,0) [0|2] "" Receiver + battery_fcCtrsResetRequestRequired = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|1] "" Receiver + battery_fcLinkAllowedToEnergize = ((rx_frame.data.u8[5] >> 4) & (0x03U)); //44|2@1+ (1,0) [0|2] "" Receiver + break; + case 0x212: //530 BMS_status: 8 + battery_BMS_hvacPowerRequest = (rx_frame.data.u8[0] & (0x01U)); + battery_BMS_notEnoughPowerForDrive = ((rx_frame.data.u8[0] >> 1) & (0x01U)); + battery_BMS_notEnoughPowerForSupport = ((rx_frame.data.u8[0] >> 2) & (0x01U)); + battery_BMS_preconditionAllowed = ((rx_frame.data.u8[0] >> 3) & (0x01U)); + battery_BMS_updateAllowed = ((rx_frame.data.u8[0] >> 4) & (0x01U)); + battery_BMS_activeHeatingWorthwhile = ((rx_frame.data.u8[0] >> 5) & (0x01U)); + battery_BMS_cpMiaOnHvs = ((rx_frame.data.u8[0] >> 6) & (0x01U)); + battery_BMS_contactorState = + (rx_frame.data.u8[1] & + (0x07U)); //0 "SNA" 1 "OPEN" 2 "OPENING" 3 "CLOSING" 4 "CLOSED" 5 "WELDED" 6 "BLOCKED" ; + battery_BMS_state = + ((rx_frame.data.u8[1] >> 3) & + (0x0FU)); //0 "STANDBY" 1 "DRIVE" 2 "SUPPORT" 3 "CHARGE" 4 "FEIM" 5 "CLEAR_FAULT" 6 "FAULT" 7 "WELD" 8 "TEST" 9 "SNA" ; + battery_BMS_hvState = + (rx_frame.data.u8[2] & + (0x07U)); //0 "DOWN" 1 "COMING_UP" 2 "GOING_DOWN" 3 "UP_FOR_DRIVE" 4 "UP_FOR_CHARGE" 5 "UP_FOR_DC_CHARGE" 6 "UP" ; + battery_BMS_isolationResistance = + ((rx_frame.data.u8[3] & (0x1FU)) << 5) | + ((rx_frame.data.u8[2] >> 3) & (0x1FU)); //19|10@1+ (10,0) [0|0] "kOhm"/to datalayer_extended + battery_BMS_chargeRequest = ((rx_frame.data.u8[3] >> 5) & (0x01U)); + battery_BMS_keepWarmRequest = ((rx_frame.data.u8[3] >> 6) & (0x01U)); + battery_BMS_uiChargeStatus = + (rx_frame.data.u8[4] & + (0x07U)); // 0 "DISCONNECTED" 1 "NO_POWER" 2 "ABOUT_TO_CHARGE" 3 "CHARGING" 4 "CHARGE_COMPLETE" 5 "CHARGE_STOPPED" ; + battery_BMS_diLimpRequest = ((rx_frame.data.u8[4] >> 3) & (0x01U)); + battery_BMS_okToShipByAir = ((rx_frame.data.u8[4] >> 4) & (0x01U)); + battery_BMS_okToShipByLand = ((rx_frame.data.u8[4] >> 5) & (0x01U)); + battery_BMS_chgPowerAvailable = ((rx_frame.data.u8[6] & (0x01U)) << 10) | ((rx_frame.data.u8[5] & (0xFFU)) << 2) | + ((rx_frame.data.u8[4] >> 6) & (0x03U)); //38|11@1+ (0.125,0) [0|0] "kW" + battery_BMS_chargeRetryCount = ((rx_frame.data.u8[6] >> 1) & (0x0FU)); + battery_BMS_pcsPwmEnabled = ((rx_frame.data.u8[6] >> 5) & (0x01U)); + battery_BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); + battery_BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC + break; + case 0x224: //548 PCS_dcdcStatus: + battery_PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ; + battery_PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" + battery_PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" + battery_PCS_dcdcMainState = + ((rx_frame.data.u8[1] & (0x03U)) << 2) | + ((rx_frame.data.u8[0] >> 6) & + (0x03U)); //0 "STANDBY" 1 "12V_SUPPORT_ACTIVE" 2 "PRECHARGE_STARTUP" 3 "PRECHARGE_ACTIVE" 4 "DIS_HVBUS_ACTIVE" 5 "SHUTDOWN" 6 "FAULTED" ; + battery_PCS_dcdcSubState = + ((rx_frame.data.u8[1] >> 2) & + (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; + battery_PCS_dcdcFaulted = ((rx_frame.data.u8[1] >> 7) & (0x01U)); + battery_PCS_dcdcOutputIsLimited = ((rx_frame.data.u8[3] >> 4) & (0x01U)); + battery_PCS_dcdcMaxOutputCurrentAllowed = ((rx_frame.data.u8[5] & (0x01U)) << 11) | + ((rx_frame.data.u8[4] & (0xFFU)) << 3) | + ((rx_frame.data.u8[3] >> 5) & (0x07U)); //29|12@1+ (0.1,0) [0|0] "A" + battery_PCS_dcdcPrechargeRtyCnt = ((rx_frame.data.u8[5] >> 1) & (0x07U)); + battery_PCS_dcdc12VSupportRtyCnt = ((rx_frame.data.u8[5] >> 4) & (0x0FU)); + battery_PCS_dcdcDischargeRtyCnt = (rx_frame.data.u8[6] & (0x0FU)); + battery_PCS_dcdcPwmEnableLine = ((rx_frame.data.u8[6] >> 4) & (0x01U)); + battery_PCS_dcdcSupportingFixedLvTarget = ((rx_frame.data.u8[6] >> 5) & (0x01U)); + battery_PCS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); + battery_PCS_dcdcPrechargeRestartCnt = (rx_frame.data.u8[7] & (0x07U)); + battery_PCS_dcdcInitialPrechargeSubState = + ((rx_frame.data.u8[7] >> 3) & + (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; break; case 0x252: //Limit //BMS_powerAvailable252: - battery_regenerative_limit = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * + BMS_regenerative_limit = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.01; //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW - battery_discharge_limit = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * + BMS_discharge_limit = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * 0.013; //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? - battery_max_heat_park = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]) * + BMS_max_heat_park = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]) * 0.01; //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW - battery_hvac_max_power = (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))) * + BMS_hvac_max_power = (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))) * 0.02; //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] "" Receiver @@ -584,27 +1033,122 @@ void receive_can_battery(CAN_frame rx_frame) { temp = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); temp = (temp & 0xFFF); battery_cell_min_v = temp * 2; - battery_max_vno = 1 + (rx_frame.data.u8[4] & 0x7F); //This cell has highest voltage - battery_min_vno = 1 + (rx_frame.data.u8[5] & 0x7F); //This cell has lowest voltage + //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[1] & (0x3FU)) << 6) | ((_d[0] >> 2) & (0x3FU)); + battery_BrickVoltageMax = + ((rx_frame.data.u8[1] & (0x3F)) << 6) | ((rx_frame.data.u8[0] >> 2) & (0x3F)); //to datalayer_extended + //BattBrickVoltageMin m1 : 16|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[3] & (0x0FU)) << 8) | (_d[2] & (0xFFU)); + battery_BrickVoltageMin = + ((rx_frame.data.u8[3] & (0x0F)) << 8) | (rx_frame.data.u8[2] & (0xFF)); //to datalayer_extended + //BattBrickVoltageMaxNum m1 : 32|7@1+ (1,1) [0|0] "" Receiver + battery_BrickVoltageMaxNum = + 1 + (rx_frame.data.u8[4] & 0x7F); //(_d[4] & (0x7FU)); //This cell has highest voltage + //BattBrickVoltageMinNum m1 : 40|7@1+ (1,1) [0|0] "" Receiver + battery_BrickVoltageMinNum = + 1 + (rx_frame.data.u8[5] & 0x7F); //(_d[5] & (0x7FU)); //This cell has lowest voltage } if (mux == 0) //Temperature sensors - { + { //BattBrickTempMax m0 : 16|8@1+ (0.5,-40) [0|0] "C" (_d[2] & (0xFFU)); battery_max_temp = (rx_frame.data.u8[2] * 5) - 400; //Temperature values have 40.0*C offset, 0.5*C /bit + //BattBrickTempMin m0 : 24|8@1+ (0.5,-40) [0|0] "C" (_d[3] & (0xFFU)); battery_min_temp = (rx_frame.data.u8[3] * 5) - 400; //Multiply by 5 and remove offset to get C+1 (0x61*5=485-400=8.5*C) + //BattBrickTempMaxNum m0 : 2|4@1+ (1,0) [0|0] "" ((_d[0] >> 2) & (0x0FU)); + battery_BrickTempMaxNum = ((rx_frame.data.u8[0] >> 2) & (0x0F)); //to datalayer_extended + //BattBrickTempMinNum m0 : 8|4@1+ (1,0) [0|0] "" (_d[1] & (0x0FU)); + battery_BrickTempMinNum = (rx_frame.data.u8[1] & (0x0F)); //to datalayer_extended + //BattBrickModelTMax m0 : 32|8@1+ (0.5,-40) [0|0] "C" (_d[4] & (0xFFU)); + battery_BrickModelTMax = (rx_frame.data.u8[4] & (0xFFU)); //to datalayer_extended + //BattBrickModelTMin m0 : 40|8@1+ (0.5,-40) [0|0] "C" (_d[5] & (0xFFU)); + battery_BrickModelTMin = (rx_frame.data.u8[5] & (0xFFU)); //to datalayer_extended } - //BattBrickMultiplexer M : 0|2@1+ (1,0) [0|0] "" Receiver - //BattBrickTempMaxNum m0 : 2|4@1+ (1,0) [0|0] "" Receiver - //BattBrickTempMinNum m0 : 8|4@1+ (1,0) [0|0] "" Receiver - //BattBrickTempMax m0 : 16|8@1+ (0.5,-40) [0|0] "C" Receiver - //BattBrickTempMin m0 : 24|8@1+ (0.5,-40) [0|0] "C" Receiver - //BattBrickModelTMax m0 : 32|8@1+ (0.5,-40) [0|0] "C" Receiver - //BattBrickModelTMin m0 : 40|8@1+ (0.5,-40) [0|0] "C" Receiver - //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver - //BattBrickVoltageMin m1 : 16|12@1+ (0.002,0) [0|0] "V" Receiver - //BattBrickVoltageMaxNum m1 : 32|7@1+ (1,1) [0|0] "" Receiver - //BattBrickVoltageMinNum m1 : 40|7@1+ (1,1) [0|0] "" Receiver break; + case 0x312: // 786 BMS_thermalStatus + BMS_powerDissipation = + ((rx_frame.data.u8[1] & (0x03U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|10@1+ (0.02,0) [0|0] "kW" + BMS_flowRequest = ((rx_frame.data.u8[2] & (0x01U)) << 6) | + ((rx_frame.data.u8[1] >> 2) & (0x3FU)); //10|7@1+ (0.3,0) [0|0] "LPM" + BMS_inletActiveCoolTargetT = ((rx_frame.data.u8[3] & (0x03U)) << 7) | + ((rx_frame.data.u8[2] >> 1) & (0x7FU)); //17|9@1+ (0.25,-25) [0|0] "DegC" + BMS_inletPassiveTargetT = ((rx_frame.data.u8[4] & (0x07U)) << 6) | + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //26|9@1+ (0.25,-25) [0|0] "DegC" X + BMS_inletActiveHeatTargetT = ((rx_frame.data.u8[5] & (0x0FU)) << 5) | + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|9@1+ (0.25,-25) [0|0] "DegC" + BMS_packTMin = ((rx_frame.data.u8[6] & (0x1FU)) << 4) | + ((rx_frame.data.u8[5] >> 4) & (0x0FU)); //44|9@1+ (0.25,-25) [-25|100] "DegC" + BMS_packTMax = ((rx_frame.data.u8[7] & (0x3FU)) << 3) | + ((rx_frame.data.u8[6] >> 5) & (0x07U)); //53|9@1+ (0.25,-25) [-25|100] "DegC" + BMS_pcsNoFlowRequest = ((rx_frame.data.u8[7] >> 6) & (0x01U)); // 62|1@1+ (1,0) [0|0] "" + BMS_noFlowRequest = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" + break; + case 0x2A4: //676 PCS_thermalStatus + PCS_chgPhATemp = + ((rx_frame.data.u8[1] & (0x07U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|11@1- (0.1,40) [0|0] "C + PCS_chgPhBTemp = + ((rx_frame.data.u8[2] & (0x3FU)) << 5) | ((rx_frame.data.u8[1] >> 3) & (0x1FU)); //11|11@1- (0.1,40) [0|0] "C + PCS_chgPhCTemp = + ((rx_frame.data.u8[4] & (0x07U)) << 8) | (rx_frame.data.u8[3] & (0xFFU)); //24|11@1- (0.1,40) [0|0] "C" + PCS_dcdcTemp = ((rx_frame.data.u8[5] & (0x3FU)) << 5) | + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|11@1- (0.1,40) [0|0] "C" + PCS_ambientTemp = + ((rx_frame.data.u8[7] & (0x07U)) << 8) | (rx_frame.data.u8[6] & (0xFFU)); //48|11@1- (0.1,40) [0|0] "C" + break; + case 0x2C4: // 708 PCS_logging: not all frames are listed, just ones relating to dcdc + mux = (rx_frame.data.u8[0] & (0x1FU)); + //PCS_logMessageSelect = (rx_frame.data.u8[0] & (0x1FU)); //0|5@1+ (1,0) [0|0] "" + if (mux == 6) { + PCS_dcdcMaxLvOutputCurrent = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //m6 : 28|12@1+ (0.1,0) [0|0] "A" X + PCS_dcdcCurrentLimit = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //m6 : 40|12@1+ (0.1,0) [0|0] "A" X + PCS_dcdcLvOutputCurrentTempLimit = ((rx_frame.data.u8[7] & (0xFFU)) << 4) | + ((rx_frame.data.u8[6] >> 4) & (0x0FU)); //m6 : 52|12@1+ (0.1,0) [0|0] "A" X + } + if (mux == 7) { + PCS_dcdcUnifiedCommand = ((rx_frame.data.u8[1] & (0x7FU)) << 3) | + ((rx_frame.data.u8[0] >> 5) & (0x07U)); //m7 : 5|10@1+ (0.001,0) [0|0] "1" X + PCS_dcdcCLAControllerOutput = ((rx_frame.data.u8[3] & (0x03U)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //m7 : 16|10@1+ (0.001,0) [0|0] "1" X + PCS_dcdcTankVoltage = ((rx_frame.data.u8[4] & (0x1FU)) << 6) | + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //m7 : 26|11@1- (1,0) [0|0] "V" X + PCS_dcdcTankVoltageTarget = ((rx_frame.data.u8[5] & (0x7FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m7 : 37|10@1+ (1,0) [0|0] "V" X + PCS_dcdcClaCurrentFreq = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //P m7 : 48|12@1+ (0.0976563,0) [0|0] "kHz" X + } + if (mux == 8) { + PCS_dcdcTCommMeasured = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m8 : 8|16@1- (0.00195313,0) [0|0] "us" X + PCS_dcdcShortTimeUs = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); // m8 : 24|16@1+ (0.000488281,0) [0|0] "us" X + PCS_dcdcHalfPeriodUs = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); // m8 : 40|16@1+ (0.000488281,0) [0|0] "us" X + } + if (mux == 18) { + PCS_dcdcIntervalMaxFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m18 : 8|12@1+ (1,0) [0|0] "kHz" X + PCS_dcdcIntervalMaxHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //m18 : 24|13@1+ (0.1,0) [0|0] "V" X + PCS_dcdcIntervalMaxLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m18 : 37|9@1+ (0.1,0) [0|0] "V" X + PCS_dcdcIntervalMaxLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //m18 : 48|12@1+ (1,0) [0|0] "A" X + } + if (mux == 19) { + PCS_dcdcIntervalMinFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //m19 : 8|12@1+ (1,0) [0|0] "kHz" X + PCS_dcdcIntervalMinHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //m19 : 24|13@1+ (0.1,0) [0|0] "V" X + PCS_dcdcIntervalMinLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); //m19 : 37|9@1+ (0.1,0) [0|0] "V" X + PCS_dcdcIntervalMinLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); // m19 : 48|12@1+ (1,0) [0|0] "A" X + } + if (mux == 22) { + PCS_dcdc12vSupportLifetimekWh = ((rx_frame.data.u8[3] & (0xFFU)) << 16) | + ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m22 : 8|24@1+ (0.01,0) [0|0] "kWh" X + } + break; case 0x401: // Cell stats //BrickVoltages mux = (rx_frame.data.u8[0]); //MultiplexSelector M : 0|8@1+ (1,0) [0|0] "" //StatusFlags : 8|8@1+ (1,0) [0|0] "" @@ -677,13 +1221,110 @@ void receive_can_battery(CAN_frame rx_frame) { mux = (rx_frame.data.u8[0] & (0xFF)); if (mux == 1) { battery_packConfigMultiplexer = (rx_frame.data.u8[0] & (0xff)); //0|8@1+ (1,0) [0|1] "" - battery_moduleType = (rx_frame.data.u8[1] & (0x07)); //8|3@1+ (1,0) [0|4] "" + battery_moduleType = (rx_frame.data.u8[1] & (0x07)); //8|3@1+ (1,0) [0|4] ""//0 "UNKNOWN" 1 "E3_NCT" 2 "E1_NCT" 3 "E3_CT" 4 "E1_CT" 5 "E1_CP" ;//to datalayer_extended battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg" battery_platformMaxBusVoltage = (((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3])); //24|10@1+ (0.1,375) [0|0] "V" } if (mux == 0) { - battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); //8|5@1+ (1,0) [0|31] "" + battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); //8|5@1+ (1,0) [0|31] ""//0 "BMS_CONFIG_0" 1 "BMS_CONFIG_1" 10 "BMS_CONFIG_10" 11 "BMS_CONFIG_11" 12 "BMS_CONFIG_12" 13 "BMS_CONFIG_13" 14 "BMS_CONFIG_14" 15 "BMS_CONFIG_15" 16 "BMS_CONFIG_16" 17 "BMS_CONFIG_17" 18 "BMS_CONFIG_18" 19 "BMS_CONFIG_19" 2 "BMS_CONFIG_2" 20 "BMS_CONFIG_20" 21 "BMS_CONFIG_21" 22 "BMS_CONFIG_22" 23 "BMS_CONFIG_23" 24 "BMS_CONFIG_24" 25 "BMS_CONFIG_25" 26 "BMS_CONFIG_26" 27 "BMS_CONFIG_27" 28 "BMS_CONFIG_28" 29 "BMS_CONFIG_29" 3 "BMS_CONFIG_3" 30 "BMS_CONFIG_30" 31 "BMS_CONFIG_31" 4 "BMS_CONFIG_4" 5 "BMS_CONFIG_5" 6 "BMS_CONFIG_6" 7 "BMS_CONFIG_7" 8 "BMS_CONFIG_8" 9 "BMS_CONFIG_9" ; + } + break; + case 0x7AA: //1962 HVP_debugMessage: + mux = (rx_frame.data.u8[0] & (0x0FU)); + //HVP_debugMessageMultiplexer = (rx_frame.data.u8[0] & (0x0FU)); //0|4@1+ (1,0) [0|6] "" + if (mux == 0) { + HVP_gpioPassivePyroDepl = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //: 4|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPyroIsoEn = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //: 5|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioCpFaultIn = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //: 6|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPackContPowerEn = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //: 7|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioHvCablesOk = (rx_frame.data.u8[1] & (0x01U)); //: 8|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioHvpSelfEnable = ((rx_frame.data.u8[1] >> 1) & (0x01U)); //: 9|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioLed = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //: 10|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioCrashSignal = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //: 11|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioShuntDataReady = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //: 12|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioFcContPosAux = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //: 13|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioFcContNegAux = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //: 14|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioBmsEout = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //: 15|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioCpFaultOut = (rx_frame.data.u8[2] & (0x01U)); //: 16|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPyroPor = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //: 17|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioShuntEn = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //: 18|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioHvpVerEn = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //: 19|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPackCoontPosFlywheel = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //: 20|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioCpLatchEnable = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //: 21|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPcsEnable = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //: 22|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPcsDcdcPwmEnable = ((rx_frame.data.u8[2] >> 7) & (0x01U)); //: 23|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPcsChargePwmEnable = (rx_frame.data.u8[3] & (0x01U)); //: 24|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioFcContPowerEnable = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //: 25|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioHvilEnable = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //: 26|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioSecDrdy = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //: 27|1@1+ (1,0) [0|1] "" Receiver + HVP_hvp1v5Ref = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|3] "V" Receiver + HVP_shuntCurrentDebug = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP_packCurrentMia = (rx_frame.data.u8[7] & (0x01U)); //: 56|1@1+ (1,0) [0|1] "" Receiver + HVP_auxCurrentMia = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //: 57|1@1+ (1,0) [0|1] "" Receiver + HVP_currentSenseMia = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|1@1+ (1,0) [0|1] "" Receiver + HVP_shuntRefVoltageMismatch = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //: 59|1@1+ (1,0) [0|1] "" Receiver + HVP_shuntThermistorMia = ((rx_frame.data.u8[7] >> 4) & (0x01U)); //: 60|1@1+ (1,0) [0|1] "" Receiver + HVP_shuntHwMia = ((rx_frame.data.u8[7] >> 5) & (0x01U)); //: 61|1@1+ (1,0) [0|1] "" Receiver + } + if (mux == 1) { + HVP_dcLinkVoltage = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + HVP_packVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + HVP_fcLinkVoltage = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + } + if (mux == 2) { + HVP_packContVoltage = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|30] "V" Receiver + HVP_packNegativeV = ((rx_frame.data.u8[3] & (0xFFU)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //: 16|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_packPositiveV = ((rx_frame.data.u8[5] & (0xFFU)) << 8) | + (rx_frame.data.u8[4] & (0xFFU)); //: 32|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_pyroAnalog = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|12@1+ (0.1,0) [0|3] "V" Receiver + } + if (mux == 3) { + HVP_dcLinkNegativeV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_dcLinkPositiveV = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_fcLinkNegativeV = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-550|550] "V" Receiver + } + if (mux == 4) { + HVP_fcContCoilCurrent = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|7.5] "A" Receiver + HVP_fcContVoltage = ((rx_frame.data.u8[3] & (0x0FU)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //: 16|12@1+ (0.1,0) [0|30] "V" Receiver + HVP_hvilInVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|30] "V" Receiver + HVP_hvilOutVoltage = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|12@1+ (0.1,0) [0|30] "V" Receiver + } + if (mux == 5) { + HVP_fcLinkPositiveV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_packContCoilCurrent = ((rx_frame.data.u8[4] & (0x0FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|12@1+ (0.1,0) [0|7.5] "A" Receiver + HVP_battery12V = ((rx_frame.data.u8[5] & (0xFFU)) << 4) | + ((rx_frame.data.u8[4] >> 4) & (0x0FU)); //: 36|12@1+ (0.1,0) [0|30] "V" Receiver + HVP_shuntRefVoltageDbg = ((rx_frame.data.u8[7] & (0xFFU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|16@1- (0.001,0) [-32.768|32.767] "V" Receiver + } + if (mux == 6) { + HVP_shuntAuxCurrentDbg = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP_shuntBarTempDbg = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + HVP_shuntAsicTempDbg = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + HVP_shuntAuxCurrentStatus = (rx_frame.data.u8[7] & (0x03U)); //: 56|2@1+ (1,0) [0|3] "" Receiver + HVP_shuntBarTempStatus = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|2@1+ (1,0) [0|3] "" Receiver + HVP_shuntAsicTempStatus = ((rx_frame.data.u8[7] >> 4) & (0x03U)); //: 60|2@1+ (1,0) [0|3] "" Receiver } break; case 0x3aa: //HVP_alertMatrix1 @@ -739,12 +1380,116 @@ void receive_can_battery(CAN_frame rx_frame) { battery_fcCtrCloseFailed = ((rx_frame.data.u8[6] & 0x02) >> 1); battery_shuntThermistorMia = ((rx_frame.data.u8[6] & 0x04) >> 2); break; + case 0x320: //800 BMS_alertMatrix //BMS_alertMatrix 800 BMS_alertMatrix: 8 VEH + mux = (rx_frame.data.u8[0] & (0x0F)); + if (mux == 0) + ; + { //mux0 + battery_BMS_matrixIndex = (rx_frame.data.u8[0] & (0x0F)); // 0|4@1+ (1,0) [0|0] "" X + battery_BMS_a017_SW_Brick_OV = ((rx_frame.data.u8[2] >> 4) & (0x01)); //20|1@1+ (1,0) [0|0] "" X + battery_BMS_a018_SW_Brick_UV = ((rx_frame.data.u8[2] >> 5) & (0x01)); //21|1@1+ (1,0) [0|0] "" X + battery_BMS_a019_SW_Module_OT = ((rx_frame.data.u8[2] >> 6) & (0x01)); //22|1@1+ (1,0) [0|0] "" X + battery_BMS_a021_SW_Dr_Limits_Regulation = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery_BMS_a022_SW_Over_Current = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X + battery_BMS_a023_SW_Stack_OV = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X + battery_BMS_a024_SW_Islanded_Brick = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery_BMS_a025_SW_PwrBalance_Anomaly = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X + battery_BMS_a026_SW_HFCurrent_Anomaly = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X + battery_BMS_a034_SW_Passive_Isolation = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X ? + battery_BMS_a035_SW_Isolation = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //38|1@1+ (1,0) [0|0] "" X + battery_BMS_a036_SW_HvpHvilFault = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X + battery_BMS_a037_SW_Flood_Port_Open = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X + battery_BMS_a039_SW_DC_Link_Over_Voltage = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery_BMS_a041_SW_Power_On_Reset = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X + battery_BMS_a042_SW_MPU_Error = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X + battery_BMS_a043_SW_Watch_Dog_Reset = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X + battery_BMS_a044_SW_Assertion = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X + battery_BMS_a045_SW_Exception = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery_BMS_a046_SW_Task_Stack_Usage = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery_BMS_a047_SW_Task_Stack_Overflow = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + battery_BMS_a048_SW_Log_Upload_Request = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X + battery_BMS_a050_SW_Brick_Voltage_MIA = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X + battery_BMS_a051_SW_HVC_Vref_Bad = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X + battery_BMS_a052_SW_PCS_MIA = ((rx_frame.data.u8[6] >> 7) & (0x01U)); //55|1@1+ (1,0) [0|0] "" X + battery_BMS_a053_SW_ThermalModel_Sanity = (rx_frame.data.u8[7] & (0x01U)); //56|1@1+ (1,0) [0|0] "" X + battery_BMS_a054_SW_Ver_Supply_Fault = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X + battery_BMS_a059_SW_Pack_Voltage_Sensing = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X + battery_BMS_a060_SW_Leakage_Test_Failure = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X + } + if (mux == 1) { //mux1 + battery_BMS_a061_robinBrickOverVoltage = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //4|1@1+ (1,0) [0|0] "" X + battery_BMS_a062_SW_BrickV_Imbalance = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X + battery_BMS_a063_SW_ChargePort_Fault = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X + battery_BMS_a064_SW_SOC_Imbalance = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|0] "" X + battery_BMS_a069_SW_Low_Power = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X + battery_BMS_a071_SW_SM_TransCon_Not_Met = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X + battery_BMS_a075_SW_Chg_Disable_Failure = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //18|1@1+ (1,0) [0|0] "" X + battery_BMS_a076_SW_Dch_While_Charging = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X + battery_BMS_a077_SW_Charger_Regulation = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X + battery_BMS_a081_SW_Ctr_Close_Blocked = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery_BMS_a082_SW_Ctr_Force_Open = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X + battery_BMS_a083_SW_Ctr_Close_Failure = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X + battery_BMS_a084_SW_Sleep_Wake_Aborted = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery_BMS_a087_SW_Feim_Test_Blocked = ((rx_frame.data.u8[3] >> 6) & (0x01U)); //30|1@1+ (1,0) [0|0] "" X + battery_BMS_a088_SW_VcFront_MIA_InDrive = ((rx_frame.data.u8[3] >> 7) & (0x01U)); //31|1@1+ (1,0) [0|0] "" X + battery_BMS_a089_SW_VcFront_MIA = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X + battery_BMS_a090_SW_Gateway_MIA = ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|0] "" X + battery_BMS_a091_SW_ChargePort_MIA = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X + battery_BMS_a092_SW_ChargePort_Mia_On_Hv = ((rx_frame.data.u8[4] >> 3) & (0x01U)); //35|1@1+ (1,0) [0|0] "" X + battery_BMS_a094_SW_Drive_Inverter_MIA = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X + battery_BMS_a099_SW_BMB_Communication = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery_BMS_a105_SW_One_Module_Tsense = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery_BMS_a106_SW_All_Module_Tsense = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery_BMS_a107_SW_Stack_Voltage_MIA = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + } + if (mux == 2) { //mux2 + battery_BMS_a121_SW_NVRAM_Config_Error = ((rx_frame.data.u8[0] >> 4) & (0x01U)); // 4|1@1+ (1,0) [0|0] "" X + battery_BMS_a122_SW_BMS_Therm_Irrational = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X + battery_BMS_a123_SW_Internal_Isolation = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X + battery_BMS_a127_SW_shunt_SNA = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //10|1@1+ (1,0) [0|0] "" X + battery_BMS_a128_SW_shunt_MIA = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //11|1@1+ (1,0) [0|0] "" X + battery_BMS_a129_SW_VSH_Failure = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X + battery_BMS_a130_IO_CAN_Error = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //13|1@1+ (1,0) [0|0] "" X + battery_BMS_a131_Bleed_FET_Failure = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X + battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //15|1@1+ (1,0) [0|0] "" X + battery_BMS_a134_SW_Delayed_Ctr_Off = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //17|1@1+ (1,0) [0|0] "" X + battery_BMS_a136_SW_Module_OT_Warning = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X + battery_BMS_a137_SW_Brick_UV_Warning = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X + battery_BMS_a138_SW_Brick_OV_Warning = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //21|1@1+ (1,0) [0|0] "" X + battery_BMS_a139_SW_DC_Link_V_Irrational = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //22|1@1+ (1,0) [0|0] "" X + battery_BMS_a141_SW_BMB_Status_Warning = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery_BMS_a144_Hvp_Config_Mismatch = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery_BMS_a145_SW_SOC_Change = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X + battery_BMS_a146_SW_Brick_Overdischarged = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X + battery_BMS_a149_SW_Missing_Config_Block = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X + battery_BMS_a151_SW_external_isolation = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X + battery_BMS_a156_SW_BMB_Vref_bad = ((rx_frame.data.u8[4] >> 7) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X + battery_BMS_a157_SW_HVP_HVS_Comms = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X + battery_BMS_a158_SW_HVP_HVI_Comms = ((rx_frame.data.u8[5] >> 1) & (0x01U)); //41|1@1+ (1,0) [0|0] "" X + battery_BMS_a159_SW_HVP_ECU_Error = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery_BMS_a161_SW_DI_Open_Request = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X + battery_BMS_a162_SW_No_Power_For_Support = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X + battery_BMS_a163_SW_Contactor_Mismatch = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X + battery_BMS_a164_SW_Uncontrolled_Regen = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X + battery_BMS_a165_SW_Pack_Partial_Weld = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery_BMS_a166_SW_Pack_Full_Weld = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery_BMS_a167_SW_FC_Partial_Weld = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + battery_BMS_a168_SW_FC_Full_Weld = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X + battery_BMS_a169_SW_FC_Pack_Weld = ((rx_frame.data.u8[6] >> 4) & (0x01U)); //52|1@1+ (1,0) [0|0] "" X + battery_BMS_a170_SW_Limp_Mode = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X + battery_BMS_a171_SW_Stack_Voltage_Sense = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X + battery_BMS_a174_SW_Charge_Failure = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X + battery_BMS_a176_SW_GracefulPowerOff = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //59|1@1+ (1,0) [0|0] "" X + battery_BMS_a179_SW_Hvp_12V_Fault = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X + battery_BMS_a180_SW_ECU_reset_blocked = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X + } + break; default: break; } } -#ifdef DOUBLE_BATTERY +#ifdef DOUBLE_BATTERY //Need to update battery2 void receive_can_battery2(CAN_frame rx_frame) { static uint8_t mux = 0; @@ -1052,7 +1797,7 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.cell_min_voltage_mV = battery2_cell_min_v; - battery2_cell_deviation_mV = (battery2_cell_max_v - battery2_cell_min_v); + datalayer.battery2_cell_deviation_mV = (battery2_cell_max_v - battery2_cell_min_v); /* Value mapping is completed. Start to check all safeties */ @@ -1227,14 +1972,14 @@ the first, for a few cycles, then stop all messages which causes the contactor #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) //Send 30ms message - if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { + if (currentMillis - previousMillis50 >= INTERVAL_50_MS) { // Check if sending of CAN messages has been delayed too much. - if ((currentMillis - previousMillis30 >= INTERVAL_30_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { - set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis30)); + if ((currentMillis - previousMillis50 >= INTERVAL_50_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis50)); } else { clear_event(EVENT_CAN_OVERRUN); } - previousMillis30 = currentMillis; + previousMillis50 = currentMillis; if ((datalayer.system.status.inverter_allows_contactor_closing == true) && (datalayer.battery.status.bms_status != FAULT)) { @@ -1292,6 +2037,7 @@ void printFaultCodesIfActive() { "disable the inverter protocol to proceed with contactor closing"); } // Check each symbol and print debug information if its value is 1 + // 0X3AA: 938 HVP_alertMatrix1 printDebugIfActive(battery_WatchdogReset, "ERROR: The processor has experienced a reset due to watchdog reset"); printDebugIfActive(battery_PowerLossReset, "ERROR: The processor has experienced a reset due to power loss"); printDebugIfActive(battery_SwAssertion, "ERROR: An internal software assertion has failed"); @@ -1350,9 +2096,101 @@ void printFaultCodesIfActive() { printDebugIfActive(battery_packCtrCloseFailed, "ERROR: packCtrCloseFailed is active"); printDebugIfActive(battery_fcCtrCloseFailed, "ERROR: fcCtrCloseFailed is active"); printDebugIfActive(battery_shuntThermistorMia, "ERROR: shuntThermistorMia is active"); + // 0x320 800 BMS_alertMatrix + printDebugIfActive(battery_BMS_a017_SW_Brick_OV, "ERROR: BMS_a017_SW_Brick_OV"); + printDebugIfActive(battery_BMS_a018_SW_Brick_UV, "ERROR: BMS_a018_SW_Brick_UV"); + printDebugIfActive(battery_BMS_a019_SW_Module_OT, "ERROR: BMS_a019_SW_Module_OT"); + printDebugIfActive(battery_BMS_a021_SW_Dr_Limits_Regulation, "ERROR: BMS_a021_SW_Dr_Limits_Regulation"); + printDebugIfActive(battery_BMS_a022_SW_Over_Current, "ERROR: BMS_a022_SW_Over_Current"); + printDebugIfActive(battery_BMS_a023_SW_Stack_OV, "ERROR: BMS_a023_SW_Stack_OV"); + printDebugIfActive(battery_BMS_a024_SW_Islanded_Brick, "ERROR: BMS_a024_SW_Islanded_Brick"); + printDebugIfActive(battery_BMS_a025_SW_PwrBalance_Anomaly, "ERROR: BMS_a025_SW_PwrBalance_Anomaly"); + printDebugIfActive(battery_BMS_a026_SW_HFCurrent_Anomaly, "ERROR: BMS_a026_SW_HFCurrent_Anomaly"); + printDebugIfActive(battery_BMS_a034_SW_Passive_Isolation, "ERROR: BMS_a034_SW_Passive_Isolation"); + printDebugIfActive(battery_BMS_a035_SW_Isolation, "ERROR: BMS_a035_SW_Isolation"); + printDebugIfActive(battery_BMS_a036_SW_HvpHvilFault, "ERROR: BMS_a036_SW_HvpHvilFault"); + printDebugIfActive(battery_BMS_a037_SW_Flood_Port_Open, "ERROR: BMS_a037_SW_Flood_Port_Open"); + printDebugIfActive(battery_BMS_a039_SW_DC_Link_Over_Voltage, "ERROR: BMS_a039_SW_DC_Link_Over_Voltage"); + printDebugIfActive(battery_BMS_a041_SW_Power_On_Reset, "ERROR: BMS_a041_SW_Power_On_Reset"); + printDebugIfActive(battery_BMS_a042_SW_MPU_Error, "ERROR: BMS_a042_SW_MPU_Error"); + printDebugIfActive(battery_BMS_a043_SW_Watch_Dog_Reset, "ERROR: BMS_a043_SW_Watch_Dog_Reset"); + printDebugIfActive(battery_BMS_a044_SW_Assertion, "ERROR: BMS_a044_SW_Assertion"); + printDebugIfActive(battery_BMS_a045_SW_Exception, "ERROR: BMS_a045_SW_Exception"); + printDebugIfActive(battery_BMS_a046_SW_Task_Stack_Usage, "ERROR: BMS_a046_SW_Task_Stack_Usage"); + printDebugIfActive(battery_BMS_a047_SW_Task_Stack_Overflow, "ERROR: BMS_a047_SW_Task_Stack_Overflow"); + printDebugIfActive(battery_BMS_a048_SW_Log_Upload_Request, "ERROR: BMS_a048_SW_Log_Upload_Request"); + printDebugIfActive(battery_BMS_a050_SW_Brick_Voltage_MIA, "ERROR: BMS_a050_SW_Brick_Voltage_MIA"); + printDebugIfActive(battery_BMS_a051_SW_HVC_Vref_Bad, "ERROR: BMS_a051_SW_HVC_Vref_Bad"); + printDebugIfActive(battery_BMS_a052_SW_PCS_MIA, "ERROR: BMS_a052_SW_PCS_MIA"); + printDebugIfActive(battery_BMS_a053_SW_ThermalModel_Sanity, "ERROR: BMS_a053_SW_ThermalModel_Sanity"); + printDebugIfActive(battery_BMS_a054_SW_Ver_Supply_Fault, "ERROR: BMS_a054_SW_Ver_Supply_Fault"); + printDebugIfActive(battery_BMS_a059_SW_Pack_Voltage_Sensing, "ERROR: BMS_a059_SW_Pack_Voltage_Sensing"); + printDebugIfActive(battery_BMS_a060_SW_Leakage_Test_Failure, "ERROR: BMS_a060_SW_Leakage_Test_Failure"); + printDebugIfActive(battery_BMS_a061_robinBrickOverVoltage, "ERROR: BMS_a061_robinBrickOverVoltage"); + printDebugIfActive(battery_BMS_a062_SW_BrickV_Imbalance, "ERROR: BMS_a062_SW_BrickV_Imbalance"); + printDebugIfActive(battery_BMS_a063_SW_ChargePort_Fault, "ERROR: BMS_a063_SW_ChargePort_Fault"); + printDebugIfActive(battery_BMS_a064_SW_SOC_Imbalance, "ERROR: BMS_a064_SW_SOC_Imbalance"); + printDebugIfActive(battery_BMS_a069_SW_Low_Power, "ERROR: BMS_a069_SW_Low_Power"); + printDebugIfActive(battery_BMS_a071_SW_SM_TransCon_Not_Met, "ERROR: BMS_a071_SW_SM_TransCon_Not_Met"); + printDebugIfActive(battery_BMS_a075_SW_Chg_Disable_Failure, "ERROR: BMS_a075_SW_Chg_Disable_Failure"); + printDebugIfActive(battery_BMS_a076_SW_Dch_While_Charging, "ERROR: BMS_a076_SW_Dch_While_Charging"); + printDebugIfActive(battery_BMS_a077_SW_Charger_Regulation, "ERROR: BMS_a077_SW_Charger_Regulation"); + printDebugIfActive(battery_BMS_a081_SW_Ctr_Close_Blocked, "ERROR: BMS_a081_SW_Ctr_Close_Blocked"); + printDebugIfActive(battery_BMS_a082_SW_Ctr_Force_Open, "ERROR: BMS_a082_SW_Ctr_Force_Open"); + printDebugIfActive(battery_BMS_a083_SW_Ctr_Close_Failure, "ERROR: BMS_a083_SW_Ctr_Close_Failure"); + printDebugIfActive(battery_BMS_a084_SW_Sleep_Wake_Aborted, "ERROR: BMS_a084_SW_Sleep_Wake_Aborted"); + printDebugIfActive(battery_BMS_a087_SW_Feim_Test_Blocked, "ERROR: BMS_a087_SW_Feim_Test_Blocked"); + printDebugIfActive(battery_BMS_a088_SW_VcFront_MIA_InDrive, "ERROR: BMS_a088_SW_VcFront_MIA_InDrive"); + printDebugIfActive(battery_BMS_a089_SW_VcFront_MIA, "ERROR: BMS_a089_SW_VcFront_MIA"); + printDebugIfActive(battery_BMS_a090_SW_Gateway_MIA, "ERROR: BMS_a090_SW_Gateway_MIA"); + printDebugIfActive(battery_BMS_a091_SW_ChargePort_MIA, "ERROR: BMS_a091_SW_ChargePort_MIA"); + printDebugIfActive(battery_BMS_a092_SW_ChargePort_Mia_On_Hv, "ERROR: BMS_a092_SW_ChargePort_Mia_On_Hv"); + printDebugIfActive(battery_BMS_a094_SW_Drive_Inverter_MIA, "ERROR: BMS_a094_SW_Drive_Inverter_MIA"); + printDebugIfActive(battery_BMS_a099_SW_BMB_Communication, "ERROR: BMS_a099_SW_BMB_Communication"); + printDebugIfActive(battery_BMS_a105_SW_One_Module_Tsense, "ERROR: BMS_a105_SW_One_Module_Tsense"); + printDebugIfActive(battery_BMS_a106_SW_All_Module_Tsense, "ERROR: BMS_a106_SW_All_Module_Tsense"); + printDebugIfActive(battery_BMS_a107_SW_Stack_Voltage_MIA, "ERROR: BMS_a107_SW_Stack_Voltage_MIA"); + printDebugIfActive(battery_BMS_a121_SW_NVRAM_Config_Error, "ERROR: BMS_a121_SW_NVRAM_Config_Error"); + printDebugIfActive(battery_BMS_a122_SW_BMS_Therm_Irrational, "ERROR: BMS_a122_SW_BMS_Therm_Irrational"); + printDebugIfActive(battery_BMS_a123_SW_Internal_Isolation, "ERROR: BMS_a123_SW_Internal_Isolation"); + printDebugIfActive(battery_BMS_a127_SW_shunt_SNA, "ERROR: BMS_a127_SW_shunt_SNA"); + printDebugIfActive(battery_BMS_a128_SW_shunt_MIA, "ERROR: BMS_a128_SW_shunt_MIA"); + printDebugIfActive(battery_BMS_a129_SW_VSH_Failure, "ERROR: BMS_a129_SW_VSH_Failure"); + printDebugIfActive(battery_BMS_a130_IO_CAN_Error, "ERROR: BMS_a130_IO_CAN_Error"); + printDebugIfActive(battery_BMS_a131_Bleed_FET_Failure, "ERROR: BMS_a131_Bleed_FET_Failure"); + printDebugIfActive(battery_BMS_a132_HW_BMB_OTP_Uncorrctbl, "ERROR: BMS_a132_HW_BMB_OTP_Uncorrctbl"); + printDebugIfActive(battery_BMS_a134_SW_Delayed_Ctr_Off, "ERROR: BMS_a134_SW_Delayed_Ctr_Off"); + printDebugIfActive(battery_BMS_a136_SW_Module_OT_Warning, "ERROR: BMS_a136_SW_Module_OT_Warning"); + printDebugIfActive(battery_BMS_a137_SW_Brick_UV_Warning, "ERROR: BMS_a137_SW_Brick_UV_Warning"); + printDebugIfActive(battery_BMS_a139_SW_DC_Link_V_Irrational, "ERROR: BMS_a139_SW_DC_Link_V_Irrational"); + printDebugIfActive(battery_BMS_a141_SW_BMB_Status_Warning, "ERROR: BMS_a141_SW_BMB_Status_Warning"); + printDebugIfActive(battery_BMS_a144_Hvp_Config_Mismatch, "ERROR: BMS_a144_Hvp_Config_Mismatch"); + printDebugIfActive(battery_BMS_a145_SW_SOC_Change, "ERROR: BMS_a145_SW_SOC_Change"); + printDebugIfActive(battery_BMS_a146_SW_Brick_Overdischarged, "ERROR: BMS_a146_SW_Brick_Overdischarged"); + printDebugIfActive(battery_BMS_a149_SW_Missing_Config_Block, "ERROR: BMS_a149_SW_Missing_Config_Block"); + printDebugIfActive(battery_BMS_a151_SW_external_isolation, "ERROR: BMS_a151_SW_external_isolation"); + printDebugIfActive(battery_BMS_a156_SW_BMB_Vref_bad, "ERROR: BMS_a156_SW_BMB_Vref_bad"); + printDebugIfActive(battery_BMS_a157_SW_HVP_HVS_Comms, "ERROR: BMS_a157_SW_HVP_HVS_Comms"); + printDebugIfActive(battery_BMS_a158_SW_HVP_HVI_Comms, "ERROR: BMS_a158_SW_HVP_HVI_Comms"); + printDebugIfActive(battery_BMS_a159_SW_HVP_ECU_Error, "ERROR: BMS_a159_SW_HVP_ECU_Error"); + printDebugIfActive(battery_BMS_a161_SW_DI_Open_Request, "ERROR: BMS_a161_SW_DI_Open_Request"); + printDebugIfActive(battery_BMS_a162_SW_No_Power_For_Support, "ERROR: BMS_a162_SW_No_Power_For_Support"); + printDebugIfActive(battery_BMS_a163_SW_Contactor_Mismatch, "ERROR: BMS_a163_SW_Contactor_Mismatch"); + printDebugIfActive(battery_BMS_a164_SW_Uncontrolled_Regen, "ERROR: BMS_a164_SW_Uncontrolled_Regen"); + printDebugIfActive(battery_BMS_a165_SW_Pack_Partial_Weld, "ERROR: BMS_a165_SW_Pack_Partial_Weld"); + printDebugIfActive(battery_BMS_a166_SW_Pack_Full_Weld, "ERROR: BMS_a166_SW_Pack_Full_Weld"); + printDebugIfActive(battery_BMS_a167_SW_FC_Partial_Weld, "ERROR: BMS_a167_SW_FC_Partial_Weld"); + printDebugIfActive(battery_BMS_a168_SW_FC_Full_Weld, "ERROR: BMS_a168_SW_FC_Full_Weld"); + printDebugIfActive(battery_BMS_a169_SW_FC_Pack_Weld, "ERROR: BMS_a169_SW_FC_Pack_Weld"); + printDebugIfActive(battery_BMS_a170_SW_Limp_Mode, "ERROR: BMS_a170_SW_Limp_Mode"); + printDebugIfActive(battery_BMS_a171_SW_Stack_Voltage_Sense, "ERROR: BMS_a171_SW_Stack_Voltage_Sense"); + printDebugIfActive(battery_BMS_a174_SW_Charge_Failure, "ERROR: BMS_a174_SW_Charge_Failure"); + printDebugIfActive(battery_BMS_a176_SW_GracefulPowerOff, "ERROR: BMS_a176_SW_GracefulPowerOff"); + printDebugIfActive(battery_BMS_a179_SW_Hvp_12V_Fault, "ERROR: BMS_a179_SW_Hvp_12V_Fault"); + printDebugIfActive(battery_BMS_a180_SW_ECU_reset_blocked, "ERROR: BMS_a180_SW_ECU_reset_blocked"); } -#ifdef DOUBLE_BATTERY +#ifdef DOUBLE_BATTERY //need to update battery2 void printFaultCodesIfActive_battery2() { if (battery2_packCtrsClosingAllowed == 0) { Serial.println( From 34f749d864bdf1859b1607e40422e4c30508f10c Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 18 Dec 2024 20:48:28 +1300 Subject: [PATCH 074/225] Update TESLA-BATTERY.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 64 ++++++++++++++------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index dd1273a11..23a7d6234 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -23,7 +23,6 @@ CAN_frame TESLA_221_2 = { .ID = 0x221, .data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive - static uint16_t sendContactorClosingMessagesStill = 300; static uint16_t battery_cell_max_v = 3700; static uint16_t battery_cell_min_v = 3700; @@ -47,15 +46,15 @@ static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh static uint16_t battery_nominal_full_pack_energy = 600; // Kwh static uint16_t battery_nominal_full_pack_energy_m0 = 600; // Kwh //0x132 306 HVBattAmpVolt -static uint16_t battery_volts = 0; // V -static int16_t battery_amps = 0; // A -static uint16_t battery_raw_amps = 0; // A -static uint16_t battery_charge_time_remaining = 0; // Minutes +static uint16_t battery_volts = 0; // V +static int16_t battery_amps = 0; // A +static uint16_t battery_raw_amps = 0; // A +static uint16_t battery_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable -static uint16_t BMS_regenerative_limit = 0; //rename from battery_regenerative_limit -static uint16_t BMS_discharge_limit = 0; // rename from battery_discharge_limit -static uint16_t BMS_max_heat_park = 0; //rename from battery_max_heat_park -static uint16_t BMS_hvac_max_power = 0; //rename from battery_hvac_max_power +static uint16_t BMS_regenerative_limit = 0; //rename from battery_regenerative_limit +static uint16_t BMS_discharge_limit = 0; // rename from battery_discharge_limit +static uint16_t BMS_max_heat_park = 0; //rename from battery_max_heat_park +static uint16_t BMS_hvac_max_power = 0; //rename from battery_hvac_max_power //0x2d2: 722 BMSVAlimits static uint16_t battery_max_discharge_current = 0; static uint16_t battery_max_charge_current = 0; @@ -64,9 +63,10 @@ static uint16_t battery_bms_min_voltage = 0; //0x2b4: 692 PCS_dcdcRailStatus static uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt static uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt -static uint16_t battery_dcdcLvOutputCurrent = 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent +static uint16_t battery_dcdcLvOutputCurrent = + 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent //0x292: 658 BMS_socStatus -static uint16_t battery_beginning_of_life = 600; // kWh +static uint16_t battery_beginning_of_life = 600; // kWh static uint16_t battery_soc_min = 0; static uint16_t battery_soc_max = 0; static uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui @@ -79,10 +79,10 @@ static uint32_t battery_packConfigMultiplexer = 0; static uint32_t battery_moduleType = 0; static uint32_t battery_reservedConfig = 0; //0x332: 818 BattBrickMinMax:BMS_bmbMinMax -static int16_t battery_max_temp = 0; // C* -static int16_t battery_min_temp = 0; // C* -static uint16_t battery_BrickVoltageMax = 0; -static uint16_t battery_BrickVoltageMin = 0; +static int16_t battery_max_temp = 0; // C* +static int16_t battery_min_temp = 0; // C* +static uint16_t battery_BrickVoltageMax = 0; +static uint16_t battery_BrickVoltageMin = 0; static uint8_t battery_BrickTempMaxNum = 0; static uint8_t battery_BrickTempMinNum = 0; static uint8_t battery_BrickModelTMax = 0; @@ -403,7 +403,7 @@ static uint8_t battery_BMS_a174_SW_Charge_Failure = 1; static uint8_t battery_BMS_a179_SW_Hvp_12V_Fault = 1; static uint8_t battery_BMS_a180_SW_ECU_reset_blocked = 1; -#ifdef DOUBLE_BATTERY //need to update for battery2 +#ifdef DOUBLE_BATTERY //need to update for battery2 static uint32_t battery2_total_discharge = 0; static uint32_t battery2_total_charge = 0; static uint16_t battery2_volts = 0; // V @@ -852,7 +852,7 @@ void receive_can_battery(CAN_frame rx_frame) { mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X if (mux == 0) { - battery_nominal_full_pack_energy_m0 = + battery_nominal_full_pack_energy_m0 = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //16|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended battery_nominal_energy_remaining_m0 = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]); //32|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended @@ -958,7 +958,7 @@ void receive_can_battery(CAN_frame rx_frame) { battery_BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); battery_BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC break; - case 0x224: //548 PCS_dcdcStatus: + case 0x224: //548 PCS_dcdcStatus: battery_PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ; battery_PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" battery_PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" @@ -987,15 +987,15 @@ void receive_can_battery(CAN_frame rx_frame) { break; case 0x252: //Limit //BMS_powerAvailable252: BMS_regenerative_limit = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * - 0.01; //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW + 0.01; //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW BMS_discharge_limit = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * - 0.013; //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? + 0.013; //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? BMS_max_heat_park = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]) * - 0.01; //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW + 0.01; //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW BMS_hvac_max_power = (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))) * - 0.02; //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? - //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver - //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] "" Receiver + 0.02; //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? + //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver + //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] "" Receiver break; case 0x132: //battery amps/volts //HVBattAmpVolt battery_volts = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * @@ -1148,7 +1148,7 @@ void receive_can_battery(CAN_frame rx_frame) { ((rx_frame.data.u8[2] & (0xFFU)) << 8) | (rx_frame.data.u8[1] & (0xFFU)); // m22 : 8|24@1+ (0.01,0) [0|0] "kWh" X } - break; + break; case 0x401: // Cell stats //BrickVoltages mux = (rx_frame.data.u8[0]); //MultiplexSelector M : 0|8@1+ (1,0) [0|0] "" //StatusFlags : 8|8@1+ (1,0) [0|0] "" @@ -1221,13 +1221,17 @@ void receive_can_battery(CAN_frame rx_frame) { mux = (rx_frame.data.u8[0] & (0xFF)); if (mux == 1) { battery_packConfigMultiplexer = (rx_frame.data.u8[0] & (0xff)); //0|8@1+ (1,0) [0|1] "" - battery_moduleType = (rx_frame.data.u8[1] & (0x07)); //8|3@1+ (1,0) [0|4] ""//0 "UNKNOWN" 1 "E3_NCT" 2 "E1_NCT" 3 "E3_CT" 4 "E1_CT" 5 "E1_CP" ;//to datalayer_extended - battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg" + battery_moduleType = + (rx_frame.data.u8[1] & + (0x07)); //8|3@1+ (1,0) [0|4] ""//0 "UNKNOWN" 1 "E3_NCT" 2 "E1_NCT" 3 "E3_CT" 4 "E1_CT" 5 "E1_CP" ;//to datalayer_extended + battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg" battery_platformMaxBusVoltage = (((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3])); //24|10@1+ (0.1,375) [0|0] "V" } if (mux == 0) { - battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); //8|5@1+ (1,0) [0|31] ""//0 "BMS_CONFIG_0" 1 "BMS_CONFIG_1" 10 "BMS_CONFIG_10" 11 "BMS_CONFIG_11" 12 "BMS_CONFIG_12" 13 "BMS_CONFIG_13" 14 "BMS_CONFIG_14" 15 "BMS_CONFIG_15" 16 "BMS_CONFIG_16" 17 "BMS_CONFIG_17" 18 "BMS_CONFIG_18" 19 "BMS_CONFIG_19" 2 "BMS_CONFIG_2" 20 "BMS_CONFIG_20" 21 "BMS_CONFIG_21" 22 "BMS_CONFIG_22" 23 "BMS_CONFIG_23" 24 "BMS_CONFIG_24" 25 "BMS_CONFIG_25" 26 "BMS_CONFIG_26" 27 "BMS_CONFIG_27" 28 "BMS_CONFIG_28" 29 "BMS_CONFIG_29" 3 "BMS_CONFIG_3" 30 "BMS_CONFIG_30" 31 "BMS_CONFIG_31" 4 "BMS_CONFIG_4" 5 "BMS_CONFIG_5" 6 "BMS_CONFIG_6" 7 "BMS_CONFIG_7" 8 "BMS_CONFIG_8" 9 "BMS_CONFIG_9" ; + battery_reservedConfig = + (rx_frame.data.u8[1] & + (0x1F)); //8|5@1+ (1,0) [0|31] ""//0 "BMS_CONFIG_0" 1 "BMS_CONFIG_1" 10 "BMS_CONFIG_10" 11 "BMS_CONFIG_11" 12 "BMS_CONFIG_12" 13 "BMS_CONFIG_13" 14 "BMS_CONFIG_14" 15 "BMS_CONFIG_15" 16 "BMS_CONFIG_16" 17 "BMS_CONFIG_17" 18 "BMS_CONFIG_18" 19 "BMS_CONFIG_19" 2 "BMS_CONFIG_2" 20 "BMS_CONFIG_20" 21 "BMS_CONFIG_21" 22 "BMS_CONFIG_22" 23 "BMS_CONFIG_23" 24 "BMS_CONFIG_24" 25 "BMS_CONFIG_25" 26 "BMS_CONFIG_26" 27 "BMS_CONFIG_27" 28 "BMS_CONFIG_28" 29 "BMS_CONFIG_29" 3 "BMS_CONFIG_3" 30 "BMS_CONFIG_30" 31 "BMS_CONFIG_31" 4 "BMS_CONFIG_4" 5 "BMS_CONFIG_5" 6 "BMS_CONFIG_6" 7 "BMS_CONFIG_7" 8 "BMS_CONFIG_8" 9 "BMS_CONFIG_9" ; } break; case 0x7AA: //1962 HVP_debugMessage: @@ -1489,7 +1493,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -#ifdef DOUBLE_BATTERY //Need to update battery2 +#ifdef DOUBLE_BATTERY //Need to update battery2 void receive_can_battery2(CAN_frame rx_frame) { static uint8_t mux = 0; @@ -2190,7 +2194,7 @@ void printFaultCodesIfActive() { printDebugIfActive(battery_BMS_a180_SW_ECU_reset_blocked, "ERROR: BMS_a180_SW_ECU_reset_blocked"); } -#ifdef DOUBLE_BATTERY //need to update battery2 +#ifdef DOUBLE_BATTERY //need to update battery2 void printFaultCodesIfActive_battery2() { if (battery2_packCtrsClosingAllowed == 0) { Serial.println( From 6ed3b7ea089ff647c3f102033b3893ce552e0588 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:05:08 +1300 Subject: [PATCH 075/225] Update TESLA-BATTERY.cpp Update battery2 info to match. --- Software/src/battery/TESLA-BATTERY.cpp | 854 +++++++++++++++++++++++-- 1 file changed, 787 insertions(+), 67 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 23a7d6234..26fa6f0b7 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -404,13 +404,14 @@ static uint8_t battery_BMS_a179_SW_Hvp_12V_Fault = 1; static uint8_t battery_BMS_a180_SW_ECU_reset_blocked = 1; #ifdef DOUBLE_BATTERY //need to update for battery2 + +static uint16_t battery2_cell_max_v = 3700; +static uint16_t battery2_cell_min_v = 3700; +static uint16_t battery2_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV +//0x3d2: 978 BMS_kwhCounter static uint32_t battery2_total_discharge = 0; static uint32_t battery2_total_charge = 0; -static uint16_t battery2_volts = 0; // V -static int16_t battery2_amps = 0; // A -static uint16_t battery2_raw_amps = 0; // A -static int16_t battery2_max_temp = 0; // C* -static int16_t battery2_min_temp = 0; // C* +//0x352: 850 BMS_energyStatus static uint16_t battery2_energy_buffer = 0; static uint16_t battery2_energy_buffer_m1 = 0; // kWh static uint16_t battery2_energy_to_charge_complete = 0; @@ -425,28 +426,50 @@ static uint16_t battery2_nominal_energy_remaining = 0; static uint16_t battery2_nominal_energy_remaining_m0 = 0; // kWh static uint16_t battery2_nominal_full_pack_energy = 600; static uint16_t battery2_nominal_full_pack_energy_m0 = 600; // Kwh -static uint16_t battery2_beginning_of_life = 600; +//0x132 306 HVBattAmpVolt +static uint16_t battery2_volts = 0; // V +static int16_t battery2_amps = 0; // A +static uint16_t battery2_raw_amps = 0; // A static uint16_t battery2_charge_time_remaining = 0; // Minutes -static uint16_t battery2_regenerative_limit = 0; -static uint16_t battery2_discharge_limit = 0; -static uint16_t battery2_max_heat_park = 0; -static uint16_t battery2_hvac_max_power = 0; +//0x252 594 BMS_powerAvailable +static uint16_t BMS2_regenerative_limit = 0; +static uint16_t BMS2_discharge_limit = 0; +static uint16_t BMS2_max_heat_park = 0; +static uint16_t BMS2_hvac_max_power = 0; +//0x2d2: 722 BMSVAlimits static uint16_t battery2_max_discharge_current = 0; static uint16_t battery2_max_charge_current = 0; static uint16_t battery2_bms_max_voltage = 0; static uint16_t battery2_bms_min_voltage = 0; +//0x2b4: 692 PCS_dcdcRailStatus static uint16_t battery2_dcdcHvBusVolt = 0; //update name static uint16_t battery2_dcdcLvBusVolt = 0; //update name static uint16_t battery2_dcdcLvOutputCurrent = 0; //update name +//0x292: 658 BMS_socStatus +static uint16_t battery2_beginning_of_life = 600; static uint16_t battery2_soc_min = 0; static uint16_t battery2_soc_max = 0; static uint16_t battery2_soc_ui = 0; static uint16_t battery2_soc_ave = 0; -static uint16_t battery2_cell_max_v = 3700; -static uint16_t battery2_cell_min_v = 3700; -static uint16_t battery2_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV -static uint8_t battery2_max_vno = 0; -static uint8_t battery2_min_vno = 0; +static uint8_t battery2_battTempPct = 0; +//0x392: BMS_packConfig +static uint32_t battery2_packMass = 0; +static uint32_t battery2_platformMaxBusVoltage = 0; +static uint32_t battery2_packConfigMultiplexer = 0; +static uint32_t battery2_moduleType = 0; +static uint32_t battery2_reservedConfig = 0; +//0x332: 818 BattBrickMinMax:BMS_bmbMinMax +static int16_t battery2_max_temp = 0; // C* +static int16_t battery2_min_temp = 0; // C* +static uint16_t battery2_BrickVoltageMax = 0; +static uint16_t battery2_BrickVoltageMin = 0; +static uint8_t battery2_BrickTempMaxNum = 0; +static uint8_t battery2_BrickTempMinNum = 0; +static uint8_t battery2_BrickModelTMax = 0; +static uint8_t battery2_BrickModelTMin = 0; +static uint8_t battery2_BrickVoltageMaxNum = 0; //rename from battery_max_vno +static uint8_t battery2_BrickVoltageMinNum = 0; //rename from battery_min_vno +//0x20A: 522 HVP_contactorState static uint8_t battery2_contactor = 0; //State of contactor static uint8_t battery2_hvil_status = 0; static uint8_t battery2_packContNegativeState = 0; @@ -454,13 +477,159 @@ static uint8_t battery2_packContPositiveState = 0; static uint8_t battery2_packContactorSetState = 0; static uint8_t battery2_packCtrsClosingAllowed = 0; static uint8_t battery2_pyroTestInProgress = 0; -static uint8_t battery2_battTempPct = 0; -static uint32_t battery2_packMass = 0; -static uint32_t battery2_platformMaxBusVoltage = 0; -static uint32_t battery2_packConfigMultiplexer = 0; -static uint32_t battery2_moduleType = 0; -static uint32_t battery2_reservedConfig = 0; -//Fault codes +static uint8_t battery2_packCtrsOpenNowRequested = 0; +static uint8_t battery2_packCtrsOpenRequested = 0; +static uint8_t battery2_packCtrsRequestStatus = 0; +static uint8_t battery2_packCtrsResetRequestRequired = 0; +static uint8_t battery2_dcLinkAllowedToEnergize = 0; +static uint8_t battery2_fcContNegativeAuxOpen = 0; +static uint8_t battery2_fcContNegativeState = 0; +static uint8_t battery2_fcContPositiveAuxOpen = 0; +static uint8_t battery2_fcContPositiveState = 0; +static uint8_t battery2_fcContactorSetState = 0; +static uint8_t battery2_fcCtrsClosingAllowed = 0; +static uint8_t battery2_fcCtrsOpenNowRequested = 0; +static uint8_t battery2_fcCtrsOpenRequested = 0; +static uint8_t battery2_fcCtrsRequestStatus = 0; +static uint8_t battery2_fcCtrsResetRequestRequired = 0; +static uint8_t battery2_fcLinkAllowedToEnergize = 0; +//0x212: 530 BMS_status +static uint8_t battery2_BMS_hvacPowerRequest = 0; +static uint8_t battery2_BMS_notEnoughPowerForDrive = 0; +static uint8_t battery2_BMS_notEnoughPowerForSupport = 0; +static uint8_t battery2_BMS_preconditionAllowed = 0; +static uint8_t battery2_BMS_updateAllowed = 0; +static uint8_t battery2_BMS_activeHeatingWorthwhile = 0; +static uint8_t battery2_BMS_cpMiaOnHvs = 0; +static uint8_t battery2_BMS_contactorState = 0; +static uint8_t battery2_BMS_state = 0; +static uint8_t battery2_BMS_hvState = 0; +static uint16_t battery2_BMS_isolationResistance = 0; +static uint8_t battery2_BMS_chargeRequest = 0; +static uint8_t battery2_BMS_keepWarmRequest = 0; +static uint8_t battery2_BMS_uiChargeStatus = 0; +static uint8_t battery2_BMS_diLimpRequest = 0; +static uint8_t battery2_BMS_okToShipByAir = 0; +static uint8_t battery2_BMS_okToShipByLand = 0; +static uint32_t battery2_BMS_chgPowerAvailable = 0; +static uint8_t battery2_BMS_chargeRetryCount = 0; +static uint8_t battery2_BMS_pcsPwmEnabled = 0; +static uint8_t battery2_BMS_ecuLogUploadRequest = 0; +static uint8_t battery2_BMS_minPackTemperature = 0; +// 0x224:548 PCS_dcdcStatus +static uint8_t battery2_PCS_dcdcPrechargeStatus = 0; +static uint8_t battery2_PCS_dcdc12VSupportStatus = 0; +static uint8_t battery2_PCS_dcdcHvBusDischargeStatus = 0; +static uint16_t battery2_PCS_dcdcMainState = 0; +static uint8_t battery2_PCS_dcdcSubState = 0; +static uint8_t battery2_PCS_dcdcFaulted = 0; +static uint8_t battery2_PCS_dcdcOutputIsLimited = 0; +static uint32_t battery2_PCS_dcdcMaxOutputCurrentAllowed = 0; +static uint8_t battery2_PCS_dcdcPrechargeRtyCnt = 0; +static uint8_t battery2_PCS_dcdc12VSupportRtyCnt = 0; +static uint8_t battery2_PCS_dcdcDischargeRtyCnt = 0; +static uint8_t battery2_PCS_dcdcPwmEnableLine = 0; +static uint8_t battery2_PCS_dcdcSupportingFixedLvTarget = 0; +static uint8_t battery2_PCS_ecuLogUploadRequest = 0; +static uint8_t battery2_PCS_dcdcPrechargeRestartCnt = 0; +static uint8_t battery2_PCS_dcdcInitialPrechargeSubState = 0; +//0x312: 786 BMS_thermalStatus +static uint16_t BMS2_powerDissipation = 0; +static uint16_t BMS2_flowRequest = 0; +static uint16_t BMS2_inletActiveCoolTargetT = 0; +static uint16_t BMS2_inletPassiveTargetT = 0; +static uint16_t BMS2_inletActiveHeatTargetT = 0; +static uint16_t BMS2_packTMin = 0; +static uint16_t BMS2_packTMax = 0; +static uint16_t BMS2_pcsNoFlowRequest = 0; +static uint16_t BMS2_noFlowRequest = 0; +//0x2A4; 676 PCS_thermalStatus +static uint16_t PCS2_chgPhATemp = 0; +static uint16_t PCS2_chgPhBTemp = 0; +static uint16_t PCS2_chgPhCTemp = 0; +static uint16_t PCS2_dcdcTemp = 0; +static uint16_t PCS2_ambientTemp = 0; +//0x2C4; 708 PCS_logging +static uint16_t PCS2_logMessageSelect = 0; +static uint16_t PCS2_dcdcMaxLvOutputCurrent = 0; +static uint16_t PCS2_dcdcCurrentLimit = 0; +static uint16_t PCS2_dcdcLvOutputCurrentTempLimit = 0; +static uint16_t PCS2_dcdcUnifiedCommand = 0; +static uint16_t PCS2_dcdcCLAControllerOutput = 0; +static uint16_t PCS2_dcdcTankVoltage = 0; +static uint16_t PCS2_dcdcTankVoltageTarget = 0; +static uint16_t PCS2_dcdcClaCurrentFreq = 0; +static uint16_t PCS2_dcdcTCommMeasured = 0; +static uint16_t PCS2_dcdcShortTimeUs = 0; +static uint16_t PCS2_dcdcHalfPeriodUs = 0; +static uint16_t PCS2_dcdcIntervalMaxFrequency = 0; +static uint16_t PCS2_dcdcIntervalMaxHvBusVolt = 0; +static uint16_t PCS2_dcdcIntervalMaxLvBusVolt = 0; +static uint16_t PCS2_dcdcIntervalMaxLvOutputCurr = 0; +static uint16_t PCS2_dcdcIntervalMinFrequency = 0; +static uint16_t PCS2_dcdcIntervalMinHvBusVolt = 0; +static uint16_t PCS2_dcdcIntervalMinLvBusVolt = 0; +static uint16_t PCS2_dcdcIntervalMinLvOutputCurr = 0; +static uint32_t PCS2_dcdc12vSupportLifetimekWh = 0; +//0x7AA: //1962 HVP_debugMessage: +static uint8_t HVP2_debugMessageMultiplexer = 0; +static uint8_t HVP2_gpioPassivePyroDepl = 0; +static uint8_t HVP2_gpioPyroIsoEn = 0; +static uint8_t HVP2_gpioCpFaultIn = 0; +static uint8_t HVP2_gpioPackContPowerEn = 0; +static uint8_t HVP2_gpioHvCablesOk = 0; +static uint8_t HVP2_gpioHVPSelfEnable = 0; +static uint8_t HVP2_gpioLed = 0; +static uint8_t HVP2_gpioCrashSignal = 0; +static uint8_t HVP2_gpioShuntDataReady = 0; +static uint8_t HVP2_gpioFcContPosAux = 0; +static uint8_t HVP2_gpioFcContNegAux = 0; +static uint8_t HVP2_gpioBmsEout = 0; +static uint8_t HVP2_gpioCpFaultOut = 0; +static uint8_t HVP2_gpioPyroPor = 0; +static uint8_t HVP2_gpioShuntEn = 0; +static uint8_t HVP2_gpioHVPVerEn = 0; +static uint8_t HVP2_gpioPackCoontPosFlywheel = 0; +static uint8_t HVP2_gpioCpLatchEnable = 0; +static uint8_t HVP2_gpioPcsEnable = 0; +static uint8_t HVP2_gpioPcsDcdcPwmEnable = 0; +static uint8_t HVP2_gpioPcsChargePwmEnable = 0; +static uint8_t HVP2_gpioFcContPowerEnable = 0; +static uint8_t HVP2_gpioHvilEnable = 0; +static uint8_t HVP2_gpioSecDrdy = 0; +static uint16_t HVP2_hvp1v5Ref = 0; +static uint16_t HVP2_shuntCurrentDebug = 0; +static uint8_t HVP2_packCurrentMia = 0; +static uint8_t HVP2_auxCurrentMia = 0; +static uint8_t HVP2_currentSenseMia = 0; +static uint8_t HVP2_shuntRefVoltageMismatch = 0; +static uint8_t HVP2_shuntThermistorMia = 0; +static uint8_t HVP2_shuntHwMia = 0; +static uint16_t HVP2_dcLinkVoltage = 0; +static uint16_t HVP2_packVoltage = 0; +static uint16_t HVP2_fcLinkVoltage = 0; +static uint16_t HVP2_packContVoltage = 0; +static uint16_t HVP2_packNegativeV = 0; +static uint16_t HVP2_packPositiveV = 0; +static uint16_t HVP2_pyroAnalog = 0; +static uint16_t HVP2_dcLinkNegativeV = 0; +static uint16_t HVP2_dcLinkPositiveV = 0; +static uint16_t HVP2_fcLinkNegativeV = 0; +static uint16_t HVP2_fcContCoilCurrent = 0; +static uint16_t HVP2_fcContVoltage = 0; +static uint16_t HVP2_hvilInVoltage = 0; +static uint16_t HVP2_hvilOutVoltage = 0; +static uint16_t HVP2_fcLinkPositiveV = 0; +static uint16_t HVP2_packContCoilCurrent = 0; +static uint16_t HVP2_battery12V = 0; +static uint16_t HVP2_shuntRefVoltageDbg = 0; +static uint16_t HVP2_shuntAuxCurrentDbg = 0; +static uint16_t HVP2_shuntBarTempDbg = 0; +static uint16_t HVP2_shuntAsicTempDbg = 0; +static uint8_t HVP2_shuntAuxCurrentStatus = 0; +static uint8_t HVP2_shuntBarTempStatus = 0; +static uint8_t HVP2_shuntAsicTempStatus = 0; +//0x3aa: HVP_alertMatrix1 Fault codes static uint8_t battery2_WatchdogReset = 0; //Warns if the processor has experienced a reset due to watchdog reset. static uint8_t battery2_PowerLossReset = 0; //Warns if the processor has experienced a reset due to power loss. static uint8_t battery2_SwAssertion = 0; //An internal software assertion has failed. @@ -519,6 +688,101 @@ static uint8_t battery2_logUploadRequest = 0; static uint8_t battery2_packCtrCloseFailed = 0; static uint8_t battery2_fcCtrCloseFailed = 0; static uint8_t battery2_shuntThermistorMia = 0; +//0x320: 800 BMS_alertMatrix +static uint8_t battery2_BMS_matrixIndex = 4; +static uint8_t battery2_BMS_a061_robinBrickOverVoltage = 1; +static uint8_t battery2_BMS_a062_SW_BrickV_Imbalance = 1; +static uint8_t battery2_BMS_a063_SW_ChargePort_Fault = 1; +static uint8_t battery2_BMS_a064_SW_SOC_Imbalance = 1; +static uint8_t battery2_BMS_a127_SW_shunt_SNA = 1; +static uint8_t battery2_BMS_a128_SW_shunt_MIA = 1; +static uint8_t battery2_BMS_a069_SW_Low_Power = 1; +static uint8_t battery2_BMS_a130_IO_CAN_Error = 1; +static uint8_t battery2_BMS_a071_SW_SM_TransCon_Not_Met = 1; +static uint8_t battery2_BMS_a132_HW_BMB_OTP_Uncorrctbl = 1; +static uint8_t battery2_BMS_a134_SW_Delayed_Ctr_Off = 1; +static uint8_t battery2_BMS_a075_SW_Chg_Disable_Failure = 1; +static uint8_t battery2_BMS_a076_SW_Dch_While_Charging = 1; +static uint8_t battery2_BMS_a017_SW_Brick_OV = 1; +static uint8_t battery2_BMS_a018_SW_Brick_UV = 1; +static uint8_t battery2_BMS_a019_SW_Module_OT = 1; +static uint8_t battery2_BMS_a021_SW_Dr_Limits_Regulation = 1; +static uint8_t battery2_BMS_a022_SW_Over_Current = 1; +static uint8_t battery2_BMS_a023_SW_Stack_OV = 1; +static uint8_t battery2_BMS_a024_SW_Islanded_Brick = 1; +static uint8_t battery2_BMS_a025_SW_PwrBalance_Anomaly = 1; +static uint8_t battery2_BMS_a026_SW_HFCurrent_Anomaly = 1; +static uint8_t battery2_BMS_a087_SW_Feim_Test_Blocked = 1; +static uint8_t battery2_BMS_a088_SW_VcFront_MIA_InDrive = 1; +static uint8_t battery2_BMS_a089_SW_VcFront_MIA = 1; +static uint8_t battery2_BMS_a090_SW_Gateway_MIA = 1; +static uint8_t battery2_BMS_a091_SW_ChargePort_MIA = 1; +static uint8_t battery2_BMS_a092_SW_ChargePort_Mia_On_Hv = 1; +static uint8_t battery2_BMS_a034_SW_Passive_Isolation = 1; +static uint8_t battery2_BMS_a035_SW_Isolation = 1; +static uint8_t battery2_BMS_a036_SW_HvpHvilFault = 1; +static uint8_t battery2_BMS_a037_SW_Flood_Port_Open = 1; +static uint8_t battery2_BMS_a158_SW_HVP_HVI_Comms = 1; +static uint8_t battery2_BMS_a039_SW_DC_Link_Over_Voltage = 1; +static uint8_t battery2_BMS_a041_SW_Power_On_Reset = 1; +static uint8_t battery2_BMS_a042_SW_MPU_Error = 1; +static uint8_t battery2_BMS_a043_SW_Watch_Dog_Reset = 1; +static uint8_t battery2_BMS_a044_SW_Assertion = 1; +static uint8_t battery2_BMS_a045_SW_Exception = 1; +static uint8_t battery2_BMS_a046_SW_Task_Stack_Usage = 1; +static uint8_t battery2_BMS_a047_SW_Task_Stack_Overflow = 1; +static uint8_t battery2_BMS_a048_SW_Log_Upload_Request = 1; +static uint8_t battery2_BMS_a169_SW_FC_Pack_Weld = 1; +static uint8_t battery2_BMS_a050_SW_Brick_Voltage_MIA = 1; +static uint8_t battery2_BMS_a051_SW_HVC_Vref_Bad = 1; +static uint8_t battery2_BMS_a052_SW_PCS_MIA = 1; +static uint8_t battery2_BMS_a053_SW_ThermalModel_Sanity = 1; +static uint8_t battery2_BMS_a054_SW_Ver_Supply_Fault = 1; +static uint8_t battery2_BMS_a176_SW_GracefulPowerOff = 1; +static uint8_t battery2_BMS_a059_SW_Pack_Voltage_Sensing = 1; +static uint8_t battery2_BMS_a060_SW_Leakage_Test_Failure = 1; +static uint8_t battery2_BMS_a077_SW_Charger_Regulation = 1; +static uint8_t battery2_BMS_a081_SW_Ctr_Close_Blocked = 1; +static uint8_t battery2_BMS_a082_SW_Ctr_Force_Open = 1; +static uint8_t battery2_BMS_a083_SW_Ctr_Close_Failure = 1; +static uint8_t battery2_BMS_a084_SW_Sleep_Wake_Aborted = 1; +static uint8_t battery2_BMS_a094_SW_Drive_Inverter_MIA = 1; +static uint8_t battery2_BMS_a099_SW_BMB_Communication = 1; +static uint8_t battery2_BMS_a105_SW_One_Module_Tsense = 1; +static uint8_t battery2_BMS_a106_SW_All_Module_Tsense = 1; +static uint8_t battery2_BMS_a107_SW_Stack_Voltage_MIA = 1; +static uint8_t battery2_BMS_a121_SW_NVRAM_Config_Error = 1; +static uint8_t battery2_BMS_a122_SW_BMS_Therm_Irrational = 1; +static uint8_t battery2_BMS_a123_SW_Internal_Isolation = 1; +static uint8_t battery2_BMS_a129_SW_VSH_Failure = 1; +static uint8_t battery2_BMS_a131_Bleed_FET_Failure = 1; +static uint8_t battery2_BMS_a136_SW_Module_OT_Warning = 1; +static uint8_t battery2_BMS_a137_SW_Brick_UV_Warning = 1; +static uint8_t battery2_BMS_a138_SW_Brick_OV_Warning = 1; +static uint8_t battery2_BMS_a139_SW_DC_Link_V_Irrational = 1; +static uint8_t battery2_BMS_a141_SW_BMB_Status_Warning = 1; +static uint8_t battery2_BMS_a144_Hvp_Config_Mismatch = 1; +static uint8_t battery2_BMS_a145_SW_SOC_Change = 1; +static uint8_t battery2_BMS_a146_SW_Brick_Overdischarged = 1; +static uint8_t battery2_BMS_a149_SW_Missing_Config_Block = 1; +static uint8_t battery2_BMS_a151_SW_external_isolation = 1; +static uint8_t battery2_BMS_a156_SW_BMB_Vref_bad = 1; +static uint8_t battery2_BMS_a157_SW_HVP_HVS_Comms = 1; +static uint8_t battery2_BMS_a159_SW_HVP_ECU_Error = 1; +static uint8_t battery2_BMS_a161_SW_DI_Open_Request = 1; +static uint8_t battery2_BMS_a162_SW_No_Power_For_Support = 1; +static uint8_t battery2_BMS_a163_SW_Contactor_Mismatch = 1; +static uint8_t battery2_BMS_a164_SW_Uncontrolled_Regen = 1; +static uint8_t battery2_BMS_a165_SW_Pack_Partial_Weld = 1; +static uint8_t battery2_BMS_a166_SW_Pack_Full_Weld = 1; +static uint8_t battery2_BMS_a167_SW_FC_Partial_Weld = 1; +static uint8_t battery2_BMS_a168_SW_FC_Full_Weld = 1; +static uint8_t battery2_BMS_a170_SW_Limp_Mode = 1; +static uint8_t battery2_BMS_a171_SW_Stack_Voltage_Sense = 1; +static uint8_t battery2_BMS_a174_SW_Charge_Failure = 1; +static uint8_t battery2_BMS_a179_SW_Hvp_12V_Fault = 1; +static uint8_t battery2_BMS_a180_SW_ECU_reset_blocked = 1; + #endif //DOUBLE_BATTERY static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", @@ -1519,33 +1783,30 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_energy_buffer_m1 = (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X battery2_expected_energy_remaining_m1 = - (rx_frame.data.u8[5] | - rx_frame.data.u8[4]); //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X + (rx_frame.data.u8[5] | rx_frame.data.u8[4]); //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X battery2_energy_to_charge_complete_m1 = - (rx_frame.data.u8[7] | - rx_frame.data.u8[6]); //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + (rx_frame.data.u8[7] | rx_frame.data.u8[6]); //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X } if (mux == 2) {} // Additional information needed on this mux, example frame: 02 26 02 20 02 80 00 00 doesn't change // older BMS <2021 without mux - //battery2_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); - (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) - //battery2_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); - (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh - //battery2_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); - (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | - ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) - //battery2_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); - (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh - //battery2_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); - (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh - //battery2_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); - (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 - //battery2_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); - ((rx_frame.data.u8[7] & 0x01) >> 7); + battery2_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); + (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) + battery2_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); + (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh + battery2_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); + (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | + ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) + battery2_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); + (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh + battery2_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); + (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh + battery2_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); + (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 + battery2_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); + ((rx_frame.data.u8[7] & 0x01) >> 7); break; - case 0x20A: - //Contactor state + case 0x20A: //522 HVP_contactorState: battery2_packContNegativeState = (rx_frame.data.u8[0] & 0x07); battery2_packContPositiveState = (rx_frame.data.u8[0] & 0x38) >> 3; battery2_contactor = (rx_frame.data.u8[1] & 0x0F); @@ -1553,22 +1814,89 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_packCtrsClosingAllowed = (rx_frame.data.u8[4] & 0x08) >> 3; battery2_pyroTestInProgress = (rx_frame.data.u8[4] & 0x20) >> 5; battery2_hvil_status = (rx_frame.data.u8[5] & 0x0F); - //HVP_packCtrsOpenNowRequested : 33|1@1+ (1,0) [0|1] "" - //HVP_packCtrsOpenRequested : 34|1@1+ (1,0) [0|1] "" - //HVP_packCtrsRequestStatus : 30|2@1+ (1,0) [0|2] "" - //HVP_packCtrsResetRequestRequired : 32|1@1+ (1,0) [0|1] "" - //HVP_dcLinkAllowedToEnergize : 36|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContNegativeAuxOpen : 7|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContNegativeState : 12|3@1+ (1,0) [0|7] "" Receiver - //HVP_fcContPositiveAuxOpen : 6|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContPositiveState : 16|3@1+ (1,0) [0|7] "" Receiver - //HVP_fcContactorSetState : 19|4@1+ (1,0) [0|9] "" Receiver - //HVP_fcCtrsClosingAllowed : 29|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsOpenNowRequested : 27|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsOpenRequested : 28|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsRequestStatus : 24|2@1+ (1,0) [0|2] "" Receiver - //HVP_fcCtrsResetRequestRequired : 26|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcLinkAllowedToEnergize : 44|2@1+ (1,0) [0|2] "" Receiver + battery2_packCtrsOpenNowRequested = + ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|1] //to datalayer_extended + battery2_packCtrsOpenRequested = + ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|1] //to datalayer_extended + battery2_packCtrsRequestStatus = + ((rx_frame.data.u8[3] >> 6) & (0x03U)); //30|2@1+ (1,0) [0|2] //to datalayer_extended + battery2_packCtrsResetRequestRequired = + (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|1] //to datalayer_extended + battery2_dcLinkAllowedToEnergize = + ((rx_frame.data.u8[4] >> 4) & (0x01U)); //36|1@1+ (1,0) [0|1] //to datalayer_extended + battery2_fcContNegativeAuxOpen = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|1] "" Receiver + battery2_fcContNegativeState = ((rx_frame.data.u8[1] >> 4) & (0x07U)); //12|3@1+ (1,0) [0|7] "" Receiver + battery2_fcContPositiveAuxOpen = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|1] "" Receiver + battery2_fcContPositiveState = (rx_frame.data.u8[2] & (0x07U)); //16|3@1+ (1,0) [0|7] "" Receiver + battery2_fcContactorSetState = ((rx_frame.data.u8[2] >> 3) & (0x0FU)); //19|4@1+ (1,0) [0|9] "" Receiver + battery2_fcCtrsClosingAllowed = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|1] "" Receiver + battery2_fcCtrsOpenNowRequested = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|1] "" Receiver + battery2_fcCtrsOpenRequested = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|1] "" Receiver + battery2_fcCtrsRequestStatus = (rx_frame.data.u8[3] & (0x03U)); //24|2@1+ (1,0) [0|2] "" Receiver + battery2_fcCtrsResetRequestRequired = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|1] "" Receiver + battery2_fcLinkAllowedToEnergize = ((rx_frame.data.u8[5] >> 4) & (0x03U)); //44|2@1+ (1,0) [0|2] "" Receiver + break; + case 0x212: //530 BMS_status: 8 + battery2_BMS_hvacPowerRequest = (rx_frame.data.u8[0] & (0x01U)); + battery2_BMS_notEnoughPowerForDrive = ((rx_frame.data.u8[0] >> 1) & (0x01U)); + battery2_BMS_notEnoughPowerForSupport = ((rx_frame.data.u8[0] >> 2) & (0x01U)); + battery2_BMS_preconditionAllowed = ((rx_frame.data.u8[0] >> 3) & (0x01U)); + battery2_BMS_updateAllowed = ((rx_frame.data.u8[0] >> 4) & (0x01U)); + battery2_BMS_activeHeatingWorthwhile = ((rx_frame.data.u8[0] >> 5) & (0x01U)); + battery2_BMS_cpMiaOnHvs = ((rx_frame.data.u8[0] >> 6) & (0x01U)); + battery2_BMS_contactorState = + (rx_frame.data.u8[1] & + (0x07U)); //0 "SNA" 1 "OPEN" 2 "OPENING" 3 "CLOSING" 4 "CLOSED" 5 "WELDED" 6 "BLOCKED" ; + battery2_BMS_state = + ((rx_frame.data.u8[1] >> 3) & + (0x0FU)); //0 "STANDBY" 1 "DRIVE" 2 "SUPPORT" 3 "CHARGE" 4 "FEIM" 5 "CLEAR_FAULT" 6 "FAULT" 7 "WELD" 8 "TEST" 9 "SNA" ; + battery2_BMS_hvState = + (rx_frame.data.u8[2] & + (0x07U)); //0 "DOWN" 1 "COMING_UP" 2 "GOING_DOWN" 3 "UP_FOR_DRIVE" 4 "UP_FOR_CHARGE" 5 "UP_FOR_DC_CHARGE" 6 "UP" ; + battery2_BMS_isolationResistance = + ((rx_frame.data.u8[3] & (0x1FU)) << 5) | + ((rx_frame.data.u8[2] >> 3) & (0x1FU)); //19|10@1+ (10,0) [0|0] "kOhm"/to datalayer_extended + battery2_BMS_chargeRequest = ((rx_frame.data.u8[3] >> 5) & (0x01U)); + battery2_BMS_keepWarmRequest = ((rx_frame.data.u8[3] >> 6) & (0x01U)); + battery2_BMS_uiChargeStatus = + (rx_frame.data.u8[4] & + (0x07U)); // 0 "DISCONNECTED" 1 "NO_POWER" 2 "ABOUT_TO_CHARGE" 3 "CHARGING" 4 "CHARGE_COMPLETE" 5 "CHARGE_STOPPED" ; + battery2_BMS_diLimpRequest = ((rx_frame.data.u8[4] >> 3) & (0x01U)); + battery2_BMS_okToShipByAir = ((rx_frame.data.u8[4] >> 4) & (0x01U)); + battery2_BMS_okToShipByLand = ((rx_frame.data.u8[4] >> 5) & (0x01U)); + battery2_BMS_chgPowerAvailable = ((rx_frame.data.u8[6] & (0x01U)) << 10) | ((rx_frame.data.u8[5] & (0xFFU)) << 2) | + ((rx_frame.data.u8[4] >> 6) & (0x03U)); //38|11@1+ (0.125,0) [0|0] "kW" + battery2_BMS_chargeRetryCount = ((rx_frame.data.u8[6] >> 1) & (0x0FU)); + battery2_BMS_pcsPwmEnabled = ((rx_frame.data.u8[6] >> 5) & (0x01U)); + battery2_BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); + battery2_BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC + break; + case 0x224: //548 PCS_dcdcStatus: + battery2_PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ; + battery2_PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" + battery2_PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" + battery2_PCS_dcdcMainState = + ((rx_frame.data.u8[1] & (0x03U)) << 2) | + ((rx_frame.data.u8[0] >> 6) & + (0x03U)); //0 "STANDBY" 1 "12V_SUPPORT_ACTIVE" 2 "PRECHARGE_STARTUP" 3 "PRECHARGE_ACTIVE" 4 "DIS_HVBUS_ACTIVE" 5 "SHUTDOWN" 6 "FAULTED" ; + battery2_PCS_dcdcSubState = + ((rx_frame.data.u8[1] >> 2) & + (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; + battery2_PCS_dcdcFaulted = ((rx_frame.data.u8[1] >> 7) & (0x01U)); + battery2_PCS_dcdcOutputIsLimited = ((rx_frame.data.u8[3] >> 4) & (0x01U)); + battery2_PCS_dcdcMaxOutputCurrentAllowed = ((rx_frame.data.u8[5] & (0x01U)) << 11) | + ((rx_frame.data.u8[4] & (0xFFU)) << 3) | + ((rx_frame.data.u8[3] >> 5) & (0x07U)); //29|12@1+ (0.1,0) [0|0] "A" + battery2_PCS_dcdcPrechargeRtyCnt = ((rx_frame.data.u8[5] >> 1) & (0x07U)); + battery2_PCS_dcdc12VSupportRtyCnt = ((rx_frame.data.u8[5] >> 4) & (0x0FU)); + battery2_PCS_dcdcDischargeRtyCnt = (rx_frame.data.u8[6] & (0x0FU)); + battery2_PCS_dcdcPwmEnableLine = ((rx_frame.data.u8[6] >> 4) & (0x01U)); + battery2_PCS_dcdcSupportingFixedLvTarget = ((rx_frame.data.u8[6] >> 5) & (0x01U)); + battery2_PCS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); + battery2_PCS_dcdcPrechargeRestartCnt = (rx_frame.data.u8[7] & (0x07U)); + battery2_PCS_dcdcInitialPrechargeSubState = + ((rx_frame.data.u8[7] >> 3) & + (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; break; case 0x252: //Limits @@ -1591,10 +1919,8 @@ void receive_can_battery2(CAN_frame rx_frame) { if (battery2_charge_time_remaining == 4095) { battery2_charge_time_remaining = 0; } - break; - case 0x3D2: - // total charge/discharge kwh + case 0x3D2: // total charge/discharge kwh battery2_total_discharge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.001; @@ -1602,8 +1928,7 @@ void receive_can_battery2(CAN_frame rx_frame) { rx_frame.data.u8[4]) * 0.001; break; - case 0x332: - //min/max hist values + case 0x332: //min/max hist values //BattBrickMinMax: mux = (rx_frame.data.u8[0] & 0x03); if (mux == 1) //Cell voltages @@ -1614,14 +1939,116 @@ void receive_can_battery2(CAN_frame rx_frame) { temp = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); temp = (temp & 0xFFF); battery2_cell_min_v = temp * 2; - battery2_max_vno = 1 + (rx_frame.data.u8[4] & 0x7F); //This cell has highest voltage - battery2_min_vno = 1 + (rx_frame.data.u8[5] & 0x7F); //This cell has lowest voltage + //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[1] & (0x3FU)) << 6) | ((_d[0] >> 2) & (0x3FU)); + battery2_BrickVoltageMax = + ((rx_frame.data.u8[1] & (0x3F)) << 6) | ((rx_frame.data.u8[0] >> 2) & (0x3F)); //to datalayer_extended + //BattBrickVoltageMin m1 : 16|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[3] & (0x0FU)) << 8) | (_d[2] & (0xFFU)); + battery2_BrickVoltageMin = + ((rx_frame.data.u8[3] & (0x0F)) << 8) | (rx_frame.data.u8[2] & (0xFF)); //to datalayer_extended + //BattBrickVoltageMaxNum m1 : 32|7@1+ (1,1) [0|0] "" Receiver + battery2_BrickVoltageMaxNum = 1 + (rx_frame.data.u8[4] & 0x7F); //This cell has highest voltage + battery2_BrickVoltageMinNum = 1 + (rx_frame.data.u8[5] & 0x7F); //This cell has lowest voltage } if (mux == 0) //Temperature sensors { battery2_max_temp = (rx_frame.data.u8[2] * 5) - 400; //Temperature values have 40.0*C offset, 0.5*C /bit battery2_min_temp = (rx_frame.data.u8[3] * 5) - 400; //Multiply by 5 and remove offset to get C+1 (0x61*5=485-400=8.5*C) + //BattBrickTempMaxNum m0 : 2|4@1+ (1,0) [0|0] "" ((_d[0] >> 2) & (0x0FU)); + battery2_BrickTempMaxNum = ((rx_frame.data.u8[0] >> 2) & (0x0F)); //to datalayer_extended + //BattBrickTempMinNum m0 : 8|4@1+ (1,0) [0|0] "" (_d[1] & (0x0FU)); + battery2_BrickTempMinNum = (rx_frame.data.u8[1] & (0x0F)); //to datalayer_extended + //BattBrickModelTMax m0 : 32|8@1+ (0.5,-40) [0|0] "C" (_d[4] & (0xFFU)); + battery2_BrickModelTMax = (rx_frame.data.u8[4] & (0xFFU)); //to datalayer_extended + //BattBrickModelTMin m0 : 40|8@1+ (0.5,-40) [0|0] "C" (_d[5] & (0xFFU)); + battery2_BrickModelTMin = (rx_frame.data.u8[5] & (0xFFU)); //to datalayer_extended + } + break; + case 0x312: // 786 BMS_thermalStatus + BMS2_powerDissipation = + ((rx_frame.data.u8[1] & (0x03U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|10@1+ (0.02,0) [0|0] "kW" + BMS2_flowRequest = ((rx_frame.data.u8[2] & (0x01U)) << 6) | + ((rx_frame.data.u8[1] >> 2) & (0x3FU)); //10|7@1+ (0.3,0) [0|0] "LPM" + BMS2_inletActiveCoolTargetT = ((rx_frame.data.u8[3] & (0x03U)) << 7) | + ((rx_frame.data.u8[2] >> 1) & (0x7FU)); //17|9@1+ (0.25,-25) [0|0] "DegC" + BMS2_inletPassiveTargetT = ((rx_frame.data.u8[4] & (0x07U)) << 6) | + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //26|9@1+ (0.25,-25) [0|0] "DegC" X + BMS2_inletActiveHeatTargetT = ((rx_frame.data.u8[5] & (0x0FU)) << 5) | + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|9@1+ (0.25,-25) [0|0] "DegC" + BMS2_packTMin = ((rx_frame.data.u8[6] & (0x1FU)) << 4) | + ((rx_frame.data.u8[5] >> 4) & (0x0FU)); //44|9@1+ (0.25,-25) [-25|100] "DegC" + BMS2_packTMax = ((rx_frame.data.u8[7] & (0x3FU)) << 3) | + ((rx_frame.data.u8[6] >> 5) & (0x07U)); //53|9@1+ (0.25,-25) [-25|100] "DegC" + BMS2_pcsNoFlowRequest = ((rx_frame.data.u8[7] >> 6) & (0x01U)); // 62|1@1+ (1,0) [0|0] "" + BMS2_noFlowRequest = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" + break; + case 0x2A4: //676 PCS_thermalStatus + PCS2_chgPhATemp = + ((rx_frame.data.u8[1] & (0x07U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|11@1- (0.1,40) [0|0] "C + PCS2_chgPhBTemp = + ((rx_frame.data.u8[2] & (0x3FU)) << 5) | ((rx_frame.data.u8[1] >> 3) & (0x1FU)); //11|11@1- (0.1,40) [0|0] "C + PCS2_chgPhCTemp = + ((rx_frame.data.u8[4] & (0x07U)) << 8) | (rx_frame.data.u8[3] & (0xFFU)); //24|11@1- (0.1,40) [0|0] "C" + PCS2_dcdcTemp = ((rx_frame.data.u8[5] & (0x3FU)) << 5) | + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|11@1- (0.1,40) [0|0] "C" + PCS2_ambientTemp = + ((rx_frame.data.u8[7] & (0x07U)) << 8) | (rx_frame.data.u8[6] & (0xFFU)); //48|11@1- (0.1,40) [0|0] "C" + break; + case 0x2C4: // 708 PCS_logging: not all frames are listed, just ones relating to dcdc + mux = (rx_frame.data.u8[0] & (0x1FU)); + //PCS_logMessageSelect = (rx_frame.data.u8[0] & (0x1FU)); //0|5@1+ (1,0) [0|0] "" + if (mux == 6) { + PCS2_dcdcMaxLvOutputCurrent = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //m6 : 28|12@1+ (0.1,0) [0|0] "A" X + PCS2_dcdcCurrentLimit = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //m6 : 40|12@1+ (0.1,0) [0|0] "A" X + PCS2_dcdcLvOutputCurrentTempLimit = ((rx_frame.data.u8[7] & (0xFFU)) << 4) | + ((rx_frame.data.u8[6] >> 4) & (0x0FU)); //m6 : 52|12@1+ (0.1,0) [0|0] "A" X + } + if (mux == 7) { + PCS2_dcdcUnifiedCommand = ((rx_frame.data.u8[1] & (0x7FU)) << 3) | + ((rx_frame.data.u8[0] >> 5) & (0x07U)); //m7 : 5|10@1+ (0.001,0) [0|0] "1" X + PCS2_dcdcCLAControllerOutput = ((rx_frame.data.u8[3] & (0x03U)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //m7 : 16|10@1+ (0.001,0) [0|0] "1" X + PCS2_dcdcTankVoltage = ((rx_frame.data.u8[4] & (0x1FU)) << 6) | + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //m7 : 26|11@1- (1,0) [0|0] "V" X + PCS2_dcdcTankVoltageTarget = ((rx_frame.data.u8[5] & (0x7FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m7 : 37|10@1+ (1,0) [0|0] "V" X + PCS2_dcdcClaCurrentFreq = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //P m7 : 48|12@1+ (0.0976563,0) [0|0] "kHz" X + } + if (mux == 8) { + PCS2_dcdcTCommMeasured = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m8 : 8|16@1- (0.00195313,0) [0|0] "us" X + PCS2_dcdcShortTimeUs = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); // m8 : 24|16@1+ (0.000488281,0) [0|0] "us" X + PCS2_dcdcHalfPeriodUs = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); // m8 : 40|16@1+ (0.000488281,0) [0|0] "us" X + } + if (mux == 18) { + PCS2_dcdcIntervalMaxFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m18 : 8|12@1+ (1,0) [0|0] "kHz" X + PCS2_dcdcIntervalMaxHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //m18 : 24|13@1+ (0.1,0) [0|0] "V" X + PCS2_dcdcIntervalMaxLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m18 : 37|9@1+ (0.1,0) [0|0] "V" X + PCS2_dcdcIntervalMaxLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //m18 : 48|12@1+ (1,0) [0|0] "A" X + } + if (mux == 19) { + PCS2_dcdcIntervalMinFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //m19 : 8|12@1+ (1,0) [0|0] "kHz" X + PCS2_dcdcIntervalMinHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //m19 : 24|13@1+ (0.1,0) [0|0] "V" X + PCS2_dcdcIntervalMinLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); //m19 : 37|9@1+ (0.1,0) [0|0] "V" X + PCS2_dcdcIntervalMinLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); // m19 : 48|12@1+ (1,0) [0|0] "A" X + } + if (mux == 22) { + PCS2_dcdc12vSupportLifetimekWh = ((rx_frame.data.u8[3] & (0xFFU)) << 16) | + ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m22 : 8|24@1+ (0.01,0) [0|0] "kWh" X } break; case 0x401: // Cell stats @@ -1692,6 +2119,103 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); } break; + case 0x7AA: //1962 HVP_debugMessage: + mux = (rx_frame.data.u8[0] & (0x0FU)); + //HVP_debugMessageMultiplexer = (rx_frame.data.u8[0] & (0x0FU)); //0|4@1+ (1,0) [0|6] "" + if (mux == 0) { + HVP2_gpioPassivePyroDepl = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //: 4|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPyroIsoEn = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //: 5|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioCpFaultIn = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //: 6|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPackContPowerEn = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //: 7|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioHvCablesOk = (rx_frame.data.u8[1] & (0x01U)); //: 8|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioHvpSelfEnable = ((rx_frame.data.u8[1] >> 1) & (0x01U)); //: 9|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioLed = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //: 10|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioCrashSignal = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //: 11|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioShuntDataReady = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //: 12|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioFcContPosAux = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //: 13|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioFcContNegAux = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //: 14|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioBmsEout = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //: 15|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioCpFaultOut = (rx_frame.data.u8[2] & (0x01U)); //: 16|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPyroPor = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //: 17|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioShuntEn = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //: 18|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioHvpVerEn = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //: 19|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPackCoontPosFlywheel = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //: 20|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioCpLatchEnable = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //: 21|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPcsEnable = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //: 22|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPcsDcdcPwmEnable = ((rx_frame.data.u8[2] >> 7) & (0x01U)); //: 23|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPcsChargePwmEnable = (rx_frame.data.u8[3] & (0x01U)); //: 24|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioFcContPowerEnable = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //: 25|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioHvilEnable = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //: 26|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioSecDrdy = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //: 27|1@1+ (1,0) [0|1] "" Receiver + HVP2_hvp1v5Ref = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|3] "V" Receiver + HVP2_shuntCurrentDebug = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP2_packCurrentMia = (rx_frame.data.u8[7] & (0x01U)); //: 56|1@1+ (1,0) [0|1] "" Receiver + HVP2_auxCurrentMia = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //: 57|1@1+ (1,0) [0|1] "" Receiver + HVP2_currentSenseMia = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|1@1+ (1,0) [0|1] "" Receiver + HVP2_shuntRefVoltageMismatch = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //: 59|1@1+ (1,0) [0|1] "" Receiver + HVP2_shuntThermistorMia = ((rx_frame.data.u8[7] >> 4) & (0x01U)); //: 60|1@1+ (1,0) [0|1] "" Receiver + HVP2_shuntHwMia = ((rx_frame.data.u8[7] >> 5) & (0x01U)); //: 61|1@1+ (1,0) [0|1] "" Receiver + } + if (mux == 1) { + HVP2_dcLinkVoltage = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + HVP2_packVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + HVP2_fcLinkVoltage = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + } + if (mux == 2) { + HVP2_packContVoltage = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_packNegativeV = ((rx_frame.data.u8[3] & (0xFFU)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //: 16|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_packPositiveV = ((rx_frame.data.u8[5] & (0xFFU)) << 8) | + (rx_frame.data.u8[4] & (0xFFU)); //: 32|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_pyroAnalog = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|12@1+ (0.1,0) [0|3] "V" Receiver + } + if (mux == 3) { + HVP2_dcLinkNegativeV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_dcLinkPositiveV = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_fcLinkNegativeV = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-550|550] "V" Receiver + } + if (mux == 4) { + HVP2_fcContCoilCurrent = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|7.5] "A" Receiver + HVP2_fcContVoltage = ((rx_frame.data.u8[3] & (0x0FU)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //: 16|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_hvilInVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_hvilOutVoltage = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|12@1+ (0.1,0) [0|30] "V" Receiver + } + if (mux == 5) { + HVP2_fcLinkPositiveV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_packContCoilCurrent = ((rx_frame.data.u8[4] & (0x0FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|12@1+ (0.1,0) [0|7.5] "A" Receiver + HVP2_battery12V = ((rx_frame.data.u8[5] & (0xFFU)) << 4) | + ((rx_frame.data.u8[4] >> 4) & (0x0FU)); //: 36|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_shuntRefVoltageDbg = ((rx_frame.data.u8[7] & (0xFFU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|16@1- (0.001,0) [-32.768|32.767] "V" Receiver + } + if (mux == 6) { + HVP2_shuntAuxCurrentDbg = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP2_shuntBarTempDbg = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + HVP2_shuntAsicTempDbg = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + HVP2_shuntAuxCurrentStatus = (rx_frame.data.u8[7] & (0x03U)); //: 56|2@1+ (1,0) [0|3] "" Receiver + HVP2_shuntBarTempStatus = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|2@1+ (1,0) [0|3] "" Receiver + HVP2_shuntAsicTempStatus = ((rx_frame.data.u8[7] >> 4) & (0x03U)); //: 60|2@1+ (1,0) [0|3] "" Receiver + } + break; case 0x3aa: //HVP_alertMatrix1 battery2_WatchdogReset = (rx_frame.data.u8[0] & 0x01); battery2_PowerLossReset = ((rx_frame.data.u8[0] & 0x02) >> 1); @@ -1745,6 +2269,110 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_fcCtrCloseFailed = ((rx_frame.data.u8[6] & 0x02) >> 1); battery2_shuntThermistorMia = ((rx_frame.data.u8[6] & 0x04) >> 2); break; + case 0x320: //800 BMS_alertMatrix //BMS_alertMatrix 800 BMS_alertMatrix: 8 VEH + mux = (rx_frame.data.u8[0] & (0x0F)); + if (mux == 0) + ; + { //mux0 + battery2_BMS_matrixIndex = (rx_frame.data.u8[0] & (0x0F)); // 0|4@1+ (1,0) [0|0] "" X + battery2_BMS_a017_SW_Brick_OV = ((rx_frame.data.u8[2] >> 4) & (0x01)); //20|1@1+ (1,0) [0|0] "" X + battery2_BMS_a018_SW_Brick_UV = ((rx_frame.data.u8[2] >> 5) & (0x01)); //21|1@1+ (1,0) [0|0] "" X + battery2_BMS_a019_SW_Module_OT = ((rx_frame.data.u8[2] >> 6) & (0x01)); //22|1@1+ (1,0) [0|0] "" X + battery2_BMS_a021_SW_Dr_Limits_Regulation = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery2_BMS_a022_SW_Over_Current = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X + battery2_BMS_a023_SW_Stack_OV = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X + battery2_BMS_a024_SW_Islanded_Brick = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery2_BMS_a025_SW_PwrBalance_Anomaly = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X + battery2_BMS_a026_SW_HFCurrent_Anomaly = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X + battery2_BMS_a034_SW_Passive_Isolation = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X ? + battery2_BMS_a035_SW_Isolation = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //38|1@1+ (1,0) [0|0] "" X + battery2_BMS_a036_SW_HvpHvilFault = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X + battery2_BMS_a037_SW_Flood_Port_Open = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X + battery2_BMS_a039_SW_DC_Link_Over_Voltage = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery2_BMS_a041_SW_Power_On_Reset = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X + battery2_BMS_a042_SW_MPU_Error = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X + battery2_BMS_a043_SW_Watch_Dog_Reset = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X + battery2_BMS_a044_SW_Assertion = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X + battery2_BMS_a045_SW_Exception = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery2_BMS_a046_SW_Task_Stack_Usage = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery2_BMS_a047_SW_Task_Stack_Overflow = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + battery2_BMS_a048_SW_Log_Upload_Request = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X + battery2_BMS_a050_SW_Brick_Voltage_MIA = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X + battery2_BMS_a051_SW_HVC_Vref_Bad = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X + battery2_BMS_a052_SW_PCS_MIA = ((rx_frame.data.u8[6] >> 7) & (0x01U)); //55|1@1+ (1,0) [0|0] "" X + battery2_BMS_a053_SW_ThermalModel_Sanity = (rx_frame.data.u8[7] & (0x01U)); //56|1@1+ (1,0) [0|0] "" X + battery2_BMS_a054_SW_Ver_Supply_Fault = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X + battery2_BMS_a059_SW_Pack_Voltage_Sensing = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X + battery2_BMS_a060_SW_Leakage_Test_Failure = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X + } + if (mux == 1) { //mux1 + battery2_BMS_a061_robinBrickOverVoltage = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //4|1@1+ (1,0) [0|0] "" X + battery2_BMS_a062_SW_BrickV_Imbalance = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X + battery2_BMS_a063_SW_ChargePort_Fault = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X + battery2_BMS_a064_SW_SOC_Imbalance = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|0] "" X + battery2_BMS_a069_SW_Low_Power = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X + battery2_BMS_a071_SW_SM_TransCon_Not_Met = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X + battery2_BMS_a075_SW_Chg_Disable_Failure = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //18|1@1+ (1,0) [0|0] "" X + battery2_BMS_a076_SW_Dch_While_Charging = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X + battery2_BMS_a077_SW_Charger_Regulation = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X + battery2_BMS_a081_SW_Ctr_Close_Blocked = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery2_BMS_a082_SW_Ctr_Force_Open = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X + battery2_BMS_a083_SW_Ctr_Close_Failure = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X + battery2_BMS_a084_SW_Sleep_Wake_Aborted = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery2_BMS_a087_SW_Feim_Test_Blocked = ((rx_frame.data.u8[3] >> 6) & (0x01U)); //30|1@1+ (1,0) [0|0] "" X + battery2_BMS_a088_SW_VcFront_MIA_InDrive = ((rx_frame.data.u8[3] >> 7) & (0x01U)); //31|1@1+ (1,0) [0|0] "" X + battery2_BMS_a089_SW_VcFront_MIA = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X + battery2_BMS_a090_SW_Gateway_MIA = ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|0] "" X + battery2_BMS_a091_SW_ChargePort_MIA = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X + battery2_BMS_a092_SW_ChargePort_Mia_On_Hv = ((rx_frame.data.u8[4] >> 3) & (0x01U)); //35|1@1+ (1,0) [0|0] "" X + battery2_BMS_a094_SW_Drive_Inverter_MIA = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X + battery2_BMS_a099_SW_BMB_Communication = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery2_BMS_a105_SW_One_Module_Tsense = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery2_BMS_a106_SW_All_Module_Tsense = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery2_BMS_a107_SW_Stack_Voltage_MIA = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + } + if (mux == 2) { //mux2 + battery2_BMS_a121_SW_NVRAM_Config_Error = ((rx_frame.data.u8[0] >> 4) & (0x01U)); // 4|1@1+ (1,0) [0|0] "" X + battery2_BMS_a122_SW_BMS_Therm_Irrational = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X + battery2_BMS_a123_SW_Internal_Isolation = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X + battery2_BMS_a127_SW_shunt_SNA = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //10|1@1+ (1,0) [0|0] "" X + battery2_BMS_a128_SW_shunt_MIA = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //11|1@1+ (1,0) [0|0] "" X + battery2_BMS_a129_SW_VSH_Failure = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X + battery2_BMS_a130_IO_CAN_Error = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //13|1@1+ (1,0) [0|0] "" X + battery2_BMS_a131_Bleed_FET_Failure = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X + battery2_BMS_a132_HW_BMB_OTP_Uncorrctbl = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //15|1@1+ (1,0) [0|0] "" X + battery2_BMS_a134_SW_Delayed_Ctr_Off = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //17|1@1+ (1,0) [0|0] "" X + battery2_BMS_a136_SW_Module_OT_Warning = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X + battery2_BMS_a137_SW_Brick_UV_Warning = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X + battery2_BMS_a138_SW_Brick_OV_Warning = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //21|1@1+ (1,0) [0|0] "" X + battery2_BMS_a139_SW_DC_Link_V_Irrational = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //22|1@1+ (1,0) [0|0] "" X + battery2_BMS_a141_SW_BMB_Status_Warning = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery2_BMS_a144_Hvp_Config_Mismatch = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery2_BMS_a145_SW_SOC_Change = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X + battery2_BMS_a146_SW_Brick_Overdischarged = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X + battery2_BMS_a149_SW_Missing_Config_Block = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X + battery2_BMS_a151_SW_external_isolation = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X + battery2_BMS_a156_SW_BMB_Vref_bad = ((rx_frame.data.u8[4] >> 7) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X + battery2_BMS_a157_SW_HVP_HVS_Comms = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X + battery2_BMS_a158_SW_HVP_HVI_Comms = ((rx_frame.data.u8[5] >> 1) & (0x01U)); //41|1@1+ (1,0) [0|0] "" X + battery2_BMS_a159_SW_HVP_ECU_Error = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery2_BMS_a161_SW_DI_Open_Request = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X + battery2_BMS_a162_SW_No_Power_For_Support = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X + battery2_BMS_a163_SW_Contactor_Mismatch = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X + battery2_BMS_a164_SW_Uncontrolled_Regen = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X + battery2_BMS_a165_SW_Pack_Partial_Weld = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery2_BMS_a166_SW_Pack_Full_Weld = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery2_BMS_a167_SW_FC_Partial_Weld = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + battery2_BMS_a168_SW_FC_Full_Weld = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X + battery2_BMS_a169_SW_FC_Pack_Weld = ((rx_frame.data.u8[6] >> 4) & (0x01U)); //52|1@1+ (1,0) [0|0] "" X + battery2_BMS_a170_SW_Limp_Mode = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X + battery2_BMS_a171_SW_Stack_Voltage_Sense = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X + battery2_BMS_a174_SW_Charge_Failure = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X + battery2_BMS_a176_SW_GracefulPowerOff = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //59|1@1+ (1,0) [0|0] "" X + battery2_BMS_a179_SW_Hvp_12V_Fault = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X + battery2_BMS_a180_SW_ECU_reset_blocked = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X + } + break; default: break; } @@ -1801,7 +2429,7 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.cell_min_voltage_mV = battery2_cell_min_v; - datalayer.battery2_cell_deviation_mV = (battery2_cell_max_v - battery2_cell_min_v); + battery2_cell_deviation_mV = (battery2_cell_max_v - battery2_cell_min_v); /* Value mapping is completed. Start to check all safeties */ @@ -2270,6 +2898,98 @@ void printFaultCodesIfActive_battery2() { printDebugIfActive(battery2_packCtrCloseFailed, "ERROR: packCtrCloseFailed is active"); printDebugIfActive(battery2_fcCtrCloseFailed, "ERROR: fcCtrCloseFailed is active"); printDebugIfActive(battery2_shuntThermistorMia, "ERROR: shuntThermistorMia is active"); + // 0x320 800 BMS_alertMatrix + printDebugIfActive(battery2_BMS_a017_SW_Brick_OV, "ERROR: BMS_a017_SW_Brick_OV"); + printDebugIfActive(battery2_BMS_a018_SW_Brick_UV, "ERROR: BMS_a018_SW_Brick_UV"); + printDebugIfActive(battery2_BMS_a019_SW_Module_OT, "ERROR: BMS_a019_SW_Module_OT"); + printDebugIfActive(battery2_BMS_a021_SW_Dr_Limits_Regulation, "ERROR: BMS_a021_SW_Dr_Limits_Regulation"); + printDebugIfActive(battery2_BMS_a022_SW_Over_Current, "ERROR: BMS_a022_SW_Over_Current"); + printDebugIfActive(battery2_BMS_a023_SW_Stack_OV, "ERROR: BMS_a023_SW_Stack_OV"); + printDebugIfActive(battery2_BMS_a024_SW_Islanded_Brick, "ERROR: BMS_a024_SW_Islanded_Brick"); + printDebugIfActive(battery2_BMS_a025_SW_PwrBalance_Anomaly, "ERROR: BMS_a025_SW_PwrBalance_Anomaly"); + printDebugIfActive(battery2_BMS_a026_SW_HFCurrent_Anomaly, "ERROR: BMS_a026_SW_HFCurrent_Anomaly"); + printDebugIfActive(battery2_BMS_a034_SW_Passive_Isolation, "ERROR: BMS_a034_SW_Passive_Isolation"); + printDebugIfActive(battery2_BMS_a035_SW_Isolation, "ERROR: BMS_a035_SW_Isolation"); + printDebugIfActive(battery2_BMS_a036_SW_HvpHvilFault, "ERROR: BMS_a036_SW_HvpHvilFault"); + printDebugIfActive(battery2_BMS_a037_SW_Flood_Port_Open, "ERROR: BMS_a037_SW_Flood_Port_Open"); + printDebugIfActive(battery2_BMS_a039_SW_DC_Link_Over_Voltage, "ERROR: BMS_a039_SW_DC_Link_Over_Voltage"); + printDebugIfActive(battery2_BMS_a041_SW_Power_On_Reset, "ERROR: BMS_a041_SW_Power_On_Reset"); + printDebugIfActive(battery2_BMS_a042_SW_MPU_Error, "ERROR: BMS_a042_SW_MPU_Error"); + printDebugIfActive(battery2_BMS_a043_SW_Watch_Dog_Reset, "ERROR: BMS_a043_SW_Watch_Dog_Reset"); + printDebugIfActive(battery2_BMS_a044_SW_Assertion, "ERROR: BMS_a044_SW_Assertion"); + printDebugIfActive(battery2_BMS_a045_SW_Exception, "ERROR: BMS_a045_SW_Exception"); + printDebugIfActive(battery2_BMS_a046_SW_Task_Stack_Usage, "ERROR: BMS_a046_SW_Task_Stack_Usage"); + printDebugIfActive(battery2_BMS_a047_SW_Task_Stack_Overflow, "ERROR: BMS_a047_SW_Task_Stack_Overflow"); + printDebugIfActive(battery2_BMS_a048_SW_Log_Upload_Request, "ERROR: BMS_a048_SW_Log_Upload_Request"); + printDebugIfActive(battery2_BMS_a050_SW_Brick_Voltage_MIA, "ERROR: BMS_a050_SW_Brick_Voltage_MIA"); + printDebugIfActive(battery2_BMS_a051_SW_HVC_Vref_Bad, "ERROR: BMS_a051_SW_HVC_Vref_Bad"); + printDebugIfActive(battery2_BMS_a052_SW_PCS_MIA, "ERROR: BMS_a052_SW_PCS_MIA"); + printDebugIfActive(battery2_BMS_a053_SW_ThermalModel_Sanity, "ERROR: BMS_a053_SW_ThermalModel_Sanity"); + printDebugIfActive(battery2_BMS_a054_SW_Ver_Supply_Fault, "ERROR: BMS_a054_SW_Ver_Supply_Fault"); + printDebugIfActive(battery2_BMS_a059_SW_Pack_Voltage_Sensing, "ERROR: BMS_a059_SW_Pack_Voltage_Sensing"); + printDebugIfActive(battery2_BMS_a060_SW_Leakage_Test_Failure, "ERROR: BMS_a060_SW_Leakage_Test_Failure"); + printDebugIfActive(battery2_BMS_a061_robinBrickOverVoltage, "ERROR: BMS_a061_robinBrickOverVoltage"); + printDebugIfActive(battery2_BMS_a062_SW_BrickV_Imbalance, "ERROR: BMS_a062_SW_BrickV_Imbalance"); + printDebugIfActive(battery2_BMS_a063_SW_ChargePort_Fault, "ERROR: BMS_a063_SW_ChargePort_Fault"); + printDebugIfActive(battery2_BMS_a064_SW_SOC_Imbalance, "ERROR: BMS_a064_SW_SOC_Imbalance"); + printDebugIfActive(battery2_BMS_a069_SW_Low_Power, "ERROR: BMS_a069_SW_Low_Power"); + printDebugIfActive(battery2_BMS_a071_SW_SM_TransCon_Not_Met, "ERROR: BMS_a071_SW_SM_TransCon_Not_Met"); + printDebugIfActive(battery2_BMS_a075_SW_Chg_Disable_Failure, "ERROR: BMS_a075_SW_Chg_Disable_Failure"); + printDebugIfActive(battery2_BMS_a076_SW_Dch_While_Charging, "ERROR: BMS_a076_SW_Dch_While_Charging"); + printDebugIfActive(battery2_BMS_a077_SW_Charger_Regulation, "ERROR: BMS_a077_SW_Charger_Regulation"); + printDebugIfActive(battery2_BMS_a081_SW_Ctr_Close_Blocked, "ERROR: BMS_a081_SW_Ctr_Close_Blocked"); + printDebugIfActive(battery2_BMS_a082_SW_Ctr_Force_Open, "ERROR: BMS_a082_SW_Ctr_Force_Open"); + printDebugIfActive(battery2_BMS_a083_SW_Ctr_Close_Failure, "ERROR: BMS_a083_SW_Ctr_Close_Failure"); + printDebugIfActive(battery2_BMS_a084_SW_Sleep_Wake_Aborted, "ERROR: BMS_a084_SW_Sleep_Wake_Aborted"); + printDebugIfActive(battery2_BMS_a087_SW_Feim_Test_Blocked, "ERROR: BMS_a087_SW_Feim_Test_Blocked"); + printDebugIfActive(battery2_BMS_a088_SW_VcFront_MIA_InDrive, "ERROR: BMS_a088_SW_VcFront_MIA_InDrive"); + printDebugIfActive(battery2_BMS_a089_SW_VcFront_MIA, "ERROR: BMS_a089_SW_VcFront_MIA"); + printDebugIfActive(battery2_BMS_a090_SW_Gateway_MIA, "ERROR: BMS_a090_SW_Gateway_MIA"); + printDebugIfActive(battery2_BMS_a091_SW_ChargePort_MIA, "ERROR: BMS_a091_SW_ChargePort_MIA"); + printDebugIfActive(battery2_BMS_a092_SW_ChargePort_Mia_On_Hv, "ERROR: BMS_a092_SW_ChargePort_Mia_On_Hv"); + printDebugIfActive(battery2_BMS_a094_SW_Drive_Inverter_MIA, "ERROR: BMS_a094_SW_Drive_Inverter_MIA"); + printDebugIfActive(battery2_BMS_a099_SW_BMB_Communication, "ERROR: BMS_a099_SW_BMB_Communication"); + printDebugIfActive(battery2_BMS_a105_SW_One_Module_Tsense, "ERROR: BMS_a105_SW_One_Module_Tsense"); + printDebugIfActive(battery2_BMS_a106_SW_All_Module_Tsense, "ERROR: BMS_a106_SW_All_Module_Tsense"); + printDebugIfActive(battery2_BMS_a107_SW_Stack_Voltage_MIA, "ERROR: BMS_a107_SW_Stack_Voltage_MIA"); + printDebugIfActive(battery2_BMS_a121_SW_NVRAM_Config_Error, "ERROR: BMS_a121_SW_NVRAM_Config_Error"); + printDebugIfActive(battery2_BMS_a122_SW_BMS_Therm_Irrational, "ERROR: BMS_a122_SW_BMS_Therm_Irrational"); + printDebugIfActive(battery2_BMS_a123_SW_Internal_Isolation, "ERROR: BMS_a123_SW_Internal_Isolation"); + printDebugIfActive(battery2_BMS_a127_SW_shunt_SNA, "ERROR: BMS_a127_SW_shunt_SNA"); + printDebugIfActive(battery2_BMS_a128_SW_shunt_MIA, "ERROR: BMS_a128_SW_shunt_MIA"); + printDebugIfActive(battery2_BMS_a129_SW_VSH_Failure, "ERROR: BMS_a129_SW_VSH_Failure"); + printDebugIfActive(battery2_BMS_a130_IO_CAN_Error, "ERROR: BMS_a130_IO_CAN_Error"); + printDebugIfActive(battery2_BMS_a131_Bleed_FET_Failure, "ERROR: BMS_a131_Bleed_FET_Failure"); + printDebugIfActive(battery2_BMS_a132_HW_BMB_OTP_Uncorrctbl, "ERROR: BMS_a132_HW_BMB_OTP_Uncorrctbl"); + printDebugIfActive(battery2_BMS_a134_SW_Delayed_Ctr_Off, "ERROR: BMS_a134_SW_Delayed_Ctr_Off"); + printDebugIfActive(battery2_BMS_a136_SW_Module_OT_Warning, "ERROR: BMS_a136_SW_Module_OT_Warning"); + printDebugIfActive(battery2_BMS_a137_SW_Brick_UV_Warning, "ERROR: BMS_a137_SW_Brick_UV_Warning"); + printDebugIfActive(battery2_BMS_a139_SW_DC_Link_V_Irrational, "ERROR: BMS_a139_SW_DC_Link_V_Irrational"); + printDebugIfActive(battery2_BMS_a141_SW_BMB_Status_Warning, "ERROR: BMS_a141_SW_BMB_Status_Warning"); + printDebugIfActive(battery2_BMS_a144_Hvp_Config_Mismatch, "ERROR: BMS_a144_Hvp_Config_Mismatch"); + printDebugIfActive(battery2_BMS_a145_SW_SOC_Change, "ERROR: BMS_a145_SW_SOC_Change"); + printDebugIfActive(battery2_BMS_a146_SW_Brick_Overdischarged, "ERROR: BMS_a146_SW_Brick_Overdischarged"); + printDebugIfActive(battery2_BMS_a149_SW_Missing_Config_Block, "ERROR: BMS_a149_SW_Missing_Config_Block"); + printDebugIfActive(battery2_BMS_a151_SW_external_isolation, "ERROR: BMS_a151_SW_external_isolation"); + printDebugIfActive(battery2_BMS_a156_SW_BMB_Vref_bad, "ERROR: BMS_a156_SW_BMB_Vref_bad"); + printDebugIfActive(battery2_BMS_a157_SW_HVP_HVS_Comms, "ERROR: BMS_a157_SW_HVP_HVS_Comms"); + printDebugIfActive(battery2_BMS_a158_SW_HVP_HVI_Comms, "ERROR: BMS_a158_SW_HVP_HVI_Comms"); + printDebugIfActive(battery2_BMS_a159_SW_HVP_ECU_Error, "ERROR: BMS_a159_SW_HVP_ECU_Error"); + printDebugIfActive(battery2_BMS_a161_SW_DI_Open_Request, "ERROR: BMS_a161_SW_DI_Open_Request"); + printDebugIfActive(battery2_BMS_a162_SW_No_Power_For_Support, "ERROR: BMS_a162_SW_No_Power_For_Support"); + printDebugIfActive(battery2_BMS_a163_SW_Contactor_Mismatch, "ERROR: BMS_a163_SW_Contactor_Mismatch"); + printDebugIfActive(battery2_BMS_a164_SW_Uncontrolled_Regen, "ERROR: BMS_a164_SW_Uncontrolled_Regen"); + printDebugIfActive(battery2_BMS_a165_SW_Pack_Partial_Weld, "ERROR: BMS_a165_SW_Pack_Partial_Weld"); + printDebugIfActive(battery2_BMS_a166_SW_Pack_Full_Weld, "ERROR: BMS_a166_SW_Pack_Full_Weld"); + printDebugIfActive(battery2_BMS_a167_SW_FC_Partial_Weld, "ERROR: BMS_a167_SW_FC_Partial_Weld"); + printDebugIfActive(battery2_BMS_a168_SW_FC_Full_Weld, "ERROR: BMS_a168_SW_FC_Full_Weld"); + printDebugIfActive(battery2_BMS_a169_SW_FC_Pack_Weld, "ERROR: BMS_a169_SW_FC_Pack_Weld"); + printDebugIfActive(battery2_BMS_a170_SW_Limp_Mode, "ERROR: BMS_a170_SW_Limp_Mode"); + printDebugIfActive(battery2_BMS_a171_SW_Stack_Voltage_Sense, "ERROR: BMS_a171_SW_Stack_Voltage_Sense"); + printDebugIfActive(battery2_BMS_a174_SW_Charge_Failure, "ERROR: BMS_a174_SW_Charge_Failure"); + printDebugIfActive(battery2_BMS_a176_SW_GracefulPowerOff, "ERROR: BMS_a176_SW_GracefulPowerOff"); + printDebugIfActive(battery2_BMS_a179_SW_Hvp_12V_Fault, "ERROR: BMS_a179_SW_Hvp_12V_Fault"); + printDebugIfActive(battery2_BMS_a180_SW_ECU_reset_blocked, "ERROR: BMS_a180_SW_ECU_reset_blocked"); } #endif //DOUBLE_BATTERY From b4ea3dcf35c18427c26f6a0ae70a35aebd77a76e Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:06:28 +1300 Subject: [PATCH 076/225] Update TESLA-BATTERY.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 155 +++++++++++++------------ 1 file changed, 80 insertions(+), 75 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 26fa6f0b7..757817201 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -427,9 +427,9 @@ static uint16_t battery2_nominal_energy_remaining_m0 = 0; // kWh static uint16_t battery2_nominal_full_pack_energy = 600; static uint16_t battery2_nominal_full_pack_energy_m0 = 600; // Kwh //0x132 306 HVBattAmpVolt -static uint16_t battery2_volts = 0; // V -static int16_t battery2_amps = 0; // A -static uint16_t battery2_raw_amps = 0; // A +static uint16_t battery2_volts = 0; // V +static int16_t battery2_amps = 0; // A +static uint16_t battery2_raw_amps = 0; // A static uint16_t battery2_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable static uint16_t BMS2_regenerative_limit = 0; @@ -459,16 +459,16 @@ static uint32_t battery2_packConfigMultiplexer = 0; static uint32_t battery2_moduleType = 0; static uint32_t battery2_reservedConfig = 0; //0x332: 818 BattBrickMinMax:BMS_bmbMinMax -static int16_t battery2_max_temp = 0; // C* -static int16_t battery2_min_temp = 0; // C* +static int16_t battery2_max_temp = 0; // C* +static int16_t battery2_min_temp = 0; // C* static uint16_t battery2_BrickVoltageMax = 0; static uint16_t battery2_BrickVoltageMin = 0; static uint8_t battery2_BrickTempMaxNum = 0; static uint8_t battery2_BrickTempMinNum = 0; static uint8_t battery2_BrickModelTMax = 0; static uint8_t battery2_BrickModelTMin = 0; -static uint8_t battery2_BrickVoltageMaxNum = 0; //rename from battery_max_vno -static uint8_t battery2_BrickVoltageMinNum = 0; //rename from battery_min_vno +static uint8_t battery2_BrickVoltageMaxNum = 0; //rename from battery_max_vno +static uint8_t battery2_BrickVoltageMinNum = 0; //rename from battery_min_vno //0x20A: 522 HVP_contactorState static uint8_t battery2_contactor = 0; //State of contactor static uint8_t battery2_hvil_status = 0; @@ -1783,9 +1783,11 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_energy_buffer_m1 = (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X battery2_expected_energy_remaining_m1 = - (rx_frame.data.u8[5] | rx_frame.data.u8[4]); //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X + (rx_frame.data.u8[5] | + rx_frame.data.u8[4]); //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X battery2_energy_to_charge_complete_m1 = - (rx_frame.data.u8[7] | rx_frame.data.u8[6]); //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + (rx_frame.data.u8[7] | + rx_frame.data.u8[6]); //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X } if (mux == 2) {} // Additional information needed on this mux, example frame: 02 26 02 20 02 80 00 00 doesn't change @@ -1796,7 +1798,7 @@ void receive_can_battery2(CAN_frame rx_frame) { (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh battery2_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | - ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) + ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) battery2_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh battery2_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); @@ -1806,7 +1808,7 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); ((rx_frame.data.u8[7] & 0x01) >> 7); break; - case 0x20A: //522 HVP_contactorState: + case 0x20A: //522 HVP_contactorState: battery2_packContNegativeState = (rx_frame.data.u8[0] & 0x07); battery2_packContPositiveState = (rx_frame.data.u8[0] & 0x38) >> 3; battery2_contactor = (rx_frame.data.u8[1] & 0x0F); @@ -1864,14 +1866,15 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_BMS_diLimpRequest = ((rx_frame.data.u8[4] >> 3) & (0x01U)); battery2_BMS_okToShipByAir = ((rx_frame.data.u8[4] >> 4) & (0x01U)); battery2_BMS_okToShipByLand = ((rx_frame.data.u8[4] >> 5) & (0x01U)); - battery2_BMS_chgPowerAvailable = ((rx_frame.data.u8[6] & (0x01U)) << 10) | ((rx_frame.data.u8[5] & (0xFFU)) << 2) | - ((rx_frame.data.u8[4] >> 6) & (0x03U)); //38|11@1+ (0.125,0) [0|0] "kW" + battery2_BMS_chgPowerAvailable = ((rx_frame.data.u8[6] & (0x01U)) << 10) | + ((rx_frame.data.u8[5] & (0xFFU)) << 2) | + ((rx_frame.data.u8[4] >> 6) & (0x03U)); //38|11@1+ (0.125,0) [0|0] "kW" battery2_BMS_chargeRetryCount = ((rx_frame.data.u8[6] >> 1) & (0x0FU)); battery2_BMS_pcsPwmEnabled = ((rx_frame.data.u8[6] >> 5) & (0x01U)); battery2_BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); battery2_BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC break; - case 0x224: //548 PCS_dcdcStatus: + case 0x224: //548 PCS_dcdcStatus: battery2_PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ; battery2_PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" battery2_PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" @@ -1885,8 +1888,8 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_PCS_dcdcFaulted = ((rx_frame.data.u8[1] >> 7) & (0x01U)); battery2_PCS_dcdcOutputIsLimited = ((rx_frame.data.u8[3] >> 4) & (0x01U)); battery2_PCS_dcdcMaxOutputCurrentAllowed = ((rx_frame.data.u8[5] & (0x01U)) << 11) | - ((rx_frame.data.u8[4] & (0xFFU)) << 3) | - ((rx_frame.data.u8[3] >> 5) & (0x07U)); //29|12@1+ (0.1,0) [0|0] "A" + ((rx_frame.data.u8[4] & (0xFFU)) << 3) | + ((rx_frame.data.u8[3] >> 5) & (0x07U)); //29|12@1+ (0.1,0) [0|0] "A" battery2_PCS_dcdcPrechargeRtyCnt = ((rx_frame.data.u8[5] >> 1) & (0x07U)); battery2_PCS_dcdc12VSupportRtyCnt = ((rx_frame.data.u8[5] >> 4) & (0x0FU)); battery2_PCS_dcdcDischargeRtyCnt = (rx_frame.data.u8[6] & (0x0FU)); @@ -1920,7 +1923,7 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_charge_time_remaining = 0; } break; - case 0x3D2: // total charge/discharge kwh + case 0x3D2: // total charge/discharge kwh battery2_total_discharge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.001; @@ -1968,17 +1971,17 @@ void receive_can_battery2(CAN_frame rx_frame) { BMS2_powerDissipation = ((rx_frame.data.u8[1] & (0x03U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|10@1+ (0.02,0) [0|0] "kW" BMS2_flowRequest = ((rx_frame.data.u8[2] & (0x01U)) << 6) | - ((rx_frame.data.u8[1] >> 2) & (0x3FU)); //10|7@1+ (0.3,0) [0|0] "LPM" + ((rx_frame.data.u8[1] >> 2) & (0x3FU)); //10|7@1+ (0.3,0) [0|0] "LPM" BMS2_inletActiveCoolTargetT = ((rx_frame.data.u8[3] & (0x03U)) << 7) | - ((rx_frame.data.u8[2] >> 1) & (0x7FU)); //17|9@1+ (0.25,-25) [0|0] "DegC" + ((rx_frame.data.u8[2] >> 1) & (0x7FU)); //17|9@1+ (0.25,-25) [0|0] "DegC" BMS2_inletPassiveTargetT = ((rx_frame.data.u8[4] & (0x07U)) << 6) | - ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //26|9@1+ (0.25,-25) [0|0] "DegC" X + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //26|9@1+ (0.25,-25) [0|0] "DegC" X BMS2_inletActiveHeatTargetT = ((rx_frame.data.u8[5] & (0x0FU)) << 5) | - ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|9@1+ (0.25,-25) [0|0] "DegC" + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|9@1+ (0.25,-25) [0|0] "DegC" BMS2_packTMin = ((rx_frame.data.u8[6] & (0x1FU)) << 4) | - ((rx_frame.data.u8[5] >> 4) & (0x0FU)); //44|9@1+ (0.25,-25) [-25|100] "DegC" + ((rx_frame.data.u8[5] >> 4) & (0x0FU)); //44|9@1+ (0.25,-25) [-25|100] "DegC" BMS2_packTMax = ((rx_frame.data.u8[7] & (0x3FU)) << 3) | - ((rx_frame.data.u8[6] >> 5) & (0x07U)); //53|9@1+ (0.25,-25) [-25|100] "DegC" + ((rx_frame.data.u8[6] >> 5) & (0x07U)); //53|9@1+ (0.25,-25) [-25|100] "DegC" BMS2_pcsNoFlowRequest = ((rx_frame.data.u8[7] >> 6) & (0x01U)); // 62|1@1+ (1,0) [0|0] "" BMS2_noFlowRequest = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" break; @@ -1990,7 +1993,7 @@ void receive_can_battery2(CAN_frame rx_frame) { PCS2_chgPhCTemp = ((rx_frame.data.u8[4] & (0x07U)) << 8) | (rx_frame.data.u8[3] & (0xFFU)); //24|11@1- (0.1,40) [0|0] "C" PCS2_dcdcTemp = ((rx_frame.data.u8[5] & (0x3FU)) << 5) | - ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|11@1- (0.1,40) [0|0] "C" + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|11@1- (0.1,40) [0|0] "C" PCS2_ambientTemp = ((rx_frame.data.u8[7] & (0x07U)) << 8) | (rx_frame.data.u8[6] & (0xFFU)); //48|11@1- (0.1,40) [0|0] "C" break; @@ -1999,56 +2002,57 @@ void receive_can_battery2(CAN_frame rx_frame) { //PCS_logMessageSelect = (rx_frame.data.u8[0] & (0x1FU)); //0|5@1+ (1,0) [0|0] "" if (mux == 6) { PCS2_dcdcMaxLvOutputCurrent = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | - ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //m6 : 28|12@1+ (0.1,0) [0|0] "A" X + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //m6 : 28|12@1+ (0.1,0) [0|0] "A" X PCS2_dcdcCurrentLimit = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | - (rx_frame.data.u8[5] & (0xFFU)); //m6 : 40|12@1+ (0.1,0) [0|0] "A" X - PCS2_dcdcLvOutputCurrentTempLimit = ((rx_frame.data.u8[7] & (0xFFU)) << 4) | - ((rx_frame.data.u8[6] >> 4) & (0x0FU)); //m6 : 52|12@1+ (0.1,0) [0|0] "A" X + (rx_frame.data.u8[5] & (0xFFU)); //m6 : 40|12@1+ (0.1,0) [0|0] "A" X + PCS2_dcdcLvOutputCurrentTempLimit = + ((rx_frame.data.u8[7] & (0xFFU)) << 4) | + ((rx_frame.data.u8[6] >> 4) & (0x0FU)); //m6 : 52|12@1+ (0.1,0) [0|0] "A" X } if (mux == 7) { PCS2_dcdcUnifiedCommand = ((rx_frame.data.u8[1] & (0x7FU)) << 3) | - ((rx_frame.data.u8[0] >> 5) & (0x07U)); //m7 : 5|10@1+ (0.001,0) [0|0] "1" X + ((rx_frame.data.u8[0] >> 5) & (0x07U)); //m7 : 5|10@1+ (0.001,0) [0|0] "1" X PCS2_dcdcCLAControllerOutput = ((rx_frame.data.u8[3] & (0x03U)) << 8) | - (rx_frame.data.u8[2] & (0xFFU)); //m7 : 16|10@1+ (0.001,0) [0|0] "1" X + (rx_frame.data.u8[2] & (0xFFU)); //m7 : 16|10@1+ (0.001,0) [0|0] "1" X PCS2_dcdcTankVoltage = ((rx_frame.data.u8[4] & (0x1FU)) << 6) | - ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //m7 : 26|11@1- (1,0) [0|0] "V" X + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //m7 : 26|11@1- (1,0) [0|0] "V" X PCS2_dcdcTankVoltageTarget = ((rx_frame.data.u8[5] & (0x7FU)) << 3) | - ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m7 : 37|10@1+ (1,0) [0|0] "V" X + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m7 : 37|10@1+ (1,0) [0|0] "V" X PCS2_dcdcClaCurrentFreq = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | - (rx_frame.data.u8[6] & (0xFFU)); //P m7 : 48|12@1+ (0.0976563,0) [0|0] "kHz" X + (rx_frame.data.u8[6] & (0xFFU)); //P m7 : 48|12@1+ (0.0976563,0) [0|0] "kHz" X } if (mux == 8) { PCS2_dcdcTCommMeasured = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | - (rx_frame.data.u8[1] & (0xFFU)); // m8 : 8|16@1- (0.00195313,0) [0|0] "us" X + (rx_frame.data.u8[1] & (0xFFU)); // m8 : 8|16@1- (0.00195313,0) [0|0] "us" X PCS2_dcdcShortTimeUs = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | - (rx_frame.data.u8[3] & (0xFFU)); // m8 : 24|16@1+ (0.000488281,0) [0|0] "us" X + (rx_frame.data.u8[3] & (0xFFU)); // m8 : 24|16@1+ (0.000488281,0) [0|0] "us" X PCS2_dcdcHalfPeriodUs = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | - (rx_frame.data.u8[5] & (0xFFU)); // m8 : 40|16@1+ (0.000488281,0) [0|0] "us" X + (rx_frame.data.u8[5] & (0xFFU)); // m8 : 40|16@1+ (0.000488281,0) [0|0] "us" X } if (mux == 18) { PCS2_dcdcIntervalMaxFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | - (rx_frame.data.u8[1] & (0xFFU)); // m18 : 8|12@1+ (1,0) [0|0] "kHz" X + (rx_frame.data.u8[1] & (0xFFU)); // m18 : 8|12@1+ (1,0) [0|0] "kHz" X PCS2_dcdcIntervalMaxHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | - (rx_frame.data.u8[3] & (0xFFU)); //m18 : 24|13@1+ (0.1,0) [0|0] "V" X + (rx_frame.data.u8[3] & (0xFFU)); //m18 : 24|13@1+ (0.1,0) [0|0] "V" X PCS2_dcdcIntervalMaxLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | - ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m18 : 37|9@1+ (0.1,0) [0|0] "V" X + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m18 : 37|9@1+ (0.1,0) [0|0] "V" X PCS2_dcdcIntervalMaxLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | - (rx_frame.data.u8[6] & (0xFFU)); //m18 : 48|12@1+ (1,0) [0|0] "A" X + (rx_frame.data.u8[6] & (0xFFU)); //m18 : 48|12@1+ (1,0) [0|0] "A" X } if (mux == 19) { PCS2_dcdcIntervalMinFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | - (rx_frame.data.u8[1] & (0xFFU)); //m19 : 8|12@1+ (1,0) [0|0] "kHz" X + (rx_frame.data.u8[1] & (0xFFU)); //m19 : 8|12@1+ (1,0) [0|0] "kHz" X PCS2_dcdcIntervalMinHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | - (rx_frame.data.u8[3] & (0xFFU)); //m19 : 24|13@1+ (0.1,0) [0|0] "V" X + (rx_frame.data.u8[3] & (0xFFU)); //m19 : 24|13@1+ (0.1,0) [0|0] "V" X PCS2_dcdcIntervalMinLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | - ((rx_frame.data.u8[4] >> 5) & (0x07U)); //m19 : 37|9@1+ (0.1,0) [0|0] "V" X + ((rx_frame.data.u8[4] >> 5) & (0x07U)); //m19 : 37|9@1+ (0.1,0) [0|0] "V" X PCS2_dcdcIntervalMinLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | - (rx_frame.data.u8[6] & (0xFFU)); // m19 : 48|12@1+ (1,0) [0|0] "A" X + (rx_frame.data.u8[6] & (0xFFU)); // m19 : 48|12@1+ (1,0) [0|0] "A" X } if (mux == 22) { PCS2_dcdc12vSupportLifetimekWh = ((rx_frame.data.u8[3] & (0xFFU)) << 16) | - ((rx_frame.data.u8[2] & (0xFFU)) << 8) | - (rx_frame.data.u8[1] & (0xFFU)); // m22 : 8|24@1+ (0.01,0) [0|0] "kWh" X + ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m22 : 8|24@1+ (0.01,0) [0|0] "kWh" X } break; case 0x401: // Cell stats @@ -2148,11 +2152,11 @@ void receive_can_battery2(CAN_frame rx_frame) { HVP2_gpioHvilEnable = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //: 26|1@1+ (1,0) [0|1] "" Receiver HVP2_gpioSecDrdy = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //: 27|1@1+ (1,0) [0|1] "" Receiver HVP2_hvp1v5Ref = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | - ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|3] "V" Receiver + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|3] "V" Receiver HVP2_shuntCurrentDebug = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | - (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver - HVP2_packCurrentMia = (rx_frame.data.u8[7] & (0x01U)); //: 56|1@1+ (1,0) [0|1] "" Receiver - HVP2_auxCurrentMia = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //: 57|1@1+ (1,0) [0|1] "" Receiver + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP2_packCurrentMia = (rx_frame.data.u8[7] & (0x01U)); //: 56|1@1+ (1,0) [0|1] "" Receiver + HVP2_auxCurrentMia = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //: 57|1@1+ (1,0) [0|1] "" Receiver HVP2_currentSenseMia = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|1@1+ (1,0) [0|1] "" Receiver HVP2_shuntRefVoltageMismatch = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //: 59|1@1+ (1,0) [0|1] "" Receiver HVP2_shuntThermistorMia = ((rx_frame.data.u8[7] >> 4) & (0x01U)); //: 60|1@1+ (1,0) [0|1] "" Receiver @@ -2160,57 +2164,58 @@ void receive_can_battery2(CAN_frame rx_frame) { } if (mux == 1) { HVP2_dcLinkVoltage = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | - (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver HVP2_packVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | - (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver HVP2_fcLinkVoltage = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | - (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver } if (mux == 2) { HVP2_packContVoltage = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | - ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|30] "V" Receiver + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|30] "V" Receiver HVP2_packNegativeV = ((rx_frame.data.u8[3] & (0xFFU)) << 8) | - (rx_frame.data.u8[2] & (0xFFU)); //: 16|16@1- (0.1,0) [-550|550] "V" Receiver + (rx_frame.data.u8[2] & (0xFFU)); //: 16|16@1- (0.1,0) [-550|550] "V" Receiver HVP2_packPositiveV = ((rx_frame.data.u8[5] & (0xFFU)) << 8) | - (rx_frame.data.u8[4] & (0xFFU)); //: 32|16@1- (0.1,0) [-550|550] "V" Receiver + (rx_frame.data.u8[4] & (0xFFU)); //: 32|16@1- (0.1,0) [-550|550] "V" Receiver HVP2_pyroAnalog = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | - (rx_frame.data.u8[6] & (0xFFU)); //: 48|12@1+ (0.1,0) [0|3] "V" Receiver + (rx_frame.data.u8[6] & (0xFFU)); //: 48|12@1+ (0.1,0) [0|3] "V" Receiver } if (mux == 3) { HVP2_dcLinkNegativeV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | - (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver HVP2_dcLinkPositiveV = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | - (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-550|550] "V" Receiver + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-550|550] "V" Receiver HVP2_fcLinkNegativeV = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | - (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-550|550] "V" Receiver + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-550|550] "V" Receiver } if (mux == 4) { HVP2_fcContCoilCurrent = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | - ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|7.5] "A" Receiver + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|7.5] "A" Receiver HVP2_fcContVoltage = ((rx_frame.data.u8[3] & (0x0FU)) << 8) | - (rx_frame.data.u8[2] & (0xFFU)); //: 16|12@1+ (0.1,0) [0|30] "V" Receiver + (rx_frame.data.u8[2] & (0xFFU)); //: 16|12@1+ (0.1,0) [0|30] "V" Receiver HVP2_hvilInVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | - ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|30] "V" Receiver + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|30] "V" Receiver HVP2_hvilOutVoltage = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | - (rx_frame.data.u8[5] & (0xFFU)); //: 40|12@1+ (0.1,0) [0|30] "V" Receiver + (rx_frame.data.u8[5] & (0xFFU)); //: 40|12@1+ (0.1,0) [0|30] "V" Receiver } if (mux == 5) { HVP2_fcLinkPositiveV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | - (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver HVP2_packContCoilCurrent = ((rx_frame.data.u8[4] & (0x0FU)) << 8) | - (rx_frame.data.u8[3] & (0xFFU)); //: 24|12@1+ (0.1,0) [0|7.5] "A" Receiver + (rx_frame.data.u8[3] & (0xFFU)); //: 24|12@1+ (0.1,0) [0|7.5] "A" Receiver HVP2_battery12V = ((rx_frame.data.u8[5] & (0xFFU)) << 4) | - ((rx_frame.data.u8[4] >> 4) & (0x0FU)); //: 36|12@1+ (0.1,0) [0|30] "V" Receiver - HVP2_shuntRefVoltageDbg = ((rx_frame.data.u8[7] & (0xFFU)) << 8) | - (rx_frame.data.u8[6] & (0xFFU)); //: 48|16@1- (0.001,0) [-32.768|32.767] "V" Receiver + ((rx_frame.data.u8[4] >> 4) & (0x0FU)); //: 36|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_shuntRefVoltageDbg = + ((rx_frame.data.u8[7] & (0xFFU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|16@1- (0.001,0) [-32.768|32.767] "V" Receiver } if (mux == 6) { HVP2_shuntAuxCurrentDbg = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | - (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver HVP2_shuntBarTempDbg = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | - (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.01,0) [-327.67|327.67] "C" Receiver HVP2_shuntAsicTempDbg = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | - (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.01,0) [-327.67|327.67] "C" Receiver HVP2_shuntAuxCurrentStatus = (rx_frame.data.u8[7] & (0x03U)); //: 56|2@1+ (1,0) [0|3] "" Receiver HVP2_shuntBarTempStatus = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|2@1+ (1,0) [0|3] "" Receiver HVP2_shuntAsicTempStatus = ((rx_frame.data.u8[7] >> 4) & (0x03U)); //: 60|2@1+ (1,0) [0|3] "" Receiver @@ -2273,7 +2278,7 @@ void receive_can_battery2(CAN_frame rx_frame) { mux = (rx_frame.data.u8[0] & (0x0F)); if (mux == 0) ; - { //mux0 + { //mux0 battery2_BMS_matrixIndex = (rx_frame.data.u8[0] & (0x0F)); // 0|4@1+ (1,0) [0|0] "" X battery2_BMS_a017_SW_Brick_OV = ((rx_frame.data.u8[2] >> 4) & (0x01)); //20|1@1+ (1,0) [0|0] "" X battery2_BMS_a018_SW_Brick_UV = ((rx_frame.data.u8[2] >> 5) & (0x01)); //21|1@1+ (1,0) [0|0] "" X @@ -2305,7 +2310,7 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_BMS_a059_SW_Pack_Voltage_Sensing = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X battery2_BMS_a060_SW_Leakage_Test_Failure = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X } - if (mux == 1) { //mux1 + if (mux == 1) { //mux1 battery2_BMS_a061_robinBrickOverVoltage = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //4|1@1+ (1,0) [0|0] "" X battery2_BMS_a062_SW_BrickV_Imbalance = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X battery2_BMS_a063_SW_ChargePort_Fault = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X @@ -2331,7 +2336,7 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_BMS_a106_SW_All_Module_Tsense = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X battery2_BMS_a107_SW_Stack_Voltage_MIA = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X } - if (mux == 2) { //mux2 + if (mux == 2) { //mux2 battery2_BMS_a121_SW_NVRAM_Config_Error = ((rx_frame.data.u8[0] >> 4) & (0x01U)); // 4|1@1+ (1,0) [0|0] "" X battery2_BMS_a122_SW_BMS_Therm_Irrational = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X battery2_BMS_a123_SW_Internal_Isolation = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X From bdc617c0dec916675669d488ef0800f1acae9133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 19 Dec 2024 19:48:27 +0200 Subject: [PATCH 077/225] Replace AsyncTCP library --- .../lib/mathieucarbou-AsyncTCP/.clang-format | 22 + .../mathieucarbou-AsyncTCP/.clang-format copy | 22 + .../src/lib/mathieucarbou-AsyncTCP/.gitignore | 6 + .../mathieucarbou-AsyncTCP/.gitpod.Dockerfile | 2 + .../lib/mathieucarbou-AsyncTCP/.gitpod.yml | 9 + .../CMakeLists.txt | 0 .../mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md | 129 ++ .../Kconfig.projbuild | 0 .../LICENSE | 0 .../src/lib/mathieucarbou-AsyncTCP/README.md | 62 + .../arduino-cli-dev.yaml | 25 + .../mathieucarbou-AsyncTCP/arduino-cli.yaml | 25 + .../component.mk | 0 .../lib/mathieucarbou-AsyncTCP/library.json | 38 + .../mathieucarbou-AsyncTCP/library.properties | 10 + .../lib/mathieucarbou-AsyncTCP/platformio.ini | 43 + .../mathieucarbou-AsyncTCP/src/AsyncTCP.cpp | 1661 +++++++++++++++++ .../lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h | 347 ++++ .../src/lib/me-no-dev-AsyncTCP/.gitignore | 2 - .../src/lib/me-no-dev-AsyncTCP/.travis.yml | 34 - Software/src/lib/me-no-dev-AsyncTCP/README.md | 15 - .../src/lib/me-no-dev-AsyncTCP/library.json | 22 - .../lib/me-no-dev-AsyncTCP/library.properties | 9 - .../lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp | 1357 -------------- .../src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h | 220 --- 25 files changed, 2401 insertions(+), 1659 deletions(-) create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.clang-format create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.clang-format copy create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.gitignore create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.Dockerfile create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.yml rename Software/src/lib/{me-no-dev-AsyncTCP => mathieucarbou-AsyncTCP}/CMakeLists.txt (100%) create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md rename Software/src/lib/{me-no-dev-AsyncTCP => mathieucarbou-AsyncTCP}/Kconfig.projbuild (100%) rename Software/src/lib/{me-no-dev-AsyncTCP => mathieucarbou-AsyncTCP}/LICENSE (100%) create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/README.md create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli-dev.yaml create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli.yaml rename Software/src/lib/{me-no-dev-AsyncTCP => mathieucarbou-AsyncTCP}/component.mk (100%) create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/library.json create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/library.properties create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp create mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h delete mode 100644 Software/src/lib/me-no-dev-AsyncTCP/.gitignore delete mode 100644 Software/src/lib/me-no-dev-AsyncTCP/.travis.yml delete mode 100644 Software/src/lib/me-no-dev-AsyncTCP/README.md delete mode 100644 Software/src/lib/me-no-dev-AsyncTCP/library.json delete mode 100644 Software/src/lib/me-no-dev-AsyncTCP/library.properties delete mode 100644 Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp delete mode 100644 Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format b/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format new file mode 100644 index 000000000..63f29c0be --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format @@ -0,0 +1,22 @@ +Language: Cpp +BasedOnStyle: LLVM + +AccessModifierOffset: -2 +AlignConsecutiveMacros: true +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLambdasOnASingleLine: Inline +BinPackArguments: false +ColumnLimit: 0 +ContinuationIndentWidth: 2 +FixNamespaceComments: false +IndentAccessModifiers: true +IndentCaseLabels: true +IndentPPDirectives: BeforeHash +IndentWidth: 2 +NamespaceIndentation: All +PointerAlignment: Left +ReferenceAlignment: Left +TabWidth: 2 +UseTab: Never diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format copy b/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format copy new file mode 100644 index 000000000..63f29c0be --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format copy @@ -0,0 +1,22 @@ +Language: Cpp +BasedOnStyle: LLVM + +AccessModifierOffset: -2 +AlignConsecutiveMacros: true +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLambdasOnASingleLine: Inline +BinPackArguments: false +ColumnLimit: 0 +ContinuationIndentWidth: 2 +FixNamespaceComments: false +IndentAccessModifiers: true +IndentCaseLabels: true +IndentPPDirectives: BeforeHash +IndentWidth: 2 +NamespaceIndentation: All +PointerAlignment: Left +ReferenceAlignment: Left +TabWidth: 2 +UseTab: Never diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.gitignore b/Software/src/lib/mathieucarbou-AsyncTCP/.gitignore new file mode 100644 index 000000000..18584e8ec --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +.lh +/.pio +/.vscode + +/logs diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.Dockerfile b/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.Dockerfile new file mode 100644 index 000000000..29eeb4357 --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.Dockerfile @@ -0,0 +1,2 @@ +FROM gitpod/workspace-python-3.11 +USER gitpod diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.yml b/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.yml new file mode 100644 index 000000000..2f8a4431c --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.yml @@ -0,0 +1,9 @@ +tasks: + - command: pip install --upgrade pip && pip install -U platformio && platformio run + +image: + file: .gitpod.Dockerfile + +vscode: + extensions: + - shardulm94.trailing-spaces diff --git a/Software/src/lib/me-no-dev-AsyncTCP/CMakeLists.txt b/Software/src/lib/mathieucarbou-AsyncTCP/CMakeLists.txt similarity index 100% rename from Software/src/lib/me-no-dev-AsyncTCP/CMakeLists.txt rename to Software/src/lib/mathieucarbou-AsyncTCP/CMakeLists.txt diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md b/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..0a5f91417 --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md @@ -0,0 +1,129 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +https://sidweb.nl/cms3/en/contact. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild b/Software/src/lib/mathieucarbou-AsyncTCP/Kconfig.projbuild similarity index 100% rename from Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild rename to Software/src/lib/mathieucarbou-AsyncTCP/Kconfig.projbuild diff --git a/Software/src/lib/me-no-dev-AsyncTCP/LICENSE b/Software/src/lib/mathieucarbou-AsyncTCP/LICENSE similarity index 100% rename from Software/src/lib/me-no-dev-AsyncTCP/LICENSE rename to Software/src/lib/mathieucarbou-AsyncTCP/LICENSE diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/README.md b/Software/src/lib/mathieucarbou-AsyncTCP/README.md new file mode 100644 index 000000000..d90814a1d --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/README.md @@ -0,0 +1,62 @@ +# AsyncTCP + +[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/) +[![Continuous Integration](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml) +[![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/AsyncTCP.svg)](https://registry.platformio.org/libraries/mathieucarbou/AsyncTCP) + +A fork of the [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) library by [@me-no-dev](https://github.com/me-no-dev). + +### Async TCP Library for ESP32 Arduino + +This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs. + +This library is the base for [ESPAsyncWebServer](https://github.com/mathieucarbou/ESPAsyncWebServer) + +## AsyncClient and AsyncServer + +The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. + +## Changes in this fork + +- Based on [ESPHome fork](https://github.com/esphome/AsyncTCP) + +- `library.properties` for Arduino IDE users +- Add `CONFIG_ASYNC_TCP_MAX_ACK_TIME` +- Add `CONFIG_ASYNC_TCP_PRIORITY` +- Add `CONFIG_ASYNC_TCP_QUEUE_SIZE` +- Add `setKeepAlive()` +- Arduino 3 / ESP-IDF 5 compatibility +- Better CI +- Better example +- Customizable macros +- Fix for "Required to lock TCPIP core functionality". Ref: https://github.com/mathieucarbou/AsyncTCP/issues/27 and https://github.com/espressif/arduino-esp32/issues/10526 +- Fix for "ack timeout 4" client disconnects. +- Fix from https://github.com/me-no-dev/AsyncTCP/pull/173 (partially applied) +- Fix from https://github.com/me-no-dev/AsyncTCP/pull/184 +- IPv6 +- LIBRETINY support +- LibreTuya +- Reduce logging of non critical messages +- Use IPADDR6_INIT() macro to set connecting IPv6 address +- xTaskCreateUniversal function + +## Coordinates + +``` +mathieucarbou/AsyncTCP @ ^3.3.1 +``` + +## Important recommendations + +Most of the crashes are caused by improper configuration of the library for the project. +Here are some recommendations to avoid them. + +I personally use the following configuration in my projects: + +```c++ + -D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 // (keep default) + -D CONFIG_ASYNC_TCP_PRIORITY=10 // (keep default) + -D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 // (keep default) + -D CONFIG_ASYNC_TCP_RUNNING_CORE=1 // force async_tcp task to be on same core as the app (default is core 0) + -D CONFIG_ASYNC_TCP_STACK_SIZE=4096 // reduce the stack size (default is 16K) +``` diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli-dev.yaml b/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli-dev.yaml new file mode 100644 index 000000000..174df7a13 --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli-dev.yaml @@ -0,0 +1,25 @@ +board_manager: + additional_urls: + - https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json +directories: + builtin.libraries: ./src/ +build_cache: + compilations_before_purge: 10 + ttl: 720h0m0s +daemon: + port: "50051" +library: + enable_unsafe_install: false +logging: + file: "" + format: text + level: info +metrics: + addr: :9090 + enabled: true +output: + no_color: false +sketch: + always_export_binaries: false +updater: + enable_notification: true diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli.yaml b/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli.yaml new file mode 100644 index 000000000..42365f42c --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli.yaml @@ -0,0 +1,25 @@ +board_manager: + additional_urls: + - https://espressif.github.io/arduino-esp32/package_esp32_index.json +directories: + builtin.libraries: ./src/ +build_cache: + compilations_before_purge: 10 + ttl: 720h0m0s +daemon: + port: "50051" +library: + enable_unsafe_install: false +logging: + file: "" + format: text + level: info +metrics: + addr: :9090 + enabled: true +output: + no_color: false +sketch: + always_export_binaries: false +updater: + enable_notification: true diff --git a/Software/src/lib/me-no-dev-AsyncTCP/component.mk b/Software/src/lib/mathieucarbou-AsyncTCP/component.mk similarity index 100% rename from Software/src/lib/me-no-dev-AsyncTCP/component.mk rename to Software/src/lib/mathieucarbou-AsyncTCP/component.mk diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/library.json b/Software/src/lib/mathieucarbou-AsyncTCP/library.json new file mode 100644 index 000000000..5d6e228b4 --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/library.json @@ -0,0 +1,38 @@ +{ + "name": "AsyncTCP", + "version": "3.3.1", + "description": "Asynchronous TCP Library for ESP32", + "keywords": "async,tcp", + "repository": { + "type": "git", + "url": "https://github.com/mathieucarbou/AsyncTCP.git" + }, + "authors": [ + { + "name": "Hristo Gochkov" + }, + { + "name": "Mathieu Carbou", + "maintainer": true + } + ], + "license": "LGPL-3.0", + "frameworks": "arduino", + "platforms": [ + "espressif32", + "libretiny" + ], + "build": { + "libCompatMode": 2 + }, + "export": { + "include": [ + "examples", + "src", + "library.json", + "library.properties", + "LICENSE", + "README.md" + ] + } +} \ No newline at end of file diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/library.properties b/Software/src/lib/mathieucarbou-AsyncTCP/library.properties new file mode 100644 index 000000000..dd945f8de --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/library.properties @@ -0,0 +1,10 @@ +name=Async TCP +includes=AsyncTCP.h +version=3.3.1 +author=Me-No-Dev +maintainer=Mathieu Carbou +sentence=Async TCP Library for ESP32 +paragraph=Async TCP Library for ESP32 +category=Other +url=https://github.com/mathieucarbou/AsyncTCP.git +architectures=* diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini b/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini new file mode 100644 index 000000000..ec65a3674 --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini @@ -0,0 +1,43 @@ +[platformio] +default_envs = arduino-2, arduino-3, arduino-310 +lib_dir = . +src_dir = examples/Client + +[env] +framework = arduino +build_flags = + -Wall -Wextra + -D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 + -D CONFIG_ASYNC_TCP_PRIORITY=10 + -D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 + -D CONFIG_ASYNC_TCP_RUNNING_CORE=1 + -D CONFIG_ASYNC_TCP_STACK_SIZE=4096 + -D CONFIG_ARDUHAL_LOG_COLORS + -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG +upload_protocol = esptool +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder, log2file +board = esp32dev + +[env:arduino-2] +platform = espressif32@6.9.0 + +[env:arduino-3] +platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip + +[env:arduino-310] +platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip + +; CI + +[env:ci-arduino-2] +platform = espressif32@6.9.0 +board = ${sysenv.PIO_BOARD} + +[env:ci-arduino-3] +platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip +board = ${sysenv.PIO_BOARD} + +[env:ci-arduino-310] +platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip +board = ${sysenv.PIO_BOARD} diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp b/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp new file mode 100644 index 000000000..9addb135e --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp @@ -0,0 +1,1661 @@ +/* + Asynchronous TCP library for Espressif MCUs + + Copyright (c) 2016 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "Arduino.h" + +#include "AsyncTCP.h" + +extern "C" { +#include "lwip/dns.h" +#include "lwip/err.h" +#include "lwip/inet.h" +#include "lwip/opt.h" +#include "lwip/tcp.h" +} + +#if CONFIG_ASYNC_TCP_USE_WDT + #include "esp_task_wdt.h" +#endif + +// Required for: +// https://github.com/espressif/arduino-esp32/blob/3.0.3/libraries/Network/src/NetworkInterface.cpp#L37-L47 +#if ESP_IDF_VERSION_MAJOR >= 5 + #include +#endif + +#define TAG "AsyncTCP" + +// https://github.com/espressif/arduino-esp32/issues/10526 +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING + #define TCP_MUTEX_LOCK() \ + if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ + LOCK_TCPIP_CORE(); \ + } + + #define TCP_MUTEX_UNLOCK() \ + if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ + UNLOCK_TCPIP_CORE(); \ + } +#else // CONFIG_LWIP_TCPIP_CORE_LOCKING + #define TCP_MUTEX_LOCK() + #define TCP_MUTEX_UNLOCK() +#endif // CONFIG_LWIP_TCPIP_CORE_LOCKING + +#define INVALID_CLOSED_SLOT -1 + +/* + TCP poll interval is specified in terms of the TCP coarse timer interval, which is called twice a second + https://github.com/espressif/esp-lwip/blob/2acf959a2bb559313cd2bf9306c24612ba3d0e19/src/core/tcp.c#L1895 +*/ +#define CONFIG_ASYNC_TCP_POLL_TIMER 1 + +/* + * TCP/IP Event Task + * */ + +typedef enum { + LWIP_TCP_SENT, + LWIP_TCP_RECV, + LWIP_TCP_FIN, + LWIP_TCP_ERROR, + LWIP_TCP_POLL, + LWIP_TCP_CLEAR, + LWIP_TCP_ACCEPT, + LWIP_TCP_CONNECTED, + LWIP_TCP_DNS +} lwip_event_t; + +typedef struct { + lwip_event_t event; + void* arg; + union { + struct { + tcp_pcb* pcb; + int8_t err; + } connected; + struct { + int8_t err; + } error; + struct { + tcp_pcb* pcb; + uint16_t len; + } sent; + struct { + tcp_pcb* pcb; + pbuf* pb; + int8_t err; + } recv; + struct { + tcp_pcb* pcb; + int8_t err; + } fin; + struct { + tcp_pcb* pcb; + } poll; + struct { + AsyncClient* client; + } accept; + struct { + const char* name; + ip_addr_t addr; + } dns; + }; +} lwip_event_packet_t; + +static QueueHandle_t _async_queue; +static TaskHandle_t _async_service_task_handle = NULL; + +SemaphoreHandle_t _slots_lock; +const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP; +static uint32_t _closed_slots[_number_of_closed_slots]; +static uint32_t _closed_index = []() { + _slots_lock = xSemaphoreCreateBinary(); + xSemaphoreGive(_slots_lock); + for (int i = 0; i < _number_of_closed_slots; ++i) { + _closed_slots[i] = 1; + } + return 1; +}(); + +static inline bool _init_async_event_queue() { + if (!_async_queue) { + _async_queue = xQueueCreate(CONFIG_ASYNC_TCP_QUEUE_SIZE, sizeof(lwip_event_packet_t*)); + if (!_async_queue) { + return false; + } + } + return true; +} + +static inline bool _send_async_event(lwip_event_packet_t** e, TickType_t wait = portMAX_DELAY) { + return _async_queue && xQueueSend(_async_queue, e, wait) == pdPASS; +} + +static inline bool _prepend_async_event(lwip_event_packet_t** e, TickType_t wait = portMAX_DELAY) { + return _async_queue && xQueueSendToFront(_async_queue, e, wait) == pdPASS; +} + +static inline bool _get_async_event(lwip_event_packet_t** e) { + if (!_async_queue) { + return false; + } + +#if CONFIG_ASYNC_TCP_USE_WDT + // need to return periodically to feed the dog + if (xQueueReceive(_async_queue, e, pdMS_TO_TICKS(1000)) != pdPASS) + return false; +#else + if (xQueueReceive(_async_queue, e, portMAX_DELAY) != pdPASS) + return false; +#endif + + if ((*e)->event != LWIP_TCP_POLL) + return true; + + /* + Let's try to coalesce two (or more) consecutive poll events into one + this usually happens with poor implemented user-callbacks that are runs too long and makes poll events to stack in the queue + if consecutive user callback for a same connection runs longer that poll time then it will fill the queue with events until it deadlocks. + This is a workaround to mitigate such poor designs and won't let other events/connections to starve the task time. + It won't be effective if user would run multiple simultaneous long running callbacks due to message interleaving. + todo: implement some kind of fair dequeing or (better) simply punish user for a bad designed callbacks by resetting hog connections + */ + lwip_event_packet_t* next_pkt = NULL; + while (xQueuePeek(_async_queue, &next_pkt, 0) == pdPASS) { + if (next_pkt->arg == (*e)->arg && next_pkt->event == LWIP_TCP_POLL) { + if (xQueueReceive(_async_queue, &next_pkt, 0) == pdPASS) { + free(next_pkt); + next_pkt = NULL; + log_d("coalescing polls, network congestion or async callbacks might be too slow!"); + continue; + } + } + + // quit while loop if next event can't be discarded + break; + } + + /* + now we have to decide if to proceed with poll callback handler or discard it? + poor designed apps using asynctcp without proper dataflow control could flood the queue with interleaved pool/ack events. + I.e. on each poll app would try to generate more data to send, which in turn results in additional ack event triggering chain effect + for long connections. Or poll callback could take long time starving other connections. Anyway our goal is to keep the queue length + grows under control (if possible) and poll events are the safest to discard. + Let's discard poll events processing using linear-increasing probability curve when queue size grows over 3/4 + Poll events are periodic and connection could get another chance next time + */ + if (uxQueueMessagesWaiting(_async_queue) > (rand() % CONFIG_ASYNC_TCP_QUEUE_SIZE / 4 + CONFIG_ASYNC_TCP_QUEUE_SIZE * 3 / 4)) { + free(*e); + *e = NULL; + log_d("discarding poll due to queue congestion"); + // evict next event from a queue + return _get_async_event(e); + } + + // last resort return + return true; +} + +static bool _remove_events_with_arg(void* arg) { + if (!_async_queue) { + return false; + } + + lwip_event_packet_t* first_packet = NULL; + lwip_event_packet_t* packet = NULL; + + // figure out which is the first non-matching packet so we can keep the order + while (!first_packet) { + if (xQueueReceive(_async_queue, &first_packet, 0) != pdPASS) { + return false; + } + // discard packet if matching + if ((int)first_packet->arg == (int)arg) { + free(first_packet); + first_packet = NULL; + } else if (xQueueSend(_async_queue, &first_packet, 0) != pdPASS) { + // try to return first packet to the back of the queue + // we can't wait here if queue is full, because this call has been done from the only consumer task of this queue + // otherwise it would deadlock, we have to discard the event + free(first_packet); + first_packet = NULL; + return false; + } + } + + while (xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet) { + if (xQueueReceive(_async_queue, &packet, 0) != pdPASS) { + return false; + } + if ((int)packet->arg == (int)arg) { + // remove matching event + free(packet); + packet = NULL; + // otherwise try to requeue it + } else if (xQueueSend(_async_queue, &packet, 0) != pdPASS) { + // we can't wait here if queue is full, because this call has been done from the only consumer task of this queue + // otherwise it would deadlock, we have to discard the event + free(packet); + packet = NULL; + return false; + } + } + return true; +} + +static void _handle_async_event(lwip_event_packet_t* e) { + if (e->arg == NULL) { + // do nothing when arg is NULL + // ets_printf("event arg == NULL: 0x%08x\n", e->recv.pcb); + } else if (e->event == LWIP_TCP_CLEAR) { + _remove_events_with_arg(e->arg); + } else if (e->event == LWIP_TCP_RECV) { + // ets_printf("-R: 0x%08x\n", e->recv.pcb); + AsyncClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err); + } else if (e->event == LWIP_TCP_FIN) { + // ets_printf("-F: 0x%08x\n", e->fin.pcb); + AsyncClient::_s_fin(e->arg, e->fin.pcb, e->fin.err); + } else if (e->event == LWIP_TCP_SENT) { + // ets_printf("-S: 0x%08x\n", e->sent.pcb); + AsyncClient::_s_sent(e->arg, e->sent.pcb, e->sent.len); + } else if (e->event == LWIP_TCP_POLL) { + // ets_printf("-P: 0x%08x\n", e->poll.pcb); + AsyncClient::_s_poll(e->arg, e->poll.pcb); + } else if (e->event == LWIP_TCP_ERROR) { + // ets_printf("-E: 0x%08x %d\n", e->arg, e->error.err); + AsyncClient::_s_error(e->arg, e->error.err); + } else if (e->event == LWIP_TCP_CONNECTED) { + // ets_printf("C: 0x%08x 0x%08x %d\n", e->arg, e->connected.pcb, e->connected.err); + AsyncClient::_s_connected(e->arg, e->connected.pcb, e->connected.err); + } else if (e->event == LWIP_TCP_ACCEPT) { + // ets_printf("A: 0x%08x 0x%08x\n", e->arg, e->accept.client); + AsyncServer::_s_accepted(e->arg, e->accept.client); + } else if (e->event == LWIP_TCP_DNS) { + // ets_printf("D: 0x%08x %s = %s\n", e->arg, e->dns.name, ipaddr_ntoa(&e->dns.addr)); + AsyncClient::_s_dns_found(e->dns.name, &e->dns.addr, e->arg); + } + free((void*)(e)); +} + +static void _async_service_task(void* pvParameters) { +#if CONFIG_ASYNC_TCP_USE_WDT + if (esp_task_wdt_add(NULL) != ESP_OK) { + log_w("Failed to add async task to WDT"); + } +#endif + lwip_event_packet_t* packet = NULL; + for (;;) { + if (_get_async_event(&packet)) { + _handle_async_event(packet); + } +#if CONFIG_ASYNC_TCP_USE_WDT + esp_task_wdt_reset(); +#endif + } +#if CONFIG_ASYNC_TCP_USE_WDT + esp_task_wdt_delete(NULL); +#endif + vTaskDelete(NULL); + _async_service_task_handle = NULL; +} +/* +static void _stop_async_task(){ + if(_async_service_task_handle){ + vTaskDelete(_async_service_task_handle); + _async_service_task_handle = NULL; + } +} +*/ + +static bool customTaskCreateUniversal( + TaskFunction_t pxTaskCode, + const char* const pcName, + const uint32_t usStackDepth, + void* const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t* const pxCreatedTask, + const BaseType_t xCoreID) { +#ifndef CONFIG_FREERTOS_UNICORE + if (xCoreID >= 0 && xCoreID < 2) { + return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID); + } else { +#endif + return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask); +#ifndef CONFIG_FREERTOS_UNICORE + } +#endif +} + +static bool _start_async_task() { + if (!_init_async_event_queue()) { + return false; + } + if (!_async_service_task_handle) { + customTaskCreateUniversal(_async_service_task, "async_tcp", CONFIG_ASYNC_TCP_STACK_SIZE, NULL, TASK_CONNECTIVITY_PRIO, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); + if (!_async_service_task_handle) { + return false; + } + } + return true; +} + +/* + * LwIP Callbacks + * */ + +static int8_t _tcp_clear_events(void* arg) { + lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_CLEAR; + e->arg = arg; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_connected(void* arg, tcp_pcb* pcb, int8_t err) { + // ets_printf("+C: 0x%08x\n", pcb); + lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_CONNECTED; + e->arg = arg; + e->connected.pcb = pcb; + e->connected.err = err; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_poll(void* arg, struct tcp_pcb* pcb) { + // throttle polling events queing when event queue is getting filled up, let it handle _onack's + // log_d("qs:%u", uxQueueMessagesWaiting(_async_queue)); + if (uxQueueMessagesWaiting(_async_queue) > (rand() % CONFIG_ASYNC_TCP_QUEUE_SIZE / 2 + CONFIG_ASYNC_TCP_QUEUE_SIZE / 4)) { + log_d("throttling"); + return ERR_OK; + } + + // ets_printf("+P: 0x%08x\n", pcb); + lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_POLL; + e->arg = arg; + e->poll.pcb = pcb; + // poll events are not critical 'cause those are repetitive, so we may not wait the queue in any case + if (!_send_async_event(&e, 0)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* pb, int8_t err) { + lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); + e->arg = arg; + if (pb) { + // ets_printf("+R: 0x%08x\n", pcb); + e->event = LWIP_TCP_RECV; + e->recv.pcb = pcb; + e->recv.pb = pb; + e->recv.err = err; + } else { + // ets_printf("+F: 0x%08x\n", pcb); + e->event = LWIP_TCP_FIN; + e->fin.pcb = pcb; + e->fin.err = err; + // close the PCB in LwIP thread + AsyncClient::_s_lwip_fin(e->arg, e->fin.pcb, e->fin.err); + } + if (!_send_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_sent(void* arg, struct tcp_pcb* pcb, uint16_t len) { + // ets_printf("+S: 0x%08x\n", pcb); + lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_SENT; + e->arg = arg; + e->sent.pcb = pcb; + e->sent.len = len; + if (!_send_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static void _tcp_error(void* arg, int8_t err) { + // ets_printf("+E: 0x%08x\n", arg); + lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_ERROR; + e->arg = arg; + e->error.err = err; + if (!_send_async_event(&e)) { + free((void*)(e)); + } +} + +static void _tcp_dns_found(const char* name, struct ip_addr* ipaddr, void* arg) { + lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); + // ets_printf("+DNS: name=%s ipaddr=0x%08x arg=%x\n", name, ipaddr, arg); + e->event = LWIP_TCP_DNS; + e->arg = arg; + e->dns.name = name; + if (ipaddr) { + memcpy(&e->dns.addr, ipaddr, sizeof(struct ip_addr)); + } else { + memset(&e->dns.addr, 0, sizeof(e->dns.addr)); + } + if (!_send_async_event(&e)) { + free((void*)(e)); + } +} + +// Used to switch out from LwIP thread +static int8_t _tcp_accept(void* arg, AsyncClient* client) { + lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_ACCEPT; + e->arg = arg; + e->accept.client = client; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +/* + * TCP/IP API Calls + * */ + +#include "lwip/priv/tcpip_priv.h" + +typedef struct { + struct tcpip_api_call_data call; + tcp_pcb* pcb; + int8_t closed_slot; + int8_t err; + union { + struct { + const char* data; + size_t size; + uint8_t apiflags; + } write; + size_t received; + struct { + ip_addr_t* addr; + uint16_t port; + tcp_connected_fn cb; + } connect; + struct { + ip_addr_t* addr; + uint16_t port; + } bind; + uint8_t backlog; + }; +} tcp_api_call_t; + +static err_t _tcp_output_api(struct tcpip_api_call_data* api_call_msg) { + tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; + msg->err = ERR_CONN; + if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_output(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_output(tcp_pcb* pcb, int8_t closed_slot) { + if (!pcb) { + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_write_api(struct tcpip_api_call_data* api_call_msg) { + tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; + msg->err = ERR_CONN; + if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); + } + return msg->err; +} + +static esp_err_t _tcp_write(tcp_pcb* pcb, int8_t closed_slot, const char* data, size_t size, uint8_t apiflags) { + if (!pcb) { + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.write.data = data; + msg.write.size = size; + msg.write.apiflags = apiflags; + tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_recved_api(struct tcpip_api_call_data* api_call_msg) { + tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; + msg->err = ERR_CONN; + if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { + // if(msg->closed_slot != INVALID_CLOSED_SLOT && !_closed_slots[msg->closed_slot]) { + // if(msg->closed_slot != INVALID_CLOSED_SLOT) { + msg->err = 0; + tcp_recved(msg->pcb, msg->received); + } + return msg->err; +} + +static esp_err_t _tcp_recved(tcp_pcb* pcb, int8_t closed_slot, size_t len) { + if (!pcb) { + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.received = len; + tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_close_api(struct tcpip_api_call_data* api_call_msg) { + tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; + msg->err = ERR_CONN; + if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_close(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_close(tcp_pcb* pcb, int8_t closed_slot) { + if (!pcb) { + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_abort_api(struct tcpip_api_call_data* api_call_msg) { + tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; + msg->err = ERR_CONN; + if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { + tcp_abort(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_abort(tcp_pcb* pcb, int8_t closed_slot) { + if (!pcb) { + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_connect_api(struct tcpip_api_call_data* api_call_msg) { + tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; + msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); + return msg->err; +} + +static esp_err_t _tcp_connect(tcp_pcb* pcb, int8_t closed_slot, ip_addr_t* addr, uint16_t port, tcp_connected_fn cb) { + if (!pcb) { + return ESP_FAIL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.connect.addr = addr; + msg.connect.port = port; + msg.connect.cb = cb; + tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_bind_api(struct tcpip_api_call_data* api_call_msg) { + tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; + msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); + return msg->err; +} + +static esp_err_t _tcp_bind(tcp_pcb* pcb, ip_addr_t* addr, uint16_t port) { + if (!pcb) { + return ESP_FAIL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = -1; + msg.bind.addr = addr; + msg.bind.port = port; + tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_listen_api(struct tcpip_api_call_data* api_call_msg) { + tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; + msg->err = 0; + msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); + return msg->err; +} + +static tcp_pcb* _tcp_listen_with_backlog(tcp_pcb* pcb, uint8_t backlog) { + if (!pcb) { + return NULL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = -1; + msg.backlog = backlog ? backlog : 0xFF; + tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); + return msg.pcb; +} + +/* + Async TCP Client + */ + +AsyncClient::AsyncClient(tcp_pcb* pcb) + : _connect_cb(0), _connect_cb_arg(0), _discard_cb(0), _discard_cb_arg(0), _sent_cb(0), _sent_cb_arg(0), _error_cb(0), _error_cb_arg(0), _recv_cb(0), _recv_cb_arg(0), _pb_cb(0), _pb_cb_arg(0), _timeout_cb(0), _timeout_cb_arg(0), _ack_pcb(true), _tx_last_packet(0), _rx_timeout(0), _rx_last_ack(0), _ack_timeout(CONFIG_ASYNC_TCP_MAX_ACK_TIME), _connect_port(0), prev(NULL), next(NULL) { + _pcb = pcb; + _closed_slot = INVALID_CLOSED_SLOT; + if (_pcb) { + _rx_last_packet = millis(); + tcp_arg(_pcb, this); + tcp_recv(_pcb, &_tcp_recv); + tcp_sent(_pcb, &_tcp_sent); + tcp_err(_pcb, &_tcp_error); + tcp_poll(_pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); + if (!_allocate_closed_slot()) { + _close(); + } + } +} + +AsyncClient::~AsyncClient() { + if (_pcb) { + _close(); + } + _free_closed_slot(); +} + +/* + * Operators + * */ + +AsyncClient& AsyncClient::operator=(const AsyncClient& other) { + if (_pcb) { + _close(); + } + + _pcb = other._pcb; + _closed_slot = other._closed_slot; + if (_pcb) { + _rx_last_packet = millis(); + tcp_arg(_pcb, this); + tcp_recv(_pcb, &_tcp_recv); + tcp_sent(_pcb, &_tcp_sent); + tcp_err(_pcb, &_tcp_error); + tcp_poll(_pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); + } + return *this; +} + +bool AsyncClient::operator==(const AsyncClient& other) { + return _pcb == other._pcb; +} + +AsyncClient& AsyncClient::operator+=(const AsyncClient& other) { + if (next == NULL) { + next = (AsyncClient*)(&other); + next->prev = this; + } else { + AsyncClient* c = next; + while (c->next != NULL) { + c = c->next; + } + c->next = (AsyncClient*)(&other); + c->next->prev = c; + } + return *this; +} + +/* + * Callback Setters + * */ + +void AsyncClient::onConnect(AcConnectHandler cb, void* arg) { + _connect_cb = cb; + _connect_cb_arg = arg; +} + +void AsyncClient::onDisconnect(AcConnectHandler cb, void* arg) { + _discard_cb = cb; + _discard_cb_arg = arg; +} + +void AsyncClient::onAck(AcAckHandler cb, void* arg) { + _sent_cb = cb; + _sent_cb_arg = arg; +} + +void AsyncClient::onError(AcErrorHandler cb, void* arg) { + _error_cb = cb; + _error_cb_arg = arg; +} + +void AsyncClient::onData(AcDataHandler cb, void* arg) { + _recv_cb = cb; + _recv_cb_arg = arg; +} + +void AsyncClient::onPacket(AcPacketHandler cb, void* arg) { + _pb_cb = cb; + _pb_cb_arg = arg; +} + +void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg) { + _timeout_cb = cb; + _timeout_cb_arg = arg; +} + +void AsyncClient::onPoll(AcConnectHandler cb, void* arg) { + _poll_cb = cb; + _poll_cb_arg = arg; +} + +/* + * Main Public Methods + * */ + +bool AsyncClient::_connect(ip_addr_t addr, uint16_t port) { + if (_pcb) { + log_d("already connected, state %d", _pcb->state); + return false; + } + if (!_start_async_task()) { + log_e("failed to start task"); + return false; + } + + if (!_allocate_closed_slot()) { + log_e("failed to allocate: closed slot full"); + return false; + } + + TCP_MUTEX_LOCK(); + tcp_pcb* pcb = tcp_new_ip_type(addr.type); + if (!pcb) { + TCP_MUTEX_UNLOCK(); + log_e("pcb == NULL"); + return false; + } + tcp_arg(pcb, this); + tcp_err(pcb, &_tcp_error); + tcp_recv(pcb, &_tcp_recv); + tcp_sent(pcb, &_tcp_sent); + tcp_poll(pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); + TCP_MUTEX_UNLOCK(); + + esp_err_t err = _tcp_connect(pcb, _closed_slot, &addr, port, (tcp_connected_fn)&_tcp_connected); + return err == ESP_OK; +} + +bool AsyncClient::connect(const IPAddress& ip, uint16_t port) { + ip_addr_t addr; +#if ESP_IDF_VERSION_MAJOR < 5 + addr.u_addr.ip4.addr = ip; + addr.type = IPADDR_TYPE_V4; +#else + ip.to_ip_addr_t(&addr); +#endif + + return _connect(addr, port); +} + +#if LWIP_IPV6 && ESP_IDF_VERSION_MAJOR < 5 +bool AsyncClient::connect(const IPv6Address& ip, uint16_t port) { + auto ipaddr = static_cast(ip); + ip_addr_t addr = IPADDR6_INIT(ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + + return _connect(addr, port); +} +#endif + +bool AsyncClient::connect(const char* host, uint16_t port) { + ip_addr_t addr; + + if (!_start_async_task()) { + log_e("failed to start task"); + return false; + } + + TCP_MUTEX_LOCK(); + err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); + TCP_MUTEX_UNLOCK(); + if (err == ERR_OK) { +#if ESP_IDF_VERSION_MAJOR < 5 + #if LWIP_IPV6 + if (addr.type == IPADDR_TYPE_V6) { + return connect(IPv6Address(addr.u_addr.ip6.addr), port); + } + return connect(IPAddress(addr.u_addr.ip4.addr), port); + #else + return connect(IPAddress(addr.addr), port); + #endif +#else + return _connect(addr, port); +#endif + } else if (err == ERR_INPROGRESS) { + _connect_port = port; + return true; + } + log_d("error: %d", err); + return false; +} + +void AsyncClient::close(bool now) { + if (_pcb) { + _tcp_recved(_pcb, _closed_slot, _rx_ack_len); + } + _close(); +} + +int8_t AsyncClient::abort() { + if (_pcb) { + _tcp_abort(_pcb, _closed_slot); + _pcb = NULL; + } + return ERR_ABRT; +} + +size_t AsyncClient::space() { + if ((_pcb != NULL) && (_pcb->state == ESTABLISHED)) { + return tcp_sndbuf(_pcb); + } + return 0; +} + +size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { + if (!_pcb || size == 0 || data == NULL) { + return 0; + } + size_t room = space(); + if (!room) { + return 0; + } + size_t will_send = (room < size) ? room : size; + int8_t err = ERR_OK; + err = _tcp_write(_pcb, _closed_slot, data, will_send, apiflags); + if (err != ERR_OK) { + return 0; + } + return will_send; +} + +bool AsyncClient::send() { + auto backup = _tx_last_packet; + _tx_last_packet = millis(); + if (_tcp_output(_pcb, _closed_slot) == ERR_OK) { + return true; + } + _tx_last_packet = backup; + return false; +} + +size_t AsyncClient::ack(size_t len) { + if (len > _rx_ack_len) + len = _rx_ack_len; + if (len) { + _tcp_recved(_pcb, _closed_slot, len); + } + _rx_ack_len -= len; + return len; +} + +void AsyncClient::ackPacket(struct pbuf* pb) { + if (!pb) { + return; + } + _tcp_recved(_pcb, _closed_slot, pb->len); + pbuf_free(pb); +} + +/* + * Main Private Methods + * */ + +int8_t AsyncClient::_close() { + // ets_printf("X: 0x%08x\n", (uint32_t)this); + int8_t err = ERR_OK; + if (_pcb) { + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + TCP_MUTEX_UNLOCK(); + _tcp_clear_events(this); + err = _tcp_close(_pcb, _closed_slot); + if (err != ERR_OK) { + err = abort(); + } + _free_closed_slot(); + _pcb = NULL; + if (_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + } + return err; +} + +bool AsyncClient::_allocate_closed_slot() { + if (_closed_slot != INVALID_CLOSED_SLOT) { + return true; + } + xSemaphoreTake(_slots_lock, portMAX_DELAY); + uint32_t closed_slot_min_index = 0; + for (int i = 0; i < _number_of_closed_slots; ++i) { + if ((_closed_slot == INVALID_CLOSED_SLOT || _closed_slots[i] <= closed_slot_min_index) && _closed_slots[i] != 0) { + closed_slot_min_index = _closed_slots[i]; + _closed_slot = i; + } + } + if (_closed_slot != INVALID_CLOSED_SLOT) { + _closed_slots[_closed_slot] = 0; + } + xSemaphoreGive(_slots_lock); + return (_closed_slot != INVALID_CLOSED_SLOT); +} + +void AsyncClient::_free_closed_slot() { + xSemaphoreTake(_slots_lock, portMAX_DELAY); + if (_closed_slot != INVALID_CLOSED_SLOT) { + _closed_slots[_closed_slot] = _closed_index; + _closed_slot = INVALID_CLOSED_SLOT; + ++_closed_index; + } + xSemaphoreGive(_slots_lock); +} + +/* + * Private Callbacks + * */ + +int8_t AsyncClient::_connected(tcp_pcb* pcb, int8_t err) { + _pcb = reinterpret_cast(pcb); + if (_pcb) { + _rx_last_packet = millis(); + } + if (_connect_cb) { + _connect_cb(_connect_cb_arg, this); + } + return ERR_OK; +} + +void AsyncClient::_error(int8_t err) { + if (_pcb) { + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, NULL); + if (_pcb->state == LISTEN) { + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + } + TCP_MUTEX_UNLOCK(); + _free_closed_slot(); + _pcb = NULL; + } + if (_error_cb) { + _error_cb(_error_cb_arg, this, err); + } + if (_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } +} + +// In LwIP Thread +int8_t AsyncClient::_lwip_fin(tcp_pcb* pcb, int8_t err) { + if (!_pcb || pcb != _pcb) { + log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + return ERR_OK; + } + tcp_arg(_pcb, NULL); + if (_pcb->state == LISTEN) { + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + } + if (tcp_close(_pcb) != ERR_OK) { + tcp_abort(_pcb); + } + _free_closed_slot(); + _pcb = NULL; + return ERR_OK; +} + +// In Async Thread +int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) { + _tcp_clear_events(this); + if (_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + return ERR_OK; +} + +int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { + _rx_last_ack = _rx_last_packet = millis(); + if (_sent_cb) { + _sent_cb(_sent_cb_arg, this, len, (_rx_last_packet - _tx_last_packet)); + } + return ERR_OK; +} + +int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { + while (pb != NULL) { + _rx_last_packet = millis(); + // we should not ack before we assimilate the data + _ack_pcb = true; + pbuf* b = pb; + pb = b->next; + b->next = NULL; + if (_pb_cb) { + _pb_cb(_pb_cb_arg, this, b); + } else { + if (_recv_cb) { + _recv_cb(_recv_cb_arg, this, b->payload, b->len); + } + if (!_ack_pcb) { + _rx_ack_len += b->len; + } else if (_pcb) { + _tcp_recved(_pcb, _closed_slot, b->len); + } + } + pbuf_free(b); + } + return ERR_OK; +} + +int8_t AsyncClient::_poll(tcp_pcb* pcb) { + if (!_pcb) { + // log_d("pcb is NULL"); + return ERR_OK; + } + if (pcb != _pcb) { + log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + return ERR_OK; + } + + uint32_t now = millis(); + + // ACK Timeout + if (_ack_timeout) { + const uint32_t one_day = 86400000; + bool last_tx_is_after_last_ack = (_rx_last_ack - _tx_last_packet + one_day) < one_day; + if (last_tx_is_after_last_ack && (now - _tx_last_packet) >= _ack_timeout) { + log_d("ack timeout %d", pcb->state); + if (_timeout_cb) + _timeout_cb(_timeout_cb_arg, this, (now - _tx_last_packet)); + return ERR_OK; + } + } + // RX Timeout + if (_rx_timeout && (now - _rx_last_packet) >= (_rx_timeout * 1000)) { + log_d("rx timeout %d", pcb->state); + _close(); + return ERR_OK; + } + // Everything is fine + if (_poll_cb) { + _poll_cb(_poll_cb_arg, this); + } + return ERR_OK; +} + +void AsyncClient::_dns_found(struct ip_addr* ipaddr) { +#if ESP_IDF_VERSION_MAJOR < 5 + if (ipaddr && IP_IS_V4(ipaddr)) { + connect(IPAddress(ip_addr_get_ip4_u32(ipaddr)), _connect_port); + #if LWIP_IPV6 + } else if (ipaddr && ipaddr->u_addr.ip6.addr) { + connect(IPv6Address(ipaddr->u_addr.ip6.addr), _connect_port); + #endif +#else + if (ipaddr) { + IPAddress ip; + ip.from_ip_addr_t(ipaddr); + connect(ip, _connect_port); +#endif + } else { + if (_error_cb) { + _error_cb(_error_cb_arg, this, -55); + } + if (_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + } +} + +/* + * Public Helper Methods + * */ + +bool AsyncClient::free() { + if (!_pcb) { + return true; + } + if (_pcb->state == CLOSED || _pcb->state > ESTABLISHED) { + return true; + } + return false; +} + +size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) { + size_t will_send = add(data, size, apiflags); + if (!will_send || !send()) { + return 0; + } + return will_send; +} + +void AsyncClient::setRxTimeout(uint32_t timeout) { + _rx_timeout = timeout; +} + +uint32_t AsyncClient::getRxTimeout() { + return _rx_timeout; +} + +uint32_t AsyncClient::getAckTimeout() { + return _ack_timeout; +} + +void AsyncClient::setAckTimeout(uint32_t timeout) { + _ack_timeout = timeout; +} + +void AsyncClient::setNoDelay(bool nodelay) { + if (!_pcb) { + return; + } + if (nodelay) { + tcp_nagle_disable(_pcb); + } else { + tcp_nagle_enable(_pcb); + } +} + +bool AsyncClient::getNoDelay() { + if (!_pcb) { + return false; + } + return tcp_nagle_disabled(_pcb); +} + +void AsyncClient::setKeepAlive(uint32_t ms, uint8_t cnt) { + if (ms != 0) { + _pcb->so_options |= SOF_KEEPALIVE; // Turn on TCP Keepalive for the given pcb + // Set the time between keepalive messages in milli-seconds + _pcb->keep_idle = ms; + _pcb->keep_intvl = ms; + _pcb->keep_cnt = cnt; // The number of unanswered probes required to force closure of the socket + } else { + _pcb->so_options &= ~SOF_KEEPALIVE; // Turn off TCP Keepalive for the given pcb + } +} + +uint16_t AsyncClient::getMss() { + if (!_pcb) { + return 0; + } + return tcp_mss(_pcb); +} + +uint32_t AsyncClient::getRemoteAddress() { + if (!_pcb) { + return 0; + } +#if LWIP_IPV4 && LWIP_IPV6 + return _pcb->remote_ip.u_addr.ip4.addr; +#else + return _pcb->remote_ip.addr; +#endif +} + +#if LWIP_IPV6 +ip6_addr_t AsyncClient::getRemoteAddress6() { + if (!_pcb) { + ip6_addr_t nulladdr; + ip6_addr_set_zero(&nulladdr); + return nulladdr; + } + return _pcb->remote_ip.u_addr.ip6; +} + +ip6_addr_t AsyncClient::getLocalAddress6() { + if (!_pcb) { + ip6_addr_t nulladdr; + ip6_addr_set_zero(&nulladdr); + return nulladdr; + } + return _pcb->local_ip.u_addr.ip6; +} + #if ESP_IDF_VERSION_MAJOR < 5 +IPv6Address AsyncClient::remoteIP6() { + return IPv6Address(getRemoteAddress6().addr); +} + +IPv6Address AsyncClient::localIP6() { + return IPv6Address(getLocalAddress6().addr); +} + #else +IPAddress AsyncClient::remoteIP6() { + if (!_pcb) { + return IPAddress(IPType::IPv6); + } + IPAddress ip; + ip.from_ip_addr_t(&(_pcb->remote_ip)); + return ip; +} + +IPAddress AsyncClient::localIP6() { + if (!_pcb) { + return IPAddress(IPType::IPv6); + } + IPAddress ip; + ip.from_ip_addr_t(&(_pcb->local_ip)); + return ip; +} + #endif +#endif + +uint16_t AsyncClient::getRemotePort() { + if (!_pcb) { + return 0; + } + return _pcb->remote_port; +} + +uint32_t AsyncClient::getLocalAddress() { + if (!_pcb) { + return 0; + } +#if LWIP_IPV4 && LWIP_IPV6 + return _pcb->local_ip.u_addr.ip4.addr; +#else + return _pcb->local_ip.addr; +#endif +} + +uint16_t AsyncClient::getLocalPort() { + if (!_pcb) { + return 0; + } + return _pcb->local_port; +} + +IPAddress AsyncClient::remoteIP() { +#if ESP_IDF_VERSION_MAJOR < 5 + return IPAddress(getRemoteAddress()); +#else + if (!_pcb) { + return IPAddress(); + } + IPAddress ip; + ip.from_ip_addr_t(&(_pcb->remote_ip)); + return ip; +#endif +} + +uint16_t AsyncClient::remotePort() { + return getRemotePort(); +} + +IPAddress AsyncClient::localIP() { +#if ESP_IDF_VERSION_MAJOR < 5 + return IPAddress(getLocalAddress()); +#else + if (!_pcb) { + return IPAddress(); + } + IPAddress ip; + ip.from_ip_addr_t(&(_pcb->local_ip)); + return ip; +#endif +} + +uint16_t AsyncClient::localPort() { + return getLocalPort(); +} + +uint8_t AsyncClient::state() { + if (!_pcb) { + return 0; + } + return _pcb->state; +} + +bool AsyncClient::connected() { + if (!_pcb) { + return false; + } + return _pcb->state == ESTABLISHED; +} + +bool AsyncClient::connecting() { + if (!_pcb) { + return false; + } + return _pcb->state > CLOSED && _pcb->state < ESTABLISHED; +} + +bool AsyncClient::disconnecting() { + if (!_pcb) { + return false; + } + return _pcb->state > ESTABLISHED && _pcb->state < TIME_WAIT; +} + +bool AsyncClient::disconnected() { + if (!_pcb) { + return true; + } + return _pcb->state == CLOSED || _pcb->state == TIME_WAIT; +} + +bool AsyncClient::freeable() { + if (!_pcb) { + return true; + } + return _pcb->state == CLOSED || _pcb->state > ESTABLISHED; +} + +bool AsyncClient::canSend() { + return space() > 0; +} + +const char* AsyncClient::errorToString(int8_t error) { + switch (error) { + case ERR_OK: + return "OK"; + case ERR_MEM: + return "Out of memory error"; + case ERR_BUF: + return "Buffer error"; + case ERR_TIMEOUT: + return "Timeout"; + case ERR_RTE: + return "Routing problem"; + case ERR_INPROGRESS: + return "Operation in progress"; + case ERR_VAL: + return "Illegal value"; + case ERR_WOULDBLOCK: + return "Operation would block"; + case ERR_USE: + return "Address in use"; + case ERR_ALREADY: + return "Already connected"; + case ERR_CONN: + return "Not connected"; + case ERR_IF: + return "Low-level netif error"; + case ERR_ABRT: + return "Connection aborted"; + case ERR_RST: + return "Connection reset"; + case ERR_CLSD: + return "Connection closed"; + case ERR_ARG: + return "Illegal argument"; + case -55: + return "DNS failed"; + default: + return "UNKNOWN"; + } +} + +const char* AsyncClient::stateToString() { + switch (state()) { + case 0: + return "Closed"; + case 1: + return "Listen"; + case 2: + return "SYN Sent"; + case 3: + return "SYN Received"; + case 4: + return "Established"; + case 5: + return "FIN Wait 1"; + case 6: + return "FIN Wait 2"; + case 7: + return "Close Wait"; + case 8: + return "Closing"; + case 9: + return "Last ACK"; + case 10: + return "Time Wait"; + default: + return "UNKNOWN"; + } +} + +/* + * Static Callbacks (LwIP C2C++ interconnect) + * */ + +void AsyncClient::_s_dns_found(const char* name, struct ip_addr* ipaddr, void* arg) { + reinterpret_cast(arg)->_dns_found(ipaddr); +} + +int8_t AsyncClient::_s_poll(void* arg, struct tcp_pcb* pcb) { + return reinterpret_cast(arg)->_poll(pcb); +} + +int8_t AsyncClient::_s_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* pb, int8_t err) { + return reinterpret_cast(arg)->_recv(pcb, pb, err); +} + +int8_t AsyncClient::_s_fin(void* arg, struct tcp_pcb* pcb, int8_t err) { + return reinterpret_cast(arg)->_fin(pcb, err); +} + +int8_t AsyncClient::_s_lwip_fin(void* arg, struct tcp_pcb* pcb, int8_t err) { + return reinterpret_cast(arg)->_lwip_fin(pcb, err); +} + +int8_t AsyncClient::_s_sent(void* arg, struct tcp_pcb* pcb, uint16_t len) { + return reinterpret_cast(arg)->_sent(pcb, len); +} + +void AsyncClient::_s_error(void* arg, int8_t err) { + reinterpret_cast(arg)->_error(err); +} + +int8_t AsyncClient::_s_connected(void* arg, struct tcp_pcb* pcb, int8_t err) { + return reinterpret_cast(arg)->_connected(pcb, err); +} + +/* + Async TCP Server + */ + +AsyncServer::AsyncServer(IPAddress addr, uint16_t port) + : _port(port) +#if ESP_IDF_VERSION_MAJOR < 5 + , + _bind4(true), _bind6(false) +#else + , + _bind4(addr.type() != IPType::IPv6), _bind6(addr.type() == IPType::IPv6) +#endif + , + _addr(addr), _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) { +} + +#if ESP_IDF_VERSION_MAJOR < 5 +AsyncServer::AsyncServer(IPv6Address addr, uint16_t port) + : _port(port), _bind4(false), _bind6(true), _addr6(addr), _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) {} +#endif + +AsyncServer::AsyncServer(uint16_t port) + : _port(port), _bind4(true), _bind6(false), _addr((uint32_t)IPADDR_ANY) +#if ESP_IDF_VERSION_MAJOR < 5 + , + _addr6() +#endif + , + _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) { +} + +AsyncServer::~AsyncServer() { + end(); +} + +void AsyncServer::onClient(AcConnectHandler cb, void* arg) { + _connect_cb = cb; + _connect_cb_arg = arg; +} + +void AsyncServer::begin() { + if (_pcb) { + return; + } + + if (!_start_async_task()) { + log_e("failed to start task"); + return; + } + int8_t err; + TCP_MUTEX_LOCK(); + _pcb = tcp_new_ip_type(_bind4 && _bind6 ? IPADDR_TYPE_ANY : (_bind6 ? IPADDR_TYPE_V6 : IPADDR_TYPE_V4)); + TCP_MUTEX_UNLOCK(); + if (!_pcb) { + log_e("_pcb == NULL"); + return; + } + + ip_addr_t local_addr; +#if ESP_IDF_VERSION_MAJOR < 5 + if (_bind6) { // _bind6 && _bind4 both at the same time is not supported on Arduino 2 in this lib API + local_addr.type = IPADDR_TYPE_V6; + memcpy(local_addr.u_addr.ip6.addr, static_cast(_addr6), sizeof(uint32_t) * 4); + } else { + local_addr.type = IPADDR_TYPE_V4; + local_addr.u_addr.ip4.addr = _addr; + } +#else + _addr.to_ip_addr_t(&local_addr); +#endif + err = _tcp_bind(_pcb, &local_addr, _port); + + if (err != ERR_OK) { + _tcp_close(_pcb, -1); + log_e("bind error: %d", err); + return; + } + + static uint8_t backlog = 5; + _pcb = _tcp_listen_with_backlog(_pcb, backlog); + if (!_pcb) { + log_e("listen_pcb == NULL"); + return; + } + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, (void*)this); + tcp_accept(_pcb, &_s_accept); + TCP_MUTEX_UNLOCK(); +} + +void AsyncServer::end() { + if (_pcb) { + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, NULL); + tcp_accept(_pcb, NULL); + if (tcp_close(_pcb) != ERR_OK) { + TCP_MUTEX_UNLOCK(); + _tcp_abort(_pcb, -1); + } else { + TCP_MUTEX_UNLOCK(); + } + _pcb = NULL; + } +} + +// runs on LwIP thread +int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err) { + // ets_printf("+A: 0x%08x\n", pcb); + if (_connect_cb) { + AsyncClient* c = new AsyncClient(pcb); + if (c) { + c->setNoDelay(_noDelay); + return _tcp_accept(this, c); + } + } + if (tcp_close(pcb) != ERR_OK) { + tcp_abort(pcb); + } + log_d("FAIL"); + return ERR_OK; +} + +int8_t AsyncServer::_accepted(AsyncClient* client) { + if (_connect_cb) { + _connect_cb(_connect_cb_arg, client); + } + return ERR_OK; +} + +void AsyncServer::setNoDelay(bool nodelay) { + _noDelay = nodelay; +} + +bool AsyncServer::getNoDelay() { + return _noDelay; +} + +uint8_t AsyncServer::status() { + if (!_pcb) { + return 0; + } + return _pcb->state; +} + +int8_t AsyncServer::_s_accept(void* arg, tcp_pcb* pcb, int8_t err) { + return reinterpret_cast(arg)->_accept(pcb, err); +} + +int8_t AsyncServer::_s_accepted(void* arg, AsyncClient* client) { + return reinterpret_cast(arg)->_accepted(client); +} diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h b/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h new file mode 100644 index 000000000..c909d0518 --- /dev/null +++ b/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h @@ -0,0 +1,347 @@ +/* + Asynchronous TCP library for Espressif MCUs + + Copyright (c) 2016 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ASYNCTCP_H_ +#define ASYNCTCP_H_ + +#define ASYNCTCP_VERSION "3.3.1" +#define ASYNCTCP_VERSION_MAJOR 3 +#define ASYNCTCP_VERSION_MINOR 3 +#define ASYNCTCP_VERSION_REVISION 1 +#define ASYNCTCP_FORK_mathieucarbou + +#include "../../../devboard/hal/hal.h" +#include "../../../system_settings.h" + +#include "IPAddress.h" +#if ESP_IDF_VERSION_MAJOR < 5 + #include "IPv6Address.h" +#endif +#include "lwip/ip6_addr.h" +#include "lwip/ip_addr.h" +#include + +#ifndef LIBRETINY + #include "sdkconfig.h" +extern "C" { + #include "freertos/semphr.h" + #include "lwip/pbuf.h" +} +#else +extern "C" { + #include + #include +} + #define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE +#endif + +// If core is not defined, then we are running in Arduino or PIO +#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE + #define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE +#endif + +// guard AsyncTCP task with watchdog +#ifndef CONFIG_ASYNC_TCP_USE_WDT + #define CONFIG_ASYNC_TCP_USE_WDT 0 +#endif + +#ifndef CONFIG_ASYNC_TCP_STACK_SIZE + #define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2 +#endif + +#ifndef CONFIG_ASYNC_TCP_PRIORITY + #define CONFIG_ASYNC_TCP_PRIORITY 10 +#endif + +#ifndef CONFIG_ASYNC_TCP_QUEUE_SIZE + #define CONFIG_ASYNC_TCP_QUEUE_SIZE 64 +#endif + +#ifndef CONFIG_ASYNC_TCP_MAX_ACK_TIME + #define CONFIG_ASYNC_TCP_MAX_ACK_TIME 5000 +#endif + +class AsyncClient; + +#define ASYNC_WRITE_FLAG_COPY 0x01 // will allocate new buffer to hold the data while sending (else will hold reference to the data given) +#define ASYNC_WRITE_FLAG_MORE 0x02 // will not send PSH flag, meaning that there should be more data to be sent before the application should react. + +typedef std::function AcConnectHandler; +typedef std::function AcAckHandler; +typedef std::function AcErrorHandler; +typedef std::function AcDataHandler; +typedef std::function AcPacketHandler; +typedef std::function AcTimeoutHandler; + +struct tcp_pcb; +struct ip_addr; + +class AsyncClient { + public: + AsyncClient(tcp_pcb* pcb = 0); + ~AsyncClient(); + + AsyncClient& operator=(const AsyncClient& other); + AsyncClient& operator+=(const AsyncClient& other); + + bool operator==(const AsyncClient& other); + + bool operator!=(const AsyncClient& other) { + return !(*this == other); + } + bool connect(const IPAddress& ip, uint16_t port); +#if ESP_IDF_VERSION_MAJOR < 5 + bool connect(const IPv6Address& ip, uint16_t port); +#endif + bool connect(const char* host, uint16_t port); + /** + * @brief close connection + * + * @param now - ignored + */ + void close(bool now = false); + // same as close() + void stop() { close(false); }; + int8_t abort(); + bool free(); + + // ack is not pending + bool canSend(); + // TCP buffer space available + size_t space(); + + /** + * @brief add data to be send (but do not send yet) + * @note add() would call lwip's tcp_write() + By default apiflags=ASYNC_WRITE_FLAG_COPY + You could try to use apiflags with this flag unset to pass data by reference and avoid copy to socket buffer, + but looks like it does not work for Arduino's lwip in ESP32/IDF at least + it is enforced in https://github.com/espressif/esp-lwip/blob/0606eed9d8b98a797514fdf6eabb4daf1c8c8cd9/src/core/tcp_out.c#L422C5-L422C30 + if LWIP_NETIF_TX_SINGLE_PBUF is set, and it is set indeed in IDF + https://github.com/espressif/esp-idf/blob/a0f798cfc4bbd624aab52b2c194d219e242d80c1/components/lwip/port/include/lwipopts.h#L744 + * + * @param data + * @param size + * @param apiflags + * @return size_t amount of data that has been copied + */ + size_t add(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); + + /** + * @brief send data previously add()'ed + * + * @return true on success + * @return false on error + */ + bool send(); + + /** + * @brief add and enqueue data for sending + * @note it is same as add() + send() + * @note only make sense when canSend() == true + * + * @param data + * @param size + * @param apiflags + * @return size_t + */ + size_t write(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); + + /** + * @brief add and enque data for sending + * @note treats data as null-terminated string + * + * @param data + * @return size_t + */ + size_t write(const char* data) { return data == NULL ? 0 : write(data, strlen(data)); }; + + uint8_t state(); + bool connecting(); + bool connected(); + bool disconnecting(); + bool disconnected(); + + // disconnected or disconnecting + bool freeable(); + + uint16_t getMss(); + + uint32_t getRxTimeout(); + // no RX data timeout for the connection in seconds + void setRxTimeout(uint32_t timeout); + + uint32_t getAckTimeout(); + // no ACK timeout for the last sent packet in milliseconds + void setAckTimeout(uint32_t timeout); + + void setNoDelay(bool nodelay); + bool getNoDelay(); + + void setKeepAlive(uint32_t ms, uint8_t cnt); + + uint32_t getRemoteAddress(); + uint16_t getRemotePort(); + uint32_t getLocalAddress(); + uint16_t getLocalPort(); +#if LWIP_IPV6 + ip6_addr_t getRemoteAddress6(); + ip6_addr_t getLocalAddress6(); + #if ESP_IDF_VERSION_MAJOR < 5 + IPv6Address remoteIP6(); + IPv6Address localIP6(); + #else + IPAddress remoteIP6(); + IPAddress localIP6(); + #endif +#endif + + // compatibility + IPAddress remoteIP(); + uint16_t remotePort(); + IPAddress localIP(); + uint16_t localPort(); + + // set callback - on successful connect + void onConnect(AcConnectHandler cb, void* arg = 0); + // set callback - disconnected + void onDisconnect(AcConnectHandler cb, void* arg = 0); + // set callback - ack received + void onAck(AcAckHandler cb, void* arg = 0); + // set callback - unsuccessful connect or error + void onError(AcErrorHandler cb, void* arg = 0); + // set callback - data received (called if onPacket is not used) + void onData(AcDataHandler cb, void* arg = 0); + // set callback - data received + void onPacket(AcPacketHandler cb, void* arg = 0); + // set callback - ack timeout + void onTimeout(AcTimeoutHandler cb, void* arg = 0); + // set callback - every 125ms when connected + void onPoll(AcConnectHandler cb, void* arg = 0); + + // ack pbuf from onPacket + void ackPacket(struct pbuf* pb); + // ack data that you have not acked using the method below + size_t ack(size_t len); + // will not ack the current packet. Call from onData + void ackLater() { _ack_pcb = false; } + + static const char* errorToString(int8_t error); + const char* stateToString(); + + // internal callbacks - Do NOT call any of the functions below in user code! + static int8_t _s_poll(void* arg, struct tcp_pcb* tpcb); + static int8_t _s_recv(void* arg, struct tcp_pcb* tpcb, struct pbuf* pb, int8_t err); + static int8_t _s_fin(void* arg, struct tcp_pcb* tpcb, int8_t err); + static int8_t _s_lwip_fin(void* arg, struct tcp_pcb* tpcb, int8_t err); + static void _s_error(void* arg, int8_t err); + static int8_t _s_sent(void* arg, struct tcp_pcb* tpcb, uint16_t len); + static int8_t _s_connected(void* arg, struct tcp_pcb* tpcb, int8_t err); + static void _s_dns_found(const char* name, struct ip_addr* ipaddr, void* arg); + + int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); + tcp_pcb* pcb() { return _pcb; } + + protected: + bool _connect(ip_addr_t addr, uint16_t port); + + tcp_pcb* _pcb; + int8_t _closed_slot; + + AcConnectHandler _connect_cb; + void* _connect_cb_arg; + AcConnectHandler _discard_cb; + void* _discard_cb_arg; + AcAckHandler _sent_cb; + void* _sent_cb_arg; + AcErrorHandler _error_cb; + void* _error_cb_arg; + AcDataHandler _recv_cb; + void* _recv_cb_arg; + AcPacketHandler _pb_cb; + void* _pb_cb_arg; + AcTimeoutHandler _timeout_cb; + void* _timeout_cb_arg; + AcConnectHandler _poll_cb; + void* _poll_cb_arg; + + bool _ack_pcb; + uint32_t _tx_last_packet; + uint32_t _rx_ack_len; + uint32_t _rx_last_packet; + uint32_t _rx_timeout; + uint32_t _rx_last_ack; + uint32_t _ack_timeout; + uint16_t _connect_port; + + int8_t _close(); + void _free_closed_slot(); + bool _allocate_closed_slot(); + int8_t _connected(tcp_pcb* pcb, int8_t err); + void _error(int8_t err); + int8_t _poll(tcp_pcb* pcb); + int8_t _sent(tcp_pcb* pcb, uint16_t len); + int8_t _fin(tcp_pcb* pcb, int8_t err); + int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); + void _dns_found(struct ip_addr* ipaddr); + + public: + AsyncClient* prev; + AsyncClient* next; +}; + +class AsyncServer { + public: + AsyncServer(IPAddress addr, uint16_t port); +#if ESP_IDF_VERSION_MAJOR < 5 + AsyncServer(IPv6Address addr, uint16_t port); +#endif + AsyncServer(uint16_t port); + ~AsyncServer(); + void onClient(AcConnectHandler cb, void* arg); + void begin(); + void end(); + void setNoDelay(bool nodelay); + bool getNoDelay(); + uint8_t status(); + + // Do not use any of the functions below! + static int8_t _s_accept(void* arg, tcp_pcb* newpcb, int8_t err); + static int8_t _s_accepted(void* arg, AsyncClient* client); + + protected: + uint16_t _port; + bool _bind4 = false; + bool _bind6 = false; + IPAddress _addr; +#if ESP_IDF_VERSION_MAJOR < 5 + IPv6Address _addr6; +#endif + bool _noDelay; + tcp_pcb* _pcb; + AcConnectHandler _connect_cb; + void* _connect_cb_arg; + + int8_t _accept(tcp_pcb* newpcb, int8_t err); + int8_t _accepted(AsyncClient* client); +}; + +#endif /* ASYNCTCP_H_ */ diff --git a/Software/src/lib/me-no-dev-AsyncTCP/.gitignore b/Software/src/lib/me-no-dev-AsyncTCP/.gitignore deleted file mode 100644 index 9bea4330f..000000000 --- a/Software/src/lib/me-no-dev-AsyncTCP/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ - -.DS_Store diff --git a/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml b/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml deleted file mode 100644 index dbfc064af..000000000 --- a/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -sudo: false -language: python -os: - - linux - -git: - depth: false - -stages: - - build - -jobs: - include: - - - name: "Arduino Build" - if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) - stage: build - script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh - - - name: "PlatformIO Build" - if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) - stage: build - script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 1 1 - -notifications: - email: - on_success: change - on_failure: change - webhooks: - urls: - - https://webhooks.gitter.im/e/60e65d0c78ea0a920347 - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: false # default: false diff --git a/Software/src/lib/me-no-dev-AsyncTCP/README.md b/Software/src/lib/me-no-dev-AsyncTCP/README.md deleted file mode 100644 index 79ffa9ef5..000000000 --- a/Software/src/lib/me-no-dev-AsyncTCP/README.md +++ /dev/null @@ -1,15 +0,0 @@ -This is commit ca8ac5f from https://github.com/me-no-dev/AsyncTCP - -# AsyncTCP -[![Build Status](https://travis-ci.org/me-no-dev/AsyncTCP.svg?branch=master)](https://travis-ci.org/me-no-dev/AsyncTCP) ![](https://github.com/me-no-dev/AsyncTCP/workflows/Async%20TCP%20CI/badge.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2f7e4d1df8b446d192cbfec6dc174d2d)](https://www.codacy.com/manual/me-no-dev/AsyncTCP?utm_source=github.com&utm_medium=referral&utm_content=me-no-dev/AsyncTCP&utm_campaign=Badge_Grade) - -### Async TCP Library for ESP32 Arduino - -[![Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer](https://badges.gitter.im/me-no-dev/ESPAsyncWebServer.svg)](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs. - -This library is the base for [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) - -## AsyncClient and AsyncServer -The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. diff --git a/Software/src/lib/me-no-dev-AsyncTCP/library.json b/Software/src/lib/me-no-dev-AsyncTCP/library.json deleted file mode 100644 index 89f90e4ec..000000000 --- a/Software/src/lib/me-no-dev-AsyncTCP/library.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name":"AsyncTCP", - "description":"Asynchronous TCP Library for ESP32", - "keywords":"async,tcp", - "authors": - { - "name": "Hristo Gochkov", - "maintainer": true - }, - "repository": - { - "type": "git", - "url": "https://github.com/me-no-dev/AsyncTCP.git" - }, - "version": "1.1.1", - "license": "LGPL-3.0", - "frameworks": "arduino", - "platforms": "espressif32", - "build": { - "libCompatMode": 2 - } -} diff --git a/Software/src/lib/me-no-dev-AsyncTCP/library.properties b/Software/src/lib/me-no-dev-AsyncTCP/library.properties deleted file mode 100644 index eb4e26e90..000000000 --- a/Software/src/lib/me-no-dev-AsyncTCP/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=AsyncTCP -version=1.1.1 -author=Me-No-Dev -maintainer=Me-No-Dev -sentence=Async TCP Library for ESP32 -paragraph=Async TCP Library for ESP32 -category=Other -url=https://github.com/me-no-dev/AsyncTCP -architectures=* diff --git a/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp deleted file mode 100644 index cce37d648..000000000 --- a/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp +++ /dev/null @@ -1,1357 +0,0 @@ -/* - Asynchronous TCP library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "Arduino.h" - -#include "AsyncTCP.h" -extern "C"{ -#include "lwip/opt.h" -#include "lwip/tcp.h" -#include "lwip/inet.h" -#include "lwip/dns.h" -#include "lwip/err.h" -} -#include "esp_task_wdt.h" - -/* - * TCP/IP Event Task - * */ - -typedef enum { - LWIP_TCP_SENT, LWIP_TCP_RECV, LWIP_TCP_FIN, LWIP_TCP_ERROR, LWIP_TCP_POLL, LWIP_TCP_CLEAR, LWIP_TCP_ACCEPT, LWIP_TCP_CONNECTED, LWIP_TCP_DNS -} lwip_event_t; - -typedef struct { - lwip_event_t event; - void *arg; - union { - struct { - void * pcb; - int8_t err; - } connected; - struct { - int8_t err; - } error; - struct { - tcp_pcb * pcb; - uint16_t len; - } sent; - struct { - tcp_pcb * pcb; - pbuf * pb; - int8_t err; - } recv; - struct { - tcp_pcb * pcb; - int8_t err; - } fin; - struct { - tcp_pcb * pcb; - } poll; - struct { - AsyncClient * client; - } accept; - struct { - const char * name; - ip_addr_t addr; - } dns; - }; -} lwip_event_packet_t; - -static xQueueHandle _async_queue; -static TaskHandle_t _async_service_task_handle = NULL; - - -SemaphoreHandle_t _slots_lock; -const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP; -static uint32_t _closed_slots[_number_of_closed_slots]; -static uint32_t _closed_index = []() { - _slots_lock = xSemaphoreCreateBinary(); - xSemaphoreGive(_slots_lock); - for (int i = 0; i < _number_of_closed_slots; ++ i) { - _closed_slots[i] = 1; - } - return 1; -}(); - - -static inline bool _init_async_event_queue(){ - if(!_async_queue){ - _async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *)); - if(!_async_queue){ - return false; - } - } - return true; -} - -static inline bool _send_async_event(lwip_event_packet_t ** e){ - return _async_queue && xQueueSend(_async_queue, e, portMAX_DELAY) == pdPASS; -} - -static inline bool _prepend_async_event(lwip_event_packet_t ** e){ - return _async_queue && xQueueSendToFront(_async_queue, e, portMAX_DELAY) == pdPASS; -} - -static inline bool _get_async_event(lwip_event_packet_t ** e){ - return _async_queue && xQueueReceive(_async_queue, e, portMAX_DELAY) == pdPASS; -} - -static bool _remove_events_with_arg(void * arg){ - lwip_event_packet_t * first_packet = NULL; - lwip_event_packet_t * packet = NULL; - - if(!_async_queue){ - return false; - } - //figure out which is the first packet so we can keep the order - while(!first_packet){ - if(xQueueReceive(_async_queue, &first_packet, 0) != pdPASS){ - return false; - } - //discard packet if matching - if((int)first_packet->arg == (int)arg){ - free(first_packet); - first_packet = NULL; - //return first packet to the back of the queue - } else if(xQueueSend(_async_queue, &first_packet, portMAX_DELAY) != pdPASS){ - return false; - } - } - - while(xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet){ - if(xQueueReceive(_async_queue, &packet, 0) != pdPASS){ - return false; - } - if((int)packet->arg == (int)arg){ - free(packet); - packet = NULL; - } else if(xQueueSend(_async_queue, &packet, portMAX_DELAY) != pdPASS){ - return false; - } - } - return true; -} - -static void _handle_async_event(lwip_event_packet_t * e){ - if(e->arg == NULL){ - // do nothing when arg is NULL - //ets_printf("event arg == NULL: 0x%08x\n", e->recv.pcb); - } else if(e->event == LWIP_TCP_CLEAR){ - _remove_events_with_arg(e->arg); - } else if(e->event == LWIP_TCP_RECV){ - //ets_printf("-R: 0x%08x\n", e->recv.pcb); - AsyncClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err); - } else if(e->event == LWIP_TCP_FIN){ - //ets_printf("-F: 0x%08x\n", e->fin.pcb); - AsyncClient::_s_fin(e->arg, e->fin.pcb, e->fin.err); - } else if(e->event == LWIP_TCP_SENT){ - //ets_printf("-S: 0x%08x\n", e->sent.pcb); - AsyncClient::_s_sent(e->arg, e->sent.pcb, e->sent.len); - } else if(e->event == LWIP_TCP_POLL){ - //ets_printf("-P: 0x%08x\n", e->poll.pcb); - AsyncClient::_s_poll(e->arg, e->poll.pcb); - } else if(e->event == LWIP_TCP_ERROR){ - //ets_printf("-E: 0x%08x %d\n", e->arg, e->error.err); - AsyncClient::_s_error(e->arg, e->error.err); - } else if(e->event == LWIP_TCP_CONNECTED){ - //ets_printf("C: 0x%08x 0x%08x %d\n", e->arg, e->connected.pcb, e->connected.err); - AsyncClient::_s_connected(e->arg, e->connected.pcb, e->connected.err); - } else if(e->event == LWIP_TCP_ACCEPT){ - //ets_printf("A: 0x%08x 0x%08x\n", e->arg, e->accept.client); - AsyncServer::_s_accepted(e->arg, e->accept.client); - } else if(e->event == LWIP_TCP_DNS){ - //ets_printf("D: 0x%08x %s = %s\n", e->arg, e->dns.name, ipaddr_ntoa(&e->dns.addr)); - AsyncClient::_s_dns_found(e->dns.name, &e->dns.addr, e->arg); - } - free((void*)(e)); -} - -static void _async_service_task(void *pvParameters){ - lwip_event_packet_t * packet = NULL; - for (;;) { - if(_get_async_event(&packet)){ -#if CONFIG_ASYNC_TCP_USE_WDT - if(esp_task_wdt_add(NULL) != ESP_OK){ - log_e("Failed to add async task to WDT"); - } -#endif - _handle_async_event(packet); -#if CONFIG_ASYNC_TCP_USE_WDT - if(esp_task_wdt_delete(NULL) != ESP_OK){ - log_e("Failed to remove loop task from WDT"); - } -#endif - } - } - vTaskDelete(NULL); - _async_service_task_handle = NULL; -} -/* -static void _stop_async_task(){ - if(_async_service_task_handle){ - vTaskDelete(_async_service_task_handle); - _async_service_task_handle = NULL; - } -} -*/ -static bool _start_async_task(){ - if(!_init_async_event_queue()){ - return false; - } - if(!_async_service_task_handle){ - xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, TASK_CONNECTIVITY_PRIO, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); - if(!_async_service_task_handle){ - return false; - } - } - return true; -} - -/* - * LwIP Callbacks - * */ - -static int8_t _tcp_clear_events(void * arg) { - lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_CLEAR; - e->arg = arg; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_connected(void * arg, tcp_pcb * pcb, int8_t err) { - //ets_printf("+C: 0x%08x\n", pcb); - lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_CONNECTED; - e->arg = arg; - e->connected.pcb = pcb; - e->connected.err = err; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_poll(void * arg, struct tcp_pcb * pcb) { - //ets_printf("+P: 0x%08x\n", pcb); - lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_POLL; - e->arg = arg; - e->poll.pcb = pcb; - if (!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) { - lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); - e->arg = arg; - if(pb){ - //ets_printf("+R: 0x%08x\n", pcb); - e->event = LWIP_TCP_RECV; - e->recv.pcb = pcb; - e->recv.pb = pb; - e->recv.err = err; - } else { - //ets_printf("+F: 0x%08x\n", pcb); - e->event = LWIP_TCP_FIN; - e->fin.pcb = pcb; - e->fin.err = err; - //close the PCB in LwIP thread - AsyncClient::_s_lwip_fin(e->arg, e->fin.pcb, e->fin.err); - } - if (!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { - //ets_printf("+S: 0x%08x\n", pcb); - lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_SENT; - e->arg = arg; - e->sent.pcb = pcb; - e->sent.len = len; - if (!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static void _tcp_error(void * arg, int8_t err) { - //ets_printf("+E: 0x%08x\n", arg); - lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_ERROR; - e->arg = arg; - e->error.err = err; - if (!_send_async_event(&e)) { - free((void*)(e)); - } -} - -static void _tcp_dns_found(const char * name, struct ip_addr * ipaddr, void * arg) { - lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); - //ets_printf("+DNS: name=%s ipaddr=0x%08x arg=%x\n", name, ipaddr, arg); - e->event = LWIP_TCP_DNS; - e->arg = arg; - e->dns.name = name; - if (ipaddr) { - memcpy(&e->dns.addr, ipaddr, sizeof(struct ip_addr)); - } else { - memset(&e->dns.addr, 0, sizeof(e->dns.addr)); - } - if (!_send_async_event(&e)) { - free((void*)(e)); - } -} - -//Used to switch out from LwIP thread -static int8_t _tcp_accept(void * arg, AsyncClient * client) { - lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_ACCEPT; - e->arg = arg; - e->accept.client = client; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -/* - * TCP/IP API Calls - * */ - -#include "lwip/priv/tcpip_priv.h" - -typedef struct { - struct tcpip_api_call_data call; - tcp_pcb * pcb; - int8_t closed_slot; - int8_t err; - union { - struct { - const char* data; - size_t size; - uint8_t apiflags; - } write; - size_t received; - struct { - ip_addr_t * addr; - uint16_t port; - tcp_connected_fn cb; - } connect; - struct { - ip_addr_t * addr; - uint16_t port; - } bind; - uint8_t backlog; - }; -} tcp_api_call_t; - -static err_t _tcp_output_api(struct tcpip_api_call_data *api_call_msg){ - tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; - msg->err = ERR_CONN; - if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_output(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_output(tcp_pcb * pcb, int8_t closed_slot) { - if(!pcb){ - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_write_api(struct tcpip_api_call_data *api_call_msg){ - tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; - msg->err = ERR_CONN; - if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); - } - return msg->err; -} - -static esp_err_t _tcp_write(tcp_pcb * pcb, int8_t closed_slot, const char* data, size_t size, uint8_t apiflags) { - if(!pcb){ - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.write.data = data; - msg.write.size = size; - msg.write.apiflags = apiflags; - tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_recved_api(struct tcpip_api_call_data *api_call_msg){ - tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; - msg->err = ERR_CONN; - if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { - msg->err = 0; - tcp_recved(msg->pcb, msg->received); - } - return msg->err; -} - -static esp_err_t _tcp_recved(tcp_pcb * pcb, int8_t closed_slot, size_t len) { - if(!pcb){ - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.received = len; - tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_close_api(struct tcpip_api_call_data *api_call_msg){ - tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; - msg->err = ERR_CONN; - if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_close(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_close(tcp_pcb * pcb, int8_t closed_slot) { - if(!pcb){ - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_abort_api(struct tcpip_api_call_data *api_call_msg){ - tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; - msg->err = ERR_CONN; - if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { - tcp_abort(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_abort(tcp_pcb * pcb, int8_t closed_slot) { - if(!pcb){ - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_connect_api(struct tcpip_api_call_data *api_call_msg){ - tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; - msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); - return msg->err; -} - -static esp_err_t _tcp_connect(tcp_pcb * pcb, int8_t closed_slot, ip_addr_t * addr, uint16_t port, tcp_connected_fn cb) { - if(!pcb){ - return ESP_FAIL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.connect.addr = addr; - msg.connect.port = port; - msg.connect.cb = cb; - tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_bind_api(struct tcpip_api_call_data *api_call_msg){ - tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; - msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); - return msg->err; -} - -static esp_err_t _tcp_bind(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port) { - if(!pcb){ - return ESP_FAIL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = -1; - msg.bind.addr = addr; - msg.bind.port = port; - tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_listen_api(struct tcpip_api_call_data *api_call_msg){ - tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; - msg->err = 0; - msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); - return msg->err; -} - -static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { - if(!pcb){ - return NULL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = -1; - msg.backlog = backlog?backlog:0xFF; - tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); - return msg.pcb; -} - - - -/* - Async TCP Client - */ - -AsyncClient::AsyncClient(tcp_pcb* pcb) -: _connect_cb(0) -, _connect_cb_arg(0) -, _discard_cb(0) -, _discard_cb_arg(0) -, _sent_cb(0) -, _sent_cb_arg(0) -, _error_cb(0) -, _error_cb_arg(0) -, _recv_cb(0) -, _recv_cb_arg(0) -, _pb_cb(0) -, _pb_cb_arg(0) -, _timeout_cb(0) -, _timeout_cb_arg(0) -, _pcb_busy(false) -, _pcb_sent_at(0) -, _ack_pcb(true) -, _rx_last_packet(0) -, _rx_since_timeout(0) -, _ack_timeout(ASYNC_MAX_ACK_TIME) -, _connect_port(0) -, prev(NULL) -, next(NULL) -{ - _pcb = pcb; - _closed_slot = -1; - if(_pcb){ - _allocate_closed_slot(); - _rx_last_packet = millis(); - tcp_arg(_pcb, this); - tcp_recv(_pcb, &_tcp_recv); - tcp_sent(_pcb, &_tcp_sent); - tcp_err(_pcb, &_tcp_error); - tcp_poll(_pcb, &_tcp_poll, 1); - } -} - -AsyncClient::~AsyncClient(){ - if(_pcb) { - _close(); - } - _free_closed_slot(); -} - -/* - * Operators - * */ - -AsyncClient& AsyncClient::operator=(const AsyncClient& other){ - if (_pcb) { - _close(); - } - - _pcb = other._pcb; - _closed_slot = other._closed_slot; - if (_pcb) { - _rx_last_packet = millis(); - tcp_arg(_pcb, this); - tcp_recv(_pcb, &_tcp_recv); - tcp_sent(_pcb, &_tcp_sent); - tcp_err(_pcb, &_tcp_error); - tcp_poll(_pcb, &_tcp_poll, 1); - } - return *this; -} - -bool AsyncClient::operator==(const AsyncClient &other) { - return _pcb == other._pcb; -} - -AsyncClient & AsyncClient::operator+=(const AsyncClient &other) { - if(next == NULL){ - next = (AsyncClient*)(&other); - next->prev = this; - } else { - AsyncClient *c = next; - while(c->next != NULL) { - c = c->next; - } - c->next =(AsyncClient*)(&other); - c->next->prev = c; - } - return *this; -} - -/* - * Callback Setters - * */ - -void AsyncClient::onConnect(AcConnectHandler cb, void* arg){ - _connect_cb = cb; - _connect_cb_arg = arg; -} - -void AsyncClient::onDisconnect(AcConnectHandler cb, void* arg){ - _discard_cb = cb; - _discard_cb_arg = arg; -} - -void AsyncClient::onAck(AcAckHandler cb, void* arg){ - _sent_cb = cb; - _sent_cb_arg = arg; -} - -void AsyncClient::onError(AcErrorHandler cb, void* arg){ - _error_cb = cb; - _error_cb_arg = arg; -} - -void AsyncClient::onData(AcDataHandler cb, void* arg){ - _recv_cb = cb; - _recv_cb_arg = arg; -} - -void AsyncClient::onPacket(AcPacketHandler cb, void* arg){ - _pb_cb = cb; - _pb_cb_arg = arg; -} - -void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg){ - _timeout_cb = cb; - _timeout_cb_arg = arg; -} - -void AsyncClient::onPoll(AcConnectHandler cb, void* arg){ - _poll_cb = cb; - _poll_cb_arg = arg; -} - -/* - * Main Public Methods - * */ - -bool AsyncClient::connect(IPAddress ip, uint16_t port){ - if (_pcb){ - log_w("already connected, state %d", _pcb->state); - return false; - } - if(!_start_async_task()){ - log_e("failed to start task"); - return false; - } - - ip_addr_t addr; - addr.type = IPADDR_TYPE_V4; - addr.u_addr.ip4.addr = ip; - - tcp_pcb* pcb = tcp_new_ip_type(IPADDR_TYPE_V4); - if (!pcb){ - log_e("pcb == NULL"); - return false; - } - - tcp_arg(pcb, this); - tcp_err(pcb, &_tcp_error); - tcp_recv(pcb, &_tcp_recv); - tcp_sent(pcb, &_tcp_sent); - tcp_poll(pcb, &_tcp_poll, 1); - //_tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); - _tcp_connect(pcb, _closed_slot, &addr, port,(tcp_connected_fn)&_tcp_connected); - return true; -} - -bool AsyncClient::connect(const char* host, uint16_t port){ - ip_addr_t addr; - - if(!_start_async_task()){ - log_e("failed to start task"); - return false; - } - - err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); - if(err == ERR_OK) { - return connect(IPAddress(addr.u_addr.ip4.addr), port); - } else if(err == ERR_INPROGRESS) { - _connect_port = port; - return true; - } - log_e("error: %d", err); - return false; -} - -void AsyncClient::close(bool now){ - if(_pcb){ - _tcp_recved(_pcb, _closed_slot, _rx_ack_len); - } - _close(); -} - -int8_t AsyncClient::abort(){ - if(_pcb) { - _tcp_abort(_pcb, _closed_slot ); - _pcb = NULL; - } - return ERR_ABRT; -} - -size_t AsyncClient::space(){ - if((_pcb != NULL) && (_pcb->state == 4)){ - return tcp_sndbuf(_pcb); - } - return 0; -} - -size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { - if(!_pcb || size == 0 || data == NULL) { - return 0; - } - size_t room = space(); - if(!room) { - return 0; - } - size_t will_send = (room < size) ? room : size; - int8_t err = ERR_OK; - err = _tcp_write(_pcb, _closed_slot, data, will_send, apiflags); - if(err != ERR_OK) { - return 0; - } - return will_send; -} - -bool AsyncClient::send(){ - int8_t err = ERR_OK; - err = _tcp_output(_pcb, _closed_slot); - if(err == ERR_OK){ - _pcb_busy = true; - _pcb_sent_at = millis(); - return true; - } - return false; -} - -size_t AsyncClient::ack(size_t len){ - if(len > _rx_ack_len) - len = _rx_ack_len; - if(len){ - _tcp_recved(_pcb, _closed_slot, len); - } - _rx_ack_len -= len; - return len; -} - -void AsyncClient::ackPacket(struct pbuf * pb){ - if(!pb){ - return; - } - _tcp_recved(_pcb, _closed_slot, pb->len); - pbuf_free(pb); -} - -/* - * Main Private Methods - * */ - -int8_t AsyncClient::_close(){ - //ets_printf("X: 0x%08x\n", (uint32_t)this); - int8_t err = ERR_OK; - if(_pcb) { - //log_i(""); - tcp_arg(_pcb, NULL); - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - _tcp_clear_events(this); - err = _tcp_close(_pcb, _closed_slot); - if(err != ERR_OK) { - err = abort(); - } - _pcb = NULL; - if(_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - } - return err; -} - -void AsyncClient::_allocate_closed_slot(){ - xSemaphoreTake(_slots_lock, portMAX_DELAY); - uint32_t closed_slot_min_index = 0; - for (int i = 0; i < _number_of_closed_slots; ++ i) { - if ((_closed_slot == -1 || _closed_slots[i] <= closed_slot_min_index) && _closed_slots[i] != 0) { - closed_slot_min_index = _closed_slots[i]; - _closed_slot = i; - } - } - if (_closed_slot != -1) { - _closed_slots[_closed_slot] = 0; - } - xSemaphoreGive(_slots_lock); -} - -void AsyncClient::_free_closed_slot(){ - if (_closed_slot != -1) { - _closed_slots[_closed_slot] = _closed_index; - _closed_slot = -1; - ++ _closed_index; - } -} - -/* - * Private Callbacks - * */ - -int8_t AsyncClient::_connected(void* pcb, int8_t err){ - _pcb = reinterpret_cast(pcb); - if(_pcb){ - _rx_last_packet = millis(); - _pcb_busy = false; -// tcp_recv(_pcb, &_tcp_recv); -// tcp_sent(_pcb, &_tcp_sent); -// tcp_poll(_pcb, &_tcp_poll, 1); - } - if(_connect_cb) { - _connect_cb(_connect_cb_arg, this); - } - return ERR_OK; -} - -void AsyncClient::_error(int8_t err) { - if(_pcb){ - tcp_arg(_pcb, NULL); - if(_pcb->state == LISTEN) { - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - } - _pcb = NULL; - } - if(_error_cb) { - _error_cb(_error_cb_arg, this, err); - } - if(_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } -} - -//In LwIP Thread -int8_t AsyncClient::_lwip_fin(tcp_pcb* pcb, int8_t err) { - if(!_pcb || pcb != _pcb){ - log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - return ERR_OK; - } - tcp_arg(_pcb, NULL); - if(_pcb->state == LISTEN) { - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - } - if(tcp_close(_pcb) != ERR_OK) { - tcp_abort(_pcb); - } - _free_closed_slot(); - _pcb = NULL; - return ERR_OK; -} - -//In Async Thread -int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) { - _tcp_clear_events(this); - if(_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - return ERR_OK; -} - -int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { - _rx_last_packet = millis(); - //log_i("%u", len); - _pcb_busy = false; - if(_sent_cb) { - _sent_cb(_sent_cb_arg, this, len, (millis() - _pcb_sent_at)); - } - return ERR_OK; -} - -int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { - while(pb != NULL) { - _rx_last_packet = millis(); - //we should not ack before we assimilate the data - _ack_pcb = true; - pbuf *b = pb; - pb = b->next; - b->next = NULL; - if(_pb_cb){ - _pb_cb(_pb_cb_arg, this, b); - } else { - if(_recv_cb) { - _recv_cb(_recv_cb_arg, this, b->payload, b->len); - } - if(!_ack_pcb) { - _rx_ack_len += b->len; - } else if(_pcb) { - _tcp_recved(_pcb, _closed_slot, b->len); - } - pbuf_free(b); - } - } - return ERR_OK; -} - -int8_t AsyncClient::_poll(tcp_pcb* pcb){ - if(!_pcb){ - log_w("pcb is NULL"); - return ERR_OK; - } - if(pcb != _pcb){ - log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - return ERR_OK; - } - - uint32_t now = millis(); - - // ACK Timeout - if(_pcb_busy && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout){ - _pcb_busy = false; - log_w("ack timeout %d", pcb->state); - if(_timeout_cb) - _timeout_cb(_timeout_cb_arg, this, (now - _pcb_sent_at)); - return ERR_OK; - } - // RX Timeout - if(_rx_since_timeout && (now - _rx_last_packet) >= (_rx_since_timeout * 1000)){ - log_w("rx timeout %d", pcb->state); - _close(); - return ERR_OK; - } - // Everything is fine - if(_poll_cb) { - _poll_cb(_poll_cb_arg, this); - } - return ERR_OK; -} - -void AsyncClient::_dns_found(struct ip_addr *ipaddr){ - if(ipaddr && ipaddr->u_addr.ip4.addr){ - connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port); - } else { - if(_error_cb) { - _error_cb(_error_cb_arg, this, -55); - } - if(_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - } -} - -/* - * Public Helper Methods - * */ - -void AsyncClient::stop() { - close(false); -} - -bool AsyncClient::free(){ - if(!_pcb) { - return true; - } - if(_pcb->state == 0 || _pcb->state > 4) { - return true; - } - return false; -} - -size_t AsyncClient::write(const char* data) { - if(data == NULL) { - return 0; - } - return write(data, strlen(data)); -} - -size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) { - size_t will_send = add(data, size, apiflags); - if(!will_send || !send()) { - return 0; - } - return will_send; -} - -void AsyncClient::setRxTimeout(uint32_t timeout){ - _rx_since_timeout = timeout; -} - -uint32_t AsyncClient::getRxTimeout(){ - return _rx_since_timeout; -} - -uint32_t AsyncClient::getAckTimeout(){ - return _ack_timeout; -} - -void AsyncClient::setAckTimeout(uint32_t timeout){ - _ack_timeout = timeout; -} - -void AsyncClient::setNoDelay(bool nodelay){ - if(!_pcb) { - return; - } - if(nodelay) { - tcp_nagle_disable(_pcb); - } else { - tcp_nagle_enable(_pcb); - } -} - -bool AsyncClient::getNoDelay(){ - if(!_pcb) { - return false; - } - return tcp_nagle_disabled(_pcb); -} - -uint16_t AsyncClient::getMss(){ - if(!_pcb) { - return 0; - } - return tcp_mss(_pcb); -} - -uint32_t AsyncClient::getRemoteAddress() { - if(!_pcb) { - return 0; - } - return _pcb->remote_ip.u_addr.ip4.addr; -} - -uint16_t AsyncClient::getRemotePort() { - if(!_pcb) { - return 0; - } - return _pcb->remote_port; -} - -uint32_t AsyncClient::getLocalAddress() { - if(!_pcb) { - return 0; - } - return _pcb->local_ip.u_addr.ip4.addr; -} - -uint16_t AsyncClient::getLocalPort() { - if(!_pcb) { - return 0; - } - return _pcb->local_port; -} - -IPAddress AsyncClient::remoteIP() { - return IPAddress(getRemoteAddress()); -} - -uint16_t AsyncClient::remotePort() { - return getRemotePort(); -} - -IPAddress AsyncClient::localIP() { - return IPAddress(getLocalAddress()); -} - -uint16_t AsyncClient::localPort() { - return getLocalPort(); -} - -uint8_t AsyncClient::state() { - if(!_pcb) { - return 0; - } - return _pcb->state; -} - -bool AsyncClient::connected(){ - if (!_pcb) { - return false; - } - return _pcb->state == 4; -} - -bool AsyncClient::connecting(){ - if (!_pcb) { - return false; - } - return _pcb->state > 0 && _pcb->state < 4; -} - -bool AsyncClient::disconnecting(){ - if (!_pcb) { - return false; - } - return _pcb->state > 4 && _pcb->state < 10; -} - -bool AsyncClient::disconnected(){ - if (!_pcb) { - return true; - } - return _pcb->state == 0 || _pcb->state == 10; -} - -bool AsyncClient::freeable(){ - if (!_pcb) { - return true; - } - return _pcb->state == 0 || _pcb->state > 4; -} - -bool AsyncClient::canSend(){ - return space() > 0; -} - -const char * AsyncClient::errorToString(int8_t error){ - switch(error){ - case ERR_OK: return "OK"; - case ERR_MEM: return "Out of memory error"; - case ERR_BUF: return "Buffer error"; - case ERR_TIMEOUT: return "Timeout"; - case ERR_RTE: return "Routing problem"; - case ERR_INPROGRESS: return "Operation in progress"; - case ERR_VAL: return "Illegal value"; - case ERR_WOULDBLOCK: return "Operation would block"; - case ERR_USE: return "Address in use"; - case ERR_ALREADY: return "Already connected"; - case ERR_CONN: return "Not connected"; - case ERR_IF: return "Low-level netif error"; - case ERR_ABRT: return "Connection aborted"; - case ERR_RST: return "Connection reset"; - case ERR_CLSD: return "Connection closed"; - case ERR_ARG: return "Illegal argument"; - case -55: return "DNS failed"; - default: return "UNKNOWN"; - } -} - -const char * AsyncClient::stateToString(){ - switch(state()){ - case 0: return "Closed"; - case 1: return "Listen"; - case 2: return "SYN Sent"; - case 3: return "SYN Received"; - case 4: return "Established"; - case 5: return "FIN Wait 1"; - case 6: return "FIN Wait 2"; - case 7: return "Close Wait"; - case 8: return "Closing"; - case 9: return "Last ACK"; - case 10: return "Time Wait"; - default: return "UNKNOWN"; - } -} - -/* - * Static Callbacks (LwIP C2C++ interconnect) - * */ - -void AsyncClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg){ - reinterpret_cast(arg)->_dns_found(ipaddr); -} - -int8_t AsyncClient::_s_poll(void * arg, struct tcp_pcb * pcb) { - return reinterpret_cast(arg)->_poll(pcb); -} - -int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) { - return reinterpret_cast(arg)->_recv(pcb, pb, err); -} - -int8_t AsyncClient::_s_fin(void * arg, struct tcp_pcb * pcb, int8_t err) { - return reinterpret_cast(arg)->_fin(pcb, err); -} - -int8_t AsyncClient::_s_lwip_fin(void * arg, struct tcp_pcb * pcb, int8_t err) { - return reinterpret_cast(arg)->_lwip_fin(pcb, err); -} - -int8_t AsyncClient::_s_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { - return reinterpret_cast(arg)->_sent(pcb, len); -} - -void AsyncClient::_s_error(void * arg, int8_t err) { - reinterpret_cast(arg)->_error(err); -} - -int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){ - return reinterpret_cast(arg)->_connected(pcb, err); -} - -/* - Async TCP Server - */ - -AsyncServer::AsyncServer(IPAddress addr, uint16_t port) -: _port(port) -, _addr(addr) -, _noDelay(false) -, _pcb(0) -, _connect_cb(0) -, _connect_cb_arg(0) -{} - -AsyncServer::AsyncServer(uint16_t port) -: _port(port) -, _addr((uint32_t) IPADDR_ANY) -, _noDelay(false) -, _pcb(0) -, _connect_cb(0) -, _connect_cb_arg(0) -{} - -AsyncServer::~AsyncServer(){ - end(); -} - -void AsyncServer::onClient(AcConnectHandler cb, void* arg){ - _connect_cb = cb; - _connect_cb_arg = arg; -} - -void AsyncServer::begin(){ - if(_pcb) { - return; - } - - if(!_start_async_task()){ - log_e("failed to start task"); - return; - } - int8_t err; - _pcb = tcp_new_ip_type(IPADDR_TYPE_V4); - if (!_pcb){ - log_e("_pcb == NULL"); - return; - } - - ip_addr_t local_addr; - local_addr.type = IPADDR_TYPE_V4; - local_addr.u_addr.ip4.addr = (uint32_t) _addr; - err = _tcp_bind(_pcb, &local_addr, _port); - - if (err != ERR_OK) { - _tcp_close(_pcb, -1); - log_e("bind error: %d", err); - return; - } - - static uint8_t backlog = 5; - _pcb = _tcp_listen_with_backlog(_pcb, backlog); - if (!_pcb) { - log_e("listen_pcb == NULL"); - return; - } - tcp_arg(_pcb, (void*) this); - tcp_accept(_pcb, &_s_accept); -} - -void AsyncServer::end(){ - if(_pcb){ - tcp_arg(_pcb, NULL); - tcp_accept(_pcb, NULL); - if(tcp_close(_pcb) != ERR_OK){ - _tcp_abort(_pcb, -1); - } - _pcb = NULL; - } -} - -//runs on LwIP thread -int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ - //ets_printf("+A: 0x%08x\n", pcb); - if(_connect_cb){ - AsyncClient *c = new AsyncClient(pcb); - if(c){ - c->setNoDelay(_noDelay); - return _tcp_accept(this, c); - } - } - if(tcp_close(pcb) != ERR_OK){ - tcp_abort(pcb); - } - log_e("FAIL"); - return ERR_OK; -} - -int8_t AsyncServer::_accepted(AsyncClient* client){ - if(_connect_cb){ - _connect_cb(_connect_cb_arg, client); - } - return ERR_OK; -} - -void AsyncServer::setNoDelay(bool nodelay){ - _noDelay = nodelay; -} - -bool AsyncServer::getNoDelay(){ - return _noDelay; -} - -uint8_t AsyncServer::status(){ - if (!_pcb) { - return 0; - } - return _pcb->state; -} - -int8_t AsyncServer::_s_accept(void * arg, tcp_pcb * pcb, int8_t err){ - return reinterpret_cast(arg)->_accept(pcb, err); -} - -int8_t AsyncServer::_s_accepted(void *arg, AsyncClient* client){ - return reinterpret_cast(arg)->_accepted(client); -} diff --git a/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h deleted file mode 100644 index b89fb1224..000000000 --- a/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - Asynchronous TCP library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef ASYNCTCP_H_ -#define ASYNCTCP_H_ - -#include "IPAddress.h" -#include "sdkconfig.h" -#include -extern "C" { - #include "freertos/semphr.h" - #include "lwip/pbuf.h" -} - -#include "../../../system_settings.h" -#include "../../../devboard/hal/hal.h" - -//If core is not defined, then we are running in Arduino or PIO -#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE -#define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE //any available core -#define CONFIG_ASYNC_TCP_USE_WDT 0 //if enabled, adds between 33us and 200us per event -#endif - -class AsyncClient; - -#define ASYNC_MAX_ACK_TIME 5000 -#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given) -#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react. - -typedef std::function AcConnectHandler; -typedef std::function AcAckHandler; -typedef std::function AcErrorHandler; -typedef std::function AcDataHandler; -typedef std::function AcPacketHandler; -typedef std::function AcTimeoutHandler; - -struct tcp_pcb; -struct ip_addr; - -class AsyncClient { - public: - AsyncClient(tcp_pcb* pcb = 0); - ~AsyncClient(); - - AsyncClient & operator=(const AsyncClient &other); - AsyncClient & operator+=(const AsyncClient &other); - - bool operator==(const AsyncClient &other); - - bool operator!=(const AsyncClient &other) { - return !(*this == other); - } - bool connect(IPAddress ip, uint16_t port); - bool connect(const char* host, uint16_t port); - void close(bool now = false); - void stop(); - int8_t abort(); - bool free(); - - bool canSend();//ack is not pending - size_t space();//space available in the TCP window - size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending - bool send();//send all data added with the method above - - //write equals add()+send() - size_t write(const char* data); - size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true - - uint8_t state(); - bool connecting(); - bool connected(); - bool disconnecting(); - bool disconnected(); - bool freeable();//disconnected or disconnecting - - uint16_t getMss(); - - uint32_t getRxTimeout(); - void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds - - uint32_t getAckTimeout(); - void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds - - void setNoDelay(bool nodelay); - bool getNoDelay(); - - uint32_t getRemoteAddress(); - uint16_t getRemotePort(); - uint32_t getLocalAddress(); - uint16_t getLocalPort(); - - //compatibility - IPAddress remoteIP(); - uint16_t remotePort(); - IPAddress localIP(); - uint16_t localPort(); - - void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect - void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected - void onAck(AcAckHandler cb, void* arg = 0); //ack received - void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error - void onData(AcDataHandler cb, void* arg = 0); //data received (called if onPacket is not used) - void onPacket(AcPacketHandler cb, void* arg = 0); //data received - void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout - void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected - - void ackPacket(struct pbuf * pb);//ack pbuf from onPacket - size_t ack(size_t len); //ack data that you have not acked using the method below - void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData - - const char * errorToString(int8_t error); - const char * stateToString(); - - //Do not use any of the functions below! - static int8_t _s_poll(void *arg, struct tcp_pcb *tpcb); - static int8_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, int8_t err); - static int8_t _s_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); - static int8_t _s_lwip_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); - static void _s_error(void *arg, int8_t err); - static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); - static int8_t _s_connected(void* arg, void* tpcb, int8_t err); - static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); - - int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); - tcp_pcb * pcb(){ return _pcb; } - - protected: - tcp_pcb* _pcb; - int8_t _closed_slot; - - AcConnectHandler _connect_cb; - void* _connect_cb_arg; - AcConnectHandler _discard_cb; - void* _discard_cb_arg; - AcAckHandler _sent_cb; - void* _sent_cb_arg; - AcErrorHandler _error_cb; - void* _error_cb_arg; - AcDataHandler _recv_cb; - void* _recv_cb_arg; - AcPacketHandler _pb_cb; - void* _pb_cb_arg; - AcTimeoutHandler _timeout_cb; - void* _timeout_cb_arg; - AcConnectHandler _poll_cb; - void* _poll_cb_arg; - - bool _pcb_busy; - uint32_t _pcb_sent_at; - bool _ack_pcb; - uint32_t _rx_ack_len; - uint32_t _rx_last_packet; - uint32_t _rx_since_timeout; - uint32_t _ack_timeout; - uint16_t _connect_port; - - int8_t _close(); - void _free_closed_slot(); - void _allocate_closed_slot(); - int8_t _connected(void* pcb, int8_t err); - void _error(int8_t err); - int8_t _poll(tcp_pcb* pcb); - int8_t _sent(tcp_pcb* pcb, uint16_t len); - int8_t _fin(tcp_pcb* pcb, int8_t err); - int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); - void _dns_found(struct ip_addr *ipaddr); - - public: - AsyncClient* prev; - AsyncClient* next; -}; - -class AsyncServer { - public: - AsyncServer(IPAddress addr, uint16_t port); - AsyncServer(uint16_t port); - ~AsyncServer(); - void onClient(AcConnectHandler cb, void* arg); - void begin(); - void end(); - void setNoDelay(bool nodelay); - bool getNoDelay(); - uint8_t status(); - - //Do not use any of the functions below! - static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); - static int8_t _s_accepted(void *arg, AsyncClient* client); - - protected: - uint16_t _port; - IPAddress _addr; - bool _noDelay; - tcp_pcb* _pcb; - AcConnectHandler _connect_cb; - void* _connect_cb_arg; - - int8_t _accept(tcp_pcb* newpcb, int8_t err); - int8_t _accepted(AsyncClient* client); -}; - - -#endif /* ASYNCTCP_H_ */ From f6fa4540a68a3d4007a0580826e9f794010bce46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 19 Dec 2024 19:55:31 +0200 Subject: [PATCH 078/225] Change references to AsyncTCP library --- Software/src/devboard/webserver/webserver.h | 2 +- Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h | 2 +- .../lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h | 2 +- .../src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h | 2 +- .../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h index a75ef8fb6..86b5a763a 100644 --- a/Software/src/devboard/webserver/webserver.h +++ b/Software/src/devboard/webserver/webserver.h @@ -6,7 +6,7 @@ #include "../../include.h" #include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h" -#include "../../lib/me-no-dev-AsyncTCP/src/AsyncTCP.h" +#include "../../lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h" #include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" diff --git a/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h b/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h index f8770a076..48833d99c 100644 --- a/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h +++ b/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h @@ -64,7 +64,7 @@ _____ _ _ ___ _____ _ #include "Update.h" #include "StreamString.h" #if ELEGANTOTA_USE_ASYNC_WEBSERVER == 1 - #include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" + #include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #include "../../me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #define ELEGANTOTA_WEBSERVER AsyncWebServer #else diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h index d3d1b1d4f..94a0c51ea 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h @@ -22,7 +22,7 @@ #include #ifdef ESP32 -#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" +#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #define SSE_MAX_QUEUED_MESSAGES 32 #else #include diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h index 747399b8d..2ef8f9ec5 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h @@ -23,7 +23,7 @@ #include #ifdef ESP32 -#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" +#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #define WS_MAX_QUEUED_MESSAGES 32 #else #include diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h index 664c0a5cf..7731a14ca 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h @@ -30,10 +30,10 @@ #ifdef ESP32 #include -#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" +#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #elif defined(ESP8266) #include -#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" +#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #else #error Platform not supported #endif From 9cada8054082cfa27ed6469c0eb8379ac66fdd60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 19 Dec 2024 20:11:57 +0200 Subject: [PATCH 079/225] Update Readme which library used --- README.md | 2 +- .../lib/mathieucarbou-AsyncTCP/.clang-format | 22 -------------- .../mathieucarbou-AsyncTCP/.clang-format copy | 22 -------------- .../src/lib/mathieucarbou-AsyncTCP/.gitignore | 6 ---- .../mathieucarbou-AsyncTCP/.gitpod.Dockerfile | 2 -- .../lib/mathieucarbou-AsyncTCP/.gitpod.yml | 9 ------ .../mathieucarbou-AsyncTCP/Kconfig.projbuild | 30 ------------------- .../arduino-cli-dev.yaml | 25 ---------------- .../mathieucarbou-AsyncTCP/arduino-cli.yaml | 25 ---------------- 9 files changed, 1 insertion(+), 142 deletions(-) delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.clang-format delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.clang-format copy delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.gitignore delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.Dockerfile delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.yml delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/Kconfig.projbuild delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli-dev.yaml delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli.yaml diff --git a/README.md b/README.md index 3d86f1202..c2d9630c3 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ This code uses the following excellent libraries: - [eModbus/eModbus](https://github.com/eModbus/eModbus) MIT-License - [knolleary/pubsubclient](https://github.com/knolleary/pubsubclient) MIT-License - [mackelec/SerialDataLink](https://github.com/mackelec/SerialDataLink) -- [me-no-dev/AsyncTCP](https://github.com/me-no-dev/AsyncTCP) LGPL-3.0 license +- [mathieucarbou/AsyncTCP](https://github.com/mathieucarbou/AsyncTCP) LGPL-3.0 license - [me-no-dev/ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) - [miwagner/ESP32-Arduino-CAN](https://github.com/miwagner/ESP32-Arduino-CAN/) MIT-License - [pierremolinaro/acan2515](https://github.com/pierremolinaro/acan2515) MIT-License diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format b/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format deleted file mode 100644 index 63f29c0be..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format +++ /dev/null @@ -1,22 +0,0 @@ -Language: Cpp -BasedOnStyle: LLVM - -AccessModifierOffset: -2 -AlignConsecutiveMacros: true -AllowAllArgumentsOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortIfStatementsOnASingleLine: false -AllowShortLambdasOnASingleLine: Inline -BinPackArguments: false -ColumnLimit: 0 -ContinuationIndentWidth: 2 -FixNamespaceComments: false -IndentAccessModifiers: true -IndentCaseLabels: true -IndentPPDirectives: BeforeHash -IndentWidth: 2 -NamespaceIndentation: All -PointerAlignment: Left -ReferenceAlignment: Left -TabWidth: 2 -UseTab: Never diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format copy b/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format copy deleted file mode 100644 index 63f29c0be..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/.clang-format copy +++ /dev/null @@ -1,22 +0,0 @@ -Language: Cpp -BasedOnStyle: LLVM - -AccessModifierOffset: -2 -AlignConsecutiveMacros: true -AllowAllArgumentsOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortIfStatementsOnASingleLine: false -AllowShortLambdasOnASingleLine: Inline -BinPackArguments: false -ColumnLimit: 0 -ContinuationIndentWidth: 2 -FixNamespaceComments: false -IndentAccessModifiers: true -IndentCaseLabels: true -IndentPPDirectives: BeforeHash -IndentWidth: 2 -NamespaceIndentation: All -PointerAlignment: Left -ReferenceAlignment: Left -TabWidth: 2 -UseTab: Never diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.gitignore b/Software/src/lib/mathieucarbou-AsyncTCP/.gitignore deleted file mode 100644 index 18584e8ec..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.DS_Store -.lh -/.pio -/.vscode - -/logs diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.Dockerfile b/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.Dockerfile deleted file mode 100644 index 29eeb4357..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM gitpod/workspace-python-3.11 -USER gitpod diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.yml b/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.yml deleted file mode 100644 index 2f8a4431c..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/.gitpod.yml +++ /dev/null @@ -1,9 +0,0 @@ -tasks: - - command: pip install --upgrade pip && pip install -U platformio && platformio run - -image: - file: .gitpod.Dockerfile - -vscode: - extensions: - - shardulm94.trailing-spaces diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/Kconfig.projbuild b/Software/src/lib/mathieucarbou-AsyncTCP/Kconfig.projbuild deleted file mode 100644 index 177492645..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/Kconfig.projbuild +++ /dev/null @@ -1,30 +0,0 @@ -menu "AsyncTCP Configuration" - -choice ASYNC_TCP_RUNNING_CORE - bool "Core on which AsyncTCP's thread is running" - default ASYNC_TCP_RUN_CORE1 - help - Select on which core AsyncTCP is running - - config ASYNC_TCP_RUN_CORE0 - bool "CORE 0" - config ASYNC_TCP_RUN_CORE1 - bool "CORE 1" - config ASYNC_TCP_RUN_NO_AFFINITY - bool "BOTH" - -endchoice - -config ASYNC_TCP_RUNNING_CORE - int - default 0 if ASYNC_TCP_RUN_CORE0 - default 1 if ASYNC_TCP_RUN_CORE1 - default -1 if ASYNC_TCP_RUN_NO_AFFINITY - -config ASYNC_TCP_USE_WDT - bool "Enable WDT for the AsyncTCP task" - default "y" - help - Enable WDT for the AsyncTCP task, so it will trigger if a handler is locking the thread. - -endmenu diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli-dev.yaml b/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli-dev.yaml deleted file mode 100644 index 174df7a13..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli-dev.yaml +++ /dev/null @@ -1,25 +0,0 @@ -board_manager: - additional_urls: - - https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json -directories: - builtin.libraries: ./src/ -build_cache: - compilations_before_purge: 10 - ttl: 720h0m0s -daemon: - port: "50051" -library: - enable_unsafe_install: false -logging: - file: "" - format: text - level: info -metrics: - addr: :9090 - enabled: true -output: - no_color: false -sketch: - always_export_binaries: false -updater: - enable_notification: true diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli.yaml b/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli.yaml deleted file mode 100644 index 42365f42c..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/arduino-cli.yaml +++ /dev/null @@ -1,25 +0,0 @@ -board_manager: - additional_urls: - - https://espressif.github.io/arduino-esp32/package_esp32_index.json -directories: - builtin.libraries: ./src/ -build_cache: - compilations_before_purge: 10 - ttl: 720h0m0s -daemon: - port: "50051" -library: - enable_unsafe_install: false -logging: - file: "" - format: text - level: info -metrics: - addr: :9090 - enabled: true -output: - no_color: false -sketch: - always_export_binaries: false -updater: - enable_notification: true From 75f270a6d970aa58c05be75bae634399d0ee815c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 20 Dec 2024 00:43:26 +0200 Subject: [PATCH 080/225] Add groups 83, 84 and 90 --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 105 +++++++++++++++---- 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 9a9f347e9..2791e0b8a 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -38,11 +38,13 @@ CAN_frame LEAF_1D4 = {.FD = false, .ID = 0x1D4, .data = {0x6E, 0x6E, 0x00, 0x04, 0x07, 0x46, 0xE0, 0x44}}; // Active polling messages +uint8_t PIDgroups[] = {0x01, 0x02, 0x04, 0x83, 0x84, 0x90}; +uint8_t PIDindex = 0; CAN_frame LEAF_GROUP_REQUEST = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x79B, - .data = {2, 0x21, 1, 0, 0, 0, 0, 0}}; + .data = {0x02, 0x21, PIDgroups[0], 0, 0, 0, 0, 0}}; CAN_frame LEAF_NEXT_LINE_REQUEST = {.FD = false, .ext_ID = false, .DLC = 8, @@ -107,7 +109,6 @@ static bool battery_Batt_Heater_Mail_Send_Request = false; //Stores info when a // Nissan LEAF battery data from polled CAN messages static uint8_t battery_request_idx = 0; static uint8_t group_7bb = 0; -static uint8_t group = 1; static bool stop_battery_query = true; static uint8_t hold_off_with_polling_10seconds = 10; static uint16_t battery_cell_voltages[97]; //array with all the cellvoltages @@ -124,7 +125,9 @@ static uint16_t battery_temp_raw_max = 0; static uint16_t battery_temp_raw_min = 0; static int16_t battery_temp_polled_max = 0; static int16_t battery_temp_polled_min = 0; - +static uint8_t BatterySerialNumber[15] = {0}; // Stores raw HEX values for ASCII chars +static uint8_t BatteryPartNumber[7] = {0}; // Stores raw HEX values for ASCII chars +static uint8_t BMSIDcode[8] = {0}; #ifdef DOUBLE_BATTERY static uint8_t LEAF_battery2_Type = ZE0_BATTERY; static bool battery2_can_alive = false; @@ -598,20 +601,16 @@ void receive_can_battery2(CAN_frame rx_frame) { hold_off_with_polling_10seconds = 10; //Polling is paused for 100s break; case 0x7BB: - //First check which group data we are getting - if (rx_frame.data.u8[0] == 0x10) { //First message of a group - battery2_group_7bb = rx_frame.data.u8[3]; - if (battery2_group_7bb != 1 && battery2_group_7bb != 2 && - battery2_group_7bb != 4) { //We are only interested in groups 1,2 and 4 - break; - } - } if (stop_battery_query) { //Leafspy/Service request is active, stop our own polling break; } - transmit_can(&LEAF_NEXT_LINE_REQUEST, can_config.battery_double); + //First check which group data we are getting + if (rx_frame.data.u8[0] == 0x10) { //First message of a group + battery2_group_7bb = rx_frame.data.u8[3]; + transmit_can(&LEAF_NEXT_LINE_REQUEST, can_config.battery_double); + } if (battery2_group_7bb == 1) //High precision SOC, Current, voltages etc. { @@ -845,7 +844,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; case 0x7BB: - // This section checks if we are doing a SOH reset towards BMS + // This section checks if we are doing a SOH reset towards BMS. If we do, all 7BB handling is halted if (stateMachineClearSOH < 255) { //Intercept the messages based on state machine if (rx_frame.data.u8[0] == 0x06) { // Incoming challenge data! @@ -860,18 +859,16 @@ void receive_can_battery(CAN_frame rx_frame) { break; } + if (stop_battery_query) { //Leafspy is active, stop our own polling + break; + } + //First check which group data we are getting if (rx_frame.data.u8[0] == 0x10) { //First message of a group group_7bb = rx_frame.data.u8[3]; - if (group_7bb != 1 && group_7bb != 2 && group_7bb != 4) { //We are only interested in groups 1,2 and 4 - break; - } - } - if (stop_battery_query) { //Leafspy is active, stop our own polling - break; + transmit_can(&LEAF_NEXT_LINE_REQUEST, can_config.battery); //Request the next frame for the group } - transmit_can(&LEAF_NEXT_LINE_REQUEST, can_config.battery); //Request the next frame for the group if (group_7bb == 1) //High precision SOC, Current, voltages etc. { @@ -991,6 +988,66 @@ void receive_can_battery(CAN_frame rx_frame) { } } + if (group_7bb == 0x83) //BatteryPartNumber + { + if (rx_frame.data.u8[0] == 0x10) { //First frame (101A6183334E4B32) + BatteryPartNumber[0] = rx_frame.data.u8[4]; + BatteryPartNumber[1] = rx_frame.data.u8[5]; + BatteryPartNumber[2] = rx_frame.data.u8[6]; + BatteryPartNumber[3] = rx_frame.data.u8[7]; + } + if (rx_frame.data.u8[0] == 0x21) { //Second frame (2141524205170000) + BatteryPartNumber[4] = rx_frame.data.u8[1]; + BatteryPartNumber[5] = rx_frame.data.u8[2]; + BatteryPartNumber[6] = rx_frame.data.u8[3]; + } + if (rx_frame.data.u8[0] == 0x22) { //Third frame (2200000002101311) + } + + if (rx_frame.data.u8[0] == 0x23) { //Fourth frame (23000000000080FF) + } + } + if (group_7bb == 0x84) { //BatterySerialNumber + if (rx_frame.data.u8[0] == 0x10) { //First frame (10 16 61 84 32 33 30 55) + BatterySerialNumber[0] = rx_frame.data.u8[7]; + } + if (rx_frame.data.u8[0] == 0x21) { //Second frame (21 4B 31 31 39 32 45 30) + BatterySerialNumber[1] = rx_frame.data.u8[1]; + BatterySerialNumber[2] = rx_frame.data.u8[2]; + BatterySerialNumber[3] = rx_frame.data.u8[3]; + BatterySerialNumber[4] = rx_frame.data.u8[4]; + BatterySerialNumber[5] = rx_frame.data.u8[5]; + BatterySerialNumber[6] = rx_frame.data.u8[6]; + BatterySerialNumber[7] = rx_frame.data.u8[7]; + } + if (rx_frame.data.u8[0] == 0x22) { //Third frame (22 30 31 34 38 32 20 A0) + BatterySerialNumber[8] = rx_frame.data.u8[1]; + BatterySerialNumber[9] = rx_frame.data.u8[2]; + BatterySerialNumber[10] = rx_frame.data.u8[3]; + BatterySerialNumber[11] = rx_frame.data.u8[4]; + BatterySerialNumber[12] = rx_frame.data.u8[5]; + BatterySerialNumber[13] = rx_frame.data.u8[6]; + BatterySerialNumber[14] = rx_frame.data.u8[7]; + } + if (rx_frame.data.u8[0] == 0x23) { //Fourth frame (23 00 00 00 00 00 00 00) + } + } + + if (group_7bb == 0x90) { //BMSIDcode + if (rx_frame.data.u8[0] == 0x10) { //First frame (100A619044434131) + BMSIDcode[0] = rx_frame.data.u8[4]; + BMSIDcode[1] = rx_frame.data.u8[5]; + BMSIDcode[2] = rx_frame.data.u8[6]; + BMSIDcode[3] = rx_frame.data.u8[7]; + } + if (rx_frame.data.u8[0] == 0x21) { //Second frame (2130303535FFFFFF) + BMSIDcode[4] = rx_frame.data.u8[1]; + BMSIDcode[5] = rx_frame.data.u8[2]; + BMSIDcode[6] = rx_frame.data.u8[3]; + BMSIDcode[7] = rx_frame.data.u8[4]; + } + } + break; default: break; @@ -1190,9 +1247,11 @@ void send_can_battery() { //Every 10s, ask diagnostic data from the battery. Don't ask if someone is already polling on the bus (Leafspy?) if (!stop_battery_query) { - group = (group == 1) ? 2 : (group == 2) ? 4 : 1; - // Cycle between group 1, 2, and 4 using ternary operation - LEAF_GROUP_REQUEST.data.u8[2] = group; + + // Move to the next group + PIDindex = (PIDindex + 1) % 6; // 6 = amount of elements in the PIDgroups[] + LEAF_GROUP_REQUEST.data.u8[2] = PIDgroups[PIDindex]; + transmit_can(&LEAF_GROUP_REQUEST, can_config.battery); #ifdef DOUBLE_BATTERY transmit_can(&LEAF_GROUP_REQUEST, can_config.battery_double); From 335533fd09a441e41c050549bb2ff75cce3ba812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 20 Dec 2024 11:55:09 +0200 Subject: [PATCH 081/225] Add numbers to more battery info page --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 3 +++ Software/src/datalayer/datalayer_extended.h | 5 +++++ .../devboard/webserver/advanced_battery_html.cpp | 14 ++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 2791e0b8a..b4b94b657 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -329,6 +329,9 @@ void update_values_battery() { /* This function maps all the values fetched via } // Update webserver datalayer + memcpy(datalayer_extended.nissanleaf.BatterySerialNumber, BatterySerialNumber, sizeof(BatterySerialNumber)); + memcpy(datalayer_extended.nissanleaf.BatteryPartNumber, BatteryPartNumber, sizeof(BatteryPartNumber)); + memcpy(datalayer_extended.nissanleaf.BMSIDcode, BMSIDcode, sizeof(BMSIDcode)); datalayer_extended.nissanleaf.LEAF_gen = LEAF_battery_Type; datalayer_extended.nissanleaf.GIDS = battery_GIDS; datalayer_extended.nissanleaf.ChargePowerLimit = battery_Charge_Power_Limit; diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index e4aa0c029..0d9b2d3fe 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -215,6 +215,11 @@ typedef struct { } DATALAYER_INFO_TESLA; typedef struct { + /** uint8_t */ + /** Battery info, stores raw HEX values for ASCII chars */ + uint8_t BatterySerialNumber[15] = {0}; + uint8_t BatteryPartNumber[7] = {0}; + uint8_t BMSIDcode[8] = {0}; /** uint8_t */ /** Enum, ZE0 = 0, AZE0 = 1, ZE1 = 2 */ uint8_t LEAF_gen = 0; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 5806bb32a..3f7eec4e7 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -399,6 +399,20 @@ String advanced_battery_processor(const String& var) { #ifdef NISSAN_LEAF_BATTERY static const char* LEAFgen[] = {"ZE0", "AZE0", "ZE1"}; content += "

LEAF generation: " + String(LEAFgen[datalayer_extended.nissanleaf.LEAF_gen]) + "

"; + char readableSerialNumber[16]; // One extra space for null terminator + memcpy(readableSerialNumber, datalayer_extended.nissanleaf.BatterySerialNumber, + sizeof(datalayer_extended.nissanleaf.BatterySerialNumber)); + readableSerialNumber[15] = '\0'; // Null terminate the string + content += "

Serial number: " + String(readableSerialNumber) + "

"; + char readablePartNumber[8]; // One extra space for null terminator + memcpy(readablePartNumber, datalayer_extended.nissanleaf.BatteryPartNumber, + sizeof(datalayer_extended.nissanleaf.BatteryPartNumber)); + readablePartNumber[7] = '\0'; // Null terminate the string + content += "

Part number: " + String(readablePartNumber) + "

"; + char readableBMSID[9]; // One extra space for null terminator + memcpy(readableBMSID, datalayer_extended.nissanleaf.BMSIDcode, sizeof(datalayer_extended.nissanleaf.BMSIDcode)); + readableBMSID[8] = '\0'; // Null terminate the string + content += "

BMS ID: " + String(readableBMSID) + "

"; content += "

GIDS: " + String(datalayer_extended.nissanleaf.GIDS) + "

"; content += "

Regen kW: " + String(datalayer_extended.nissanleaf.ChargePowerLimit) + "

"; content += "

Charge kW: " + String(datalayer_extended.nissanleaf.MaxPowerForCharger) + "

"; From 3f1f2e68a2a75aae5a354bbf6823fa4c51bb3e02 Mon Sep 17 00:00:00 2001 From: lenvm Date: Mon, 16 Dec 2024 23:30:46 +0100 Subject: [PATCH 082/225] split compile-all-combinations workflow into two pieces, to avoid that the strategy expansion exceeds 256 results for job build-matrix --- ...ll-combinations-part1-batteries-A-to-M.yml | 111 ++++++++++++++++++ ...l-combinations-part2-batteries-N-to-Z.yml} | 12 -- 2 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml rename .github/workflows/{compile-all-combinations.yml => compile-all-combinations-part2-batteries-N-to-Z.yml} (91%) diff --git a/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml b/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml new file mode 100644 index 000000000..3fc077343 --- /dev/null +++ b/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml @@ -0,0 +1,111 @@ +# This is the name of the workflow, visible on GitHub UI. +name: Compile All Combinations + +# Here we tell GitHub when to run the workflow. +on: + # This allows you to run this workflow manually from the + # GitHub Actions tab. + workflow_dispatch: + # The workflow is run upon creating, editing, + # pre-releasing, releasing and publishing a release + release: + types: [created, edited, prereleased, released, published] + +# This is the list of jobs that will be run concurrently. +jobs: + # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request + skip-duplicate-actions: + runs-on: ubuntu-latest + # Map a step output to a job output + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # All of these options are optional, so you can remove them if you are happy with the defaults + concurrent_skipping: 'never' + skip_after_successful_duplicate: 'true' + do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' + + # Since we use a build matrix, the actual number of jobs + # started depends on how many configurations the matrix + # will produce. + + # This is the name of the job. + build-matrix: + needs: skip-duplicate-actions + if: needs.skip-duplicate-actions.outputs.should_skip != 'true' + + # Here we tell GitHub that the jobs must be determined + # dynamically depending on a matrix configuration. + strategy: + # The matrix will produce one job for each combination of parameters. + matrix: + # This is the development board hardware for which the code will be compiled. + # FBQN stands for "fully qualified board name", and is used by Arduino to define the hardware to compile for. + fqbn: + - esp32:esp32:esp32 + # further ESP32 chips + #- esp32:esp32:esp32c3 + #- esp32:esp32:esp32c2 + #- esp32:esp32:esp32c6 + #- esp32:esp32:esp32h2 + #- esp32:esp32:esp32s3 + # These are the batteries for which the code will be compiled. + battery: + - BMW_I3_BATTERY + - BMW_IX_BATTERY + - BYD_ATTO_3_BATTERY + - CELLPOWER_BMS + - CHADEMO_BATTERY + - IMIEV_CZERO_ION_BATTERY + - JAGUAR_IPACE_BATTERY + - KIA_E_GMP_BATTERY + - KIA_HYUNDAI_64_BATTERY + - KIA_HYUNDAI_HYBRID_BATTERY + - MEB_BATTERY + - MG_5_BATTERY + # These are the emulated inverter communication protocols for which the code will be compiled. + inverter: + - AFORE_CAN + - BYD_CAN + - BYD_KOSTAL_RS485 + - BYD_MODBUS + - BYD_SMA + - FOXESS_CAN + - PYLON_CAN + - PYLON_LV_CAN + - SCHNEIDER_CAN + - SMA_CAN + - SMA_LV_CAN + - SMA_TRIPOWER_CAN + - SOFAR_CAN + - SOLAX_CAN + - SERIAL_LINK_TRANSMITTER + + # This is the platform GitHub will use to run our workflow. + runs-on: ubuntu-latest + + # This is the list of steps this job will run. + steps: + # First we clone the repo using the `checkout` action. + - name: Checkout + uses: actions/checkout@v4 + + # We use the `arduino/setup-arduino-cli` action to install and + # configure the Arduino CLI on the system. + - name: Setup Arduino CLI + uses: arduino/setup-arduino-cli@v2 + + # We then install the platform. + - name: Install platform + run: | + arduino-cli core update-index + arduino-cli core install esp32:esp32 + + # Finally, we compile the sketch, using the FQBN that was set + # in the build matrix, and using build flags to define the + # battery and inverter set in the build matrix. + - name: Compile Sketch + run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}}" ./Software diff --git a/.github/workflows/compile-all-combinations.yml b/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml similarity index 91% rename from .github/workflows/compile-all-combinations.yml rename to .github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml index 23ff0b85e..668f6db3b 100644 --- a/.github/workflows/compile-all-combinations.yml +++ b/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml @@ -54,18 +54,6 @@ jobs: #- esp32:esp32:esp32s3 # These are the batteries for which the code will be compiled. battery: - - BMW_I3_BATTERY - - BMW_IX_BATTERY - - BYD_ATTO_3_BATTERY - - CELLPOWER_BMS - - CHADEMO_BATTERY - - IMIEV_CZERO_ION_BATTERY - - JAGUAR_IPACE_BATTERY - - KIA_E_GMP_BATTERY - - KIA_HYUNDAI_64_BATTERY - - KIA_HYUNDAI_HYBRID_BATTERY - - MEB_BATTERY - - MG_5_BATTERY - NISSAN_LEAF_BATTERY - PYLON_BATTERY - RJXZS_BMS From a043dc6968d631d4ecb4a21a011feb32730806c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 20 Dec 2024 19:27:13 +0200 Subject: [PATCH 083/225] Add Current and allowed charge mappings --- .../src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 79 ++++++++----------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index 899331911..b513c95df 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -1,6 +1,5 @@ #include "../include.h" #ifdef RENAULT_ZOE_GEN1_BATTERY -#include // For std::min and std::max #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" #include "RENAULT-ZOE-GEN1-BATTERY.h" @@ -9,22 +8,24 @@ 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 Still TODO: -- Find max discharge and max charge values (for now hardcoded to 5kW) -- Fix the missing cell96 issue (Only cells 1-95 is shown) -- Find current sensor value (OVMS code reads this from inverter, which we dont have) -- Figure out why SOH% is not read (low prio) - - Most likely relates to the CAN message not being present on 41kWh packs -- Automatically detect if we are on 22 or 41kWh battery +- Fix the missing cell96 issue (Only cells 1-95 is shown on cellmonitor page) +- Automatically detect if we are on 22 or 41kWh battery (Nice to have, requires log file from 22kWh battery) /* /* Do not change code below unless you are sure what you are doing */ static uint16_t LB_SOC = 50; +static uint16_t LB_Display_SOC = 50; static uint16_t LB_SOH = 99; static int16_t LB_Average_Temperature = 0; -static uint32_t LB_Charge_Power_W = 0; -static int32_t LB_Current = 0; +static uint32_t LB_Charging_Power_W = 0; +static uint32_t LB_Regen_allowed_W = 0; +static uint32_t LB_Discharge_allowed_W = 0; +static int16_t LB_Current = 0; +static int16_t LB_Cell_minimum_temperature = 0; +static int16_t LB_Cell_maximum_temperature = 0; static uint16_t LB_kWh_Remaining = 0; static uint16_t LB_Battery_Voltage = 3700; +static uint8_t LB_Heartbeat = 0; static uint8_t frame0 = 0; static uint8_t current_poll = 0; static uint8_t requested_poll = 0; @@ -79,32 +80,17 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.soh_pptt = (LB_SOH * 100); // Increase range from 99% -> 99.00% datalayer.battery.status.real_soc = SOC_polled; + //datalayer.battery.status.real_soc = LB_Display_SOC; //Alternative would be to use Dash SOC% - datalayer.battery.status.current_dA = LB_Current; //TODO: Take from CAN + datalayer.battery.status.current_dA = LB_Current; //Calculate the remaining Wh amount from SOC% and max Wh value. 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_discharge_power_W = 5000; //TODO: Take from CAN + datalayer.battery.status.max_discharge_power_W = LB_Discharge_allowed_W; - datalayer.battery.status.max_charge_power_W = 5000; //TODO: Take from CAN - // TODO: Remove this hacky wacky scaling down charge power when we find value from CAN - if (datalayer.battery.status.real_soc > 9500) { - datalayer.battery.status.max_charge_power_W = 3000; - } - if (datalayer.battery.status.real_soc > 9600) { - datalayer.battery.status.max_charge_power_W = 2000; - } - if (datalayer.battery.status.real_soc > 9700) { - datalayer.battery.status.max_charge_power_W = 1000; - } - if (datalayer.battery.status.real_soc > 9800) { - datalayer.battery.status.max_charge_power_W = 500; - } - if (datalayer.battery.status.real_soc > 9900) { - datalayer.battery.status.max_charge_power_W = 50; - } + datalayer.battery.status.max_charge_power_W = LB_Charging_Power_W; int16_t temperatures[] = {cell_1_temperature_polled, cell_2_temperature_polled, cell_3_temperature_polled, cell_4_temperature_polled, cell_5_temperature_polled, cell_6_temperature_polled, @@ -147,44 +133,47 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value; datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value; datalayer.battery.status.voltage_dV = static_cast((calculated_total_pack_voltage_mV / 100)); // mV to dV - -#ifdef DEBUG_VIA_USB - -#endif } void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { - case 0x155: //10ms - Unknown content + case 0x155: //10ms - Charging power, current and SOC datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + LB_Charging_Power_W = rx_frame.data.u8[0] * 300; + LB_Current = (((((rx_frame.data.u8[1] & 0xF0) << 8) | rx_frame.data.u8[2]) * 0.25) - 500); + LB_Display_SOC = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); break; case 0x427: // NOTE: Not present on 41kWh battery! datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - LB_Charge_Power_W = rx_frame.data.u8[5] * 300; LB_kWh_Remaining = (((((rx_frame.data.u8[6] << 8) | (rx_frame.data.u8[7])) >> 6) & 0x3ff) * 0.1); break; - case 0x42E: //NOTE: Not present on 41kWh battery! HV SOC & Battery Temp & Charging Power + case 0x42E: //NOTE: Not present on 41kWh battery! datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; LB_Battery_Voltage = (((((rx_frame.data.u8[3] << 8) | (rx_frame.data.u8[4])) >> 5) & 0x3ff) * 0.5); //0.5V/bit LB_Average_Temperature = (((((rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6])) >> 5) & 0x7F) - 40); break; - case 0x424: + case 0x424: //100ms - Charge limits, Temperatures, SOH datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - //Sent only? by 41kWh battery (potential use for detecting which generation we are on) + LB_Regen_allowed_W = rx_frame.data.u8[2] * 500; + LB_Discharge_allowed_W = rx_frame.data.u8[3] * 500; + LB_Cell_minimum_temperature = (rx_frame.data.u8[4] - 40); + LB_SOH = rx_frame.data.u8[5]; + LB_Heartbeat = rx_frame.data.u8[6]; // Alternates between 0x55 and 0xAA every 500ms (Same as on Nissan LEAF) + LB_Cell_maximum_temperature = (rx_frame.data.u8[7] - 40); break; - case 0x425: + case 0x425: //100ms Unknown content datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - //Sent only? by 41kWh battery (potential use for detecting which generation we are on) + //Sent only? by 41kWh battery break; - case 0x445: + case 0x445: //100ms datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //Sent only? by 41kWh battery (potential use for detecting which generation we are on) break; - case 0x4AE: + case 0x4AE: //3000ms datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //Sent only? by 41kWh battery (potential use for detecting which generation we are on) break; - case 0x4AF: + case 0x4AF: //100ms datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //Sent only? by 41kWh battery (potential use for detecting which generation we are on) break; @@ -192,11 +181,11 @@ void receive_can_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; LB_SOC = rx_frame.data.u8[3]; break; - case 0x658: //SOH - NOTE: Not present on 41kWh battery! + case 0x658: //SOH - NOTE: Not present on 41kWh battery! (Is this message on 21kWh?) datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; - LB_SOH = (rx_frame.data.u8[4] & 0x7F); + //LB_SOH = (rx_frame.data.u8[4] & 0x7F); break; - case 0x659: + case 0x659: //3000ms datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; //Sent only? by 41kWh battery (potential use for detecting which generation we are on) break; From 9abf7db2a188b811ce4facc96d65272c2db94954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 20 Dec 2024 20:25:14 +0200 Subject: [PATCH 084/225] Fix bitmasking in current value --- Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index b513c95df..76b3bd388 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -140,7 +140,7 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x155: //10ms - Charging power, current and SOC datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; LB_Charging_Power_W = rx_frame.data.u8[0] * 300; - LB_Current = (((((rx_frame.data.u8[1] & 0xF0) << 8) | rx_frame.data.u8[2]) * 0.25) - 500); + LB_Current = (((((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[2]) * 0.25) - 500); LB_Display_SOC = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); break; case 0x427: // NOTE: Not present on 41kWh battery! From ecff22a26e5fbeb55639fe77c62805ce23bff58d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 20 Dec 2024 20:49:52 +0200 Subject: [PATCH 085/225] Fix scaling of A value --- Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index 76b3bd388..84a8463f5 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -82,7 +82,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.real_soc = SOC_polled; //datalayer.battery.status.real_soc = LB_Display_SOC; //Alternative would be to use Dash SOC% - datalayer.battery.status.current_dA = LB_Current; + datalayer.battery.status.current_dA = LB_Current * 10; //Convert A to dA //Calculate the remaining Wh amount from SOC% and max Wh value. datalayer.battery.status.remaining_capacity_Wh = static_cast( From dd510f40ca3386f14072bea6540f2aacbfc08414 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sat, 21 Dec 2024 21:51:15 +1300 Subject: [PATCH 086/225] Update TESLA-BATTERY.cpp Update advanced_battery_html.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 79 +++-- .../webserver/advanced_battery_html.cpp | 325 ++++++++++++++---- 2 files changed, 312 insertions(+), 92 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 757817201..7a46d0654 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -51,10 +51,13 @@ static int16_t battery_amps = 0; // A static uint16_t battery_raw_amps = 0; // A static uint16_t battery_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable -static uint16_t BMS_regenerative_limit = 0; //rename from battery_regenerative_limit -static uint16_t BMS_discharge_limit = 0; // rename from battery_discharge_limit -static uint16_t BMS_max_heat_park = 0; //rename from battery_max_heat_park -static uint16_t BMS_hvac_max_power = 0; //rename from battery_hvac_max_power +static uint16_t BMS_maxRegenPower = 0; //rename from battery_regenerative_limit +static uint16_t BMS_maxDischargePower = 0; // rename from battery_discharge_limit +static uint16_t BMS_maxStationaryHeatPower = 0; //rename from battery_max_heat_park +static uint16_t BMS_hvacPowerBudget = 0; //rename from battery_hvac_max_power +static uint8_t BMS_notEnoughPowerForHeatPump = 0; +static uint8_t BMS_powerLimitState = 0; +static uint8_t BMS_inverterTQF = 0; //0x2d2: 722 BMSVAlimits static uint16_t battery_max_discharge_current = 0; static uint16_t battery_max_charge_current = 0; @@ -923,10 +926,12 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.battery_energy_to_charge_complete_m1 = battery_energy_to_charge_complete_m1; datalayer_extended.tesla.battery_energy_buffer = battery_energy_buffer; datalayer_extended.tesla.battery_energy_buffer_m1 = battery_energy_buffer_m1; + datalayer_extended.tesla.battery_expected_energy_remaining_m1 = battery_expected_energy_remaining_m1; datalayer_extended.tesla.battery_full_charge_complete = battery_full_charge_complete; + datalayer_extended.tesla.battery_fully_charged = battery_fully_charged; + //0x3D2 datalayer_extended.tesla.battery_total_discharge = battery_total_discharge; datalayer_extended.tesla.battery_total_charge = battery_total_charge; - datalayer_extended.tesla.battery_fully_charged = battery_fully_charged; //0x392 datalayer_extended.tesla.battery_moduleType = battery_moduleType; datalayer_extended.tesla.battery_packMass = battery_packMass; @@ -976,10 +981,13 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt = battery_PCS_dcdcPrechargeRestartCnt; datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState = battery_PCS_dcdcInitialPrechargeSubState; //0x252 - datalayer_extended.tesla.BMS_regenerative_limit = BMS_regenerative_limit; - datalayer_extended.tesla.BMS_discharge_limit = BMS_discharge_limit; - datalayer_extended.tesla.BMS_max_heat_park = BMS_max_heat_park; - datalayer_extended.tesla.BMS_hvac_max_power = BMS_hvac_max_power; + datalayer_extended.tesla.BMS_maxRegenPower = BMS_maxRegenPower; + datalayer_extended.tesla.BMS_maxDischargePower = BMS_maxDischargePower; + datalayer_extended.tesla.BMS_maxStationaryHeatPower = BMS_maxStationaryHeatPower; + datalayer_extended.tesla.BMS_hvacPowerBudget = BMS_hvacPowerBudget; + datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump = BMS_notEnoughPowerForHeatPump; + datalayer_extended.tesla.BMS_powerLimitState = BMS_powerLimitState; + datalayer_extended.tesla.BMS_inverterTQF = BMS_inverterTQF; //0x312 datalayer_extended.tesla.BMS_powerDissipation = BMS_powerDissipation; datalayer_extended.tesla.BMS_flowRequest = BMS_flowRequest; @@ -1015,8 +1023,38 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr = PCS_dcdcIntervalMinLvOutputCurr; datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh = PCS_dcdc12vSupportLifetimekWh; //0x7AA + datalayer_extended.tesla.HVP_gpioPassivePyroDepl = HVP_gpioPassivePyroDepl; + datalayer_extended.tesla.HVP_gpioPyroIsoEn = HVP_gpioPyroIsoEn; + datalayer_extended.tesla.HVP_gpioCpFaultIn = HVP_gpioCpFaultIn; + datalayer_extended.tesla.HVP_gpioPackContPowerEn = HVP_gpioPackContPowerEn; + datalayer_extended.tesla.HVP_gpioHvCablesOk = HVP_gpioHvCablesOk; + datalayer_extended.tesla.HVP_gpioHvpSelfEnable = HVP_gpioHvpSelfEnable; + datalayer_extended.tesla.HVP_gpioLed = HVP_gpioLed; + datalayer_extended.tesla.HVP_gpioCrashSignal = HVP_gpioCrashSignal; + datalayer_extended.tesla.HVP_gpioShuntDataReady = HVP_gpioShuntDataReady; + datalayer_extended.tesla.HVP_gpioFcContPosAux = HVP_gpioFcContPosAux; + datalayer_extended.tesla.HVP_gpioFcContNegAux = HVP_gpioFcContNegAux; + datalayer_extended.tesla.HVP_gpioBmsEout = HVP_gpioBmsEout; + datalayer_extended.tesla.HVP_gpioCpFaultOut = HVP_gpioCpFaultOut; + datalayer_extended.tesla.HVP_gpioPyroPor = HVP_gpioPyroPor; + datalayer_extended.tesla.HVP_gpioShuntEn = HVP_gpioShuntEn; + datalayer_extended.tesla.HVP_gpioHvpVerEn = HVP_gpioHvpVerEn; + datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel = HVP_gpioPackCoontPosFlywheel; + datalayer_extended.tesla.HVP_gpioCpLatchEnable = HVP_gpioCpLatchEnable; + datalayer_extended.tesla.HVP_gpioPcsEnable = HVP_gpioPcsEnable; + datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable = HVP_gpioPcsDcdcPwmEnable; + datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable = HVP_gpioPcsChargePwmEnable; + datalayer_extended.tesla.HVP_gpioFcContPowerEnable = HVP_gpioFcContPowerEnable; + datalayer_extended.tesla.HVP_gpioHvilEnable = HVP_gpioHvilEnable; + datalayer_extended.tesla.HVP_gpioSecDrdy = HVP_gpioSecDrdy; datalayer_extended.tesla.HVP_hvp1v5Ref = HVP_hvp1v5Ref; datalayer_extended.tesla.HVP_shuntCurrentDebug = HVP_shuntCurrentDebug; + datalayer_extended.tesla.HVP_packCurrentMia = HVP_packCurrentMia; + datalayer_extended.tesla.HVP_auxCurrentMia = HVP_auxCurrentMia; + datalayer_extended.tesla.HVP_currentSenseMia = HVP_currentSenseMia; + datalayer_extended.tesla.HVP_shuntRefVoltageMismatch = HVP_shuntRefVoltageMismatch; + datalayer_extended.tesla.HVP_shuntThermistorMia = HVP_shuntThermistorMia; + datalayer_extended.tesla.HVP_shuntHwMia = HVP_shuntHwMia; datalayer_extended.tesla.HVP_dcLinkVoltage = HVP_dcLinkVoltage; datalayer_extended.tesla.HVP_packVoltage = HVP_packVoltage; datalayer_extended.tesla.HVP_fcLinkVoltage = HVP_fcLinkVoltage; @@ -1112,7 +1150,7 @@ void receive_can_battery(CAN_frame rx_frame) { static uint16_t temp = 0; switch (rx_frame.ID) { - case 0x352: // BMS_energyStatus // newer BMS >2021 + case 0x352: // 850 BMS_energyStatus newer BMS mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X if (mux == 0) { @@ -1222,7 +1260,7 @@ void receive_can_battery(CAN_frame rx_frame) { battery_BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); battery_BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC break; - case 0x224: //548 PCS_dcdcStatus: + case 0x224: //548 PCS_dcdcStatus: battery_PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ; battery_PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" battery_PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" @@ -1249,17 +1287,14 @@ void receive_can_battery(CAN_frame rx_frame) { ((rx_frame.data.u8[7] >> 3) & (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; break; - case 0x252: //Limit //BMS_powerAvailable252: - BMS_regenerative_limit = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * - 0.01; //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW - BMS_discharge_limit = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * - 0.013; //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? - BMS_max_heat_park = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]) * - 0.01; //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW - BMS_hvac_max_power = (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))) * - 0.02; //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? - //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver - //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] "" Receiver + case 0x252: //Limit //594 BMS_powerAvailable: + BMS_maxRegenPower = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW + BMS_maxDischargePower = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? + BMS_maxStationaryHeatPower = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]); //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW + BMS_hvacPowerBudget = (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))); //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? + BMS_notEnoughPowerForHeatPump = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver + BMS_powerLimitState = (rx_frame.data.u8[6] & (0x01U)); //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] 0 "NOT_CALCULATED_FOR_DRIVE" 1 "CALCULATED_FOR_DRIVE" + BMS_inverterTQF = ((rx_frame.data.u8[7] >> 4) & (0x03U)); break; case 0x132: //battery amps/volts //HVBattAmpVolt battery_volts = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 5806bb32a..5959e761a 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -294,28 +294,21 @@ String advanced_battery_processor(const String& var) { float dcdcLvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcLvBusVolt) * 0.0390625; float dcdcHvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcHvBusVolt) * 0.146484; float dcdcLvOutputCurrent = static_cast(datalayer_extended.tesla.battery_dcdcLvOutputCurrent) * 0.1; - float nominal_full_pack_energy = - static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy) * 0.1; - float nominal_full_pack_energy_m0 = - static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy_m0) * 0.02; - float nominal_energy_remaining = - static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining) * 0.1; - float nominal_energy_remaining_m0 = - static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining_m0) * 0.02; + float nominal_full_pack_energy = static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy) * 0.1; + float nominal_full_pack_energy_m0 = static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy_m0) * 0.02; + float nominal_energy_remaining = static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining) * 0.1; + float nominal_energy_remaining_m0 = static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining_m0) * 0.02; float ideal_energy_remaining = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining) * 0.1; - float ideal_energy_remaining_m0 = - static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining_m0) * 0.02; - float energy_to_charge_complete = - static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete) * 0.1; - float energy_to_charge_complete_m1 = - static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete_m1) * 0.02; + float ideal_energy_remaining_m0 = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining_m0) * 0.02; + float energy_to_charge_complete = static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete) * 0.1; + float energy_to_charge_complete_m1 = static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete_m1) * 0.02; float energy_buffer = static_cast(datalayer_extended.tesla.battery_energy_buffer) * 0.1; float energy_buffer_m1 = static_cast(datalayer_extended.tesla.battery_energy_buffer_m1) * 0.01; + float expected_energy_remaining_m1 = static_cast(datalayer_extended.tesla.battery_expected_energy_remaining_m1) * 0.02; float total_discharge = static_cast(datalayer_extended.tesla.battery_total_discharge); float total_charge = static_cast(datalayer_extended.tesla.battery_total_charge); float packMass = static_cast(datalayer_extended.tesla.battery_packMass); - float platformMaxBusVoltage = - static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage) * 0.1 + 375; + float platformMaxBusVoltage = static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage) * 0.1 + 375; float bms_min_voltage = static_cast(datalayer_extended.tesla.battery_bms_min_voltage) * 0.01 * 2; float bms_max_voltage = static_cast(datalayer_extended.tesla.battery_bms_max_voltage) * 0.01 * 2; float max_charge_current = static_cast(datalayer_extended.tesla.battery_max_charge_current); @@ -324,76 +317,268 @@ String advanced_battery_processor(const String& var) { float soc_max = static_cast(datalayer_extended.tesla.battery_soc_max) * 0.1; float soc_min = static_cast(datalayer_extended.tesla.battery_soc_min) * 0.1; float soc_ui = static_cast(datalayer_extended.tesla.battery_soc_ui) * 0.1; + float BrickVoltageMax = static_cast(datalayer_extended.tesla.battery_BrickVoltageMax) * 0.002; + float BrickVoltageMin = static_cast(datalayer_extended.tesla.battery_BrickVoltageMin) * 0.002; + float BrickModelTMax = static_cast(datalayer_extended.tesla.battery_BrickTempMinNum) * 0.5 - 40; + float BrickModelTMin = static_cast(datalayer_extended.tesla.battery_BrickModelTMin) * 0.5 - 40; + float isolationResistance = static_cast(datalayer_extended.tesla.battery_BMS_isolationResistance) * 10; + float PCS_dcdcMaxOutputCurrentAllowed = static_cast(datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed) * 0.1; + float PCS_dcdcTemp = static_cast(datalayer_extended.tesla.PCS_dcdcTemp * 0.1 + 40); + float PCS_ambientTemp = static_cast(datalayer_extended.tesla.PCS_ambientTemp) * 0.1 + 40; + float BMS_maxRegenPower = static_cast(datalayer_extended.tesla.BMS_maxRegenPower) * 0.01; + float BMS_maxDischargePower = static_cast(datalayer_extended.tesla.BMS_maxDischargePower) * 0.013; + float BMS_maxStationaryHeatPower = static_cast(datalayer_extended.tesla.BMS_maxStationaryHeatPower) * 0.01; + float BMS_hvacPowerBudget = static_cast(datalayer_extended.tesla.BMS_hvacPowerBudget) * 0.02; + float BMS_powerDissipation = static_cast(datalayer_extended.tesla.BMS_powerDissipation) * 0.02; + float BMS_flowRequest = static_cast(datalayer_extended.tesla.BMS_flowRequest) * 0.3; + float BMS_inletActiveCoolTargetT = static_cast(datalayer_extended.tesla.BMS_inletActiveCoolTargetT) * 0.25 - 25; + float BMS_inletPassiveTargetT = static_cast(datalayer_extended.tesla.BMS_inletPassiveTargetT) * 0.25 - 25; + float BMS_inletActiveHeatTargetT = static_cast(datalayer_extended.tesla.BMS_inletActiveHeatTargetT) * 0.25 - 25; + float BMS_packTMin = static_cast(datalayer_extended.tesla.BMS_packTMin); + float BMS_packTMax = static_cast(datalayer_extended.tesla.BMS_packTMax); + float PCS_dcdcMaxLvOutputCurrent = static_cast(datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent) * 0.1; + float PCS_dcdcCurrentLimit = static_cast(datalayer_extended.tesla.PCS_dcdcCurrentLimit) * 0.1; + float PCS_dcdcLvOutputCurrentTempLimit = static_cast(datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit) * 0.1; + float PCS_dcdcUnifiedCommand = static_cast(datalayer_extended.tesla.PCS_dcdcUnifiedCommand) * 0.001; + float PCS_dcdcCLAControllerOutput = static_cast(datalayer_extended.tesla.PCS_dcdcCLAControllerOutput * 0.001); + float PCS_dcdcTankVoltage = static_cast(datalayer_extended.tesla.PCS_dcdcTankVoltage); + float PCS_dcdcTankVoltageTarget = static_cast(datalayer_extended.tesla.PCS_dcdcTankVoltageTarget); + float PCS_dcdcClaCurrentFreq = static_cast(datalayer_extended.tesla.PCS_dcdcClaCurrentFreq) * 0.0976563; + float PCS_dcdcTCommMeasured = static_cast(datalayer_extended.tesla.PCS_dcdcTCommMeasured) * 0.00195313; + float PCS_dcdcShortTimeUs = static_cast(datalayer_extended.tesla.PCS_dcdcShortTimeUs) * 0.000488281; + float PCS_dcdcHalfPeriodUs = static_cast(datalayer_extended.tesla.PCS_dcdcHalfPeriodUs) * 0.000488281; + float PCS_dcdcIntervalMaxFrequency = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxFrequency); + float PCS_dcdcIntervalMaxHvBusVolt = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxHvBusVolt) * 0.1; + float PCS_dcdcIntervalMaxLvBusVolt = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvBusVolt) * 0.1; + float PCS_dcdcIntervalMaxLvOutputCurr = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvOutputCurr); + float PCS_dcdcIntervalMinFrequency = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinFrequency); + float PCS_dcdcIntervalMinHvBusVolt = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinHvBusVolt) * 0.1; + float PCS_dcdcIntervalMinLvBusVolt = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinLvBusVolt) * 0.1; + float PCS_dcdcIntervalMinLvOutputCurr = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr); + float PCS_dcdc12vSupportLifetimekWh = static_cast(datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh) * 0.01; + float HVP_hvp1v5Ref = static_cast(datalayer_extended.tesla.HVP_hvp1v5Ref) * 0.1; + float HVP_shuntCurrentDebug = static_cast(datalayer_extended.tesla.HVP_shuntCurrentDebug) * 0.1; + float HVP_dcLinkVoltage = static_cast(datalayer_extended.tesla.HVP_dcLinkVoltage) * 0.1; + float HVP_packVoltage = static_cast(datalayer_extended.tesla.HVP_packVoltage) * 0.1; + float HVP_fcLinkVoltage = static_cast(datalayer_extended.tesla.HVP_fcLinkVoltage) * 0.1; + float HVP_packContVoltage = static_cast(datalayer_extended.tesla.HVP_packContVoltage) * 0.1; + float HVP_packNegativeV = static_cast(datalayer_extended.tesla.HVP_packNegativeV) * 0.1; + float HVP_packPositiveV = static_cast(datalayer_extended.tesla.HVP_packPositiveV) * 0.1; + float HVP_pyroAnalog = static_cast(datalayer_extended.tesla.HVP_pyroAnalog) * 0.1; + float HVP_dcLinkNegativeV = static_cast(datalayer_extended.tesla.HVP_dcLinkNegativeV) * 0.1; + float HVP_dcLinkPositiveV = static_cast(datalayer_extended.tesla.HVP_dcLinkPositiveV) * 0.1; + float HVP_fcLinkNegativeV = static_cast(datalayer_extended.tesla.HVP_fcLinkNegativeV) * 0.1; + float HVP_fcContCoilCurrent = static_cast(datalayer_extended.tesla.HVP_fcContCoilCurrent) * 0.1; + float HVP_fcContVoltage = static_cast(datalayer_extended.tesla.HVP_fcContVoltage) * 0.1; + float HVP_hvilInVoltage = static_cast(datalayer_extended.tesla.HVP_hvilInVoltage) * 0.1; + float HVP_hvilOutVoltage = static_cast(datalayer_extended.tesla.HVP_hvilOutVoltage) * 0.1; + float HVP_fcLinkPositiveV = static_cast(datalayer_extended.tesla.HVP_fcLinkPositiveV) * 0.1; + float HVP_packContCoilCurrent = static_cast(datalayer_extended.tesla.HVP_packContCoilCurrent) * 0.1; + float HVP_battery12V = static_cast(datalayer_extended.tesla.HVP_battery12V) * 0.1; + float HVP_shuntRefVoltageDbg = static_cast(datalayer_extended.tesla.HVP_shuntRefVoltageDbg) * 0.001; + float HVP_shuntAuxCurrentDbg = static_cast(datalayer_extended.tesla.HVP_shuntAuxCurrentDbg) * 0.1; + float HVP_shuntBarTempDbg = static_cast(datalayer_extended.tesla.HVP_shuntBarTempDbg) * 0.01; + float HVP_shuntAsicTempDbg = static_cast(datalayer_extended.tesla.HVP_shuntAsicTempDbg) * 0.01; + static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"}; + static const char* hvilStatusState[] = {"NOT Ok", "STATUS_OK", "CURRENT_SOURCE_FAULT", "INTERNAL_OPEN_FAULT", "VEHICLE_OPEN_FAULT", "PENTHOUSE_LID_OPEN_FAULT", "UNKNOWN_LOCATION_OPEN_FAULT", "VEHICLE_NODE_FAULT", "NO_12V_SUPPLY", "VEHICLE_OR_PENTHOUSE_LID_OPENFAULT", "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)", "UNKNOWN(13)", "UNKNOWN(14)", "UNKNOWN(15)"}; + static const char* contactorState[] = {"SNA", "OPEN", "PRECHARGE", "BLOCKED", "PULLED_IN", "OPENING", "ECONOMIZED", "WELDED", "UNKNOWN(8)", "UNKNOWN(9)", "UNKNOWN(10)", "UNKNOWN(11)"}; + static const char* BMS_state[] = {"STANDBY", "DRIVE", "SUPPORT", "CHARGE", "FEIM", "CLEAR_FAULT", "FAULT", "WELD", "TEST", "SNA"}; + static const char* BMS_contactorState[] = {"SNA", "OPEN", "OPENING", "CLOSING", "CLOSED", "WELDED", "BLOCKED"}; + static const char* BMS_hvState[] = {"DOWN", "COMING_UP", "GOING_DOWN", "UP_FOR_DRIVE", "UP_FOR_CHARGE", "UP_FOR_DC_CHARGE", "UP"}; + static const char* BMS_uiChargeStatus[] = {"DISCONNECTED", "NO_POWER", "ABOUT_TO_CHARGE", "CHARGING", "CHARGE_COMPLETE", "CHARGE_STOPPED"}; + static const char* PCS_dcdcStatus[] = {"IDLE", "ACTIVE", "FAULTED"}; + static const char* PCS_dcdcMainState[] = {"STANDBY", "12V_SUPPORT_ACTIVE", "PRECHARGE_STARTUP", "PRECHARGE_ACTIVE", "DIS_HVBUS_ACTIVE", "SHUTDOWN", "FAULTED"}; + static const char* PCS_dcdcSubState[] = {"PWR_UP_INIT", "STANDBY", "12V_SUPPORT_ACTIVE", "DIS_HVBUS", "PCHG_FAST_DIS_HVBUS", "PCHG_SLOW_DIS_HVBUS", "PCHG_DWELL_CHARGE", "PCHG_DWELL_WAIT", "PCHG_DI_RECOVERY_WAIT", "PCHG_ACTIVE", "PCHG_FLT_FAST_DIS_HVBUS", "SHUTDOWN", "12V_SUPPORT_FAULTED", "DIS_HVBUS_FAULTED", "PCHG_FAULTED", "CLEAR_FAULTS", "FAULTED", "NUM"}; + static const char* BMS_powerLimitState[] = {"NOT_CALCULATED_FOR_DRIVE", "CALCULATED_FOR_DRIVE"}; + static const char* HVP_status[] = {"INVALID", "NOT_AVAILABLE", "STALE", "VALID"}; + static const char* falseTrue[] = {"False", "True"}; + static const char* noYes[] = {"No", "Yes"}; + //0x20A 522 HVP_contatorState + content += "

Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "

"; + content += "

HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "

"; + content += "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; + content += "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; + content += "

Closing allowed?: " + String(falseTrue[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; + content += "

Pyrotest in Progress: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "

"; + content += "

Contactors Open Now Requested: " + String(falseTrue[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; + content += "

Contactors Open Requested; " + String(falseTrue[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + "

"; + content += "

Contactors Request Status; " + String(falseTrue[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; + content += "

Contactors Reset Request Required; " + String(falseTrue[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; + content += "

DC Link Allowed to Energize;" + String(falseTrue[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + "

"; // Comment what data you would like to dislay, order can be changed. - content += "

Battery Beginning of Life: " + String(beginning_of_life) + " kWh

"; + //0x292 658 BMS_socStates + content += "

Battery Beginning of Life: " + String(beginning_of_life) + " KWh

"; content += "

BattTempPct: " + String(battTempPct) + "

"; + content += "

Battery SOC Ave: " + String(soc_ave) + "

"; + content += "

Battery SOC Max: " + String(soc_max) + "

"; + content += "

Battery SOC Min: " + String(soc_min) + "

"; + content += "

Battery SOC UI: " + String(soc_ui) + "

"; + //0x2B4 PCS_dcdcRailStatus content += "

PCS Lv Bus: " + String(dcdcLvBusVolt) + " V

"; content += "

PCS Hv Bus: " + String(dcdcHvBusVolt) + " V

"; content += "

PCS Lv Output: " + String(dcdcLvOutputCurrent) + " A

"; - - //if using older BMS <2021 and comment 0x352 without MUX - //content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " kWh

"; - //content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " kWh

"; - //content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " kWh

"; - //content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " kWh

"; - //content += "

Energy Buffer: " + String(energy_buffer) + " kWh

"; - - //if using newer BMS >2021 and comment 0x352 with MUX - content += "

Nominal Full Pack Energy m0: " + String(nominal_full_pack_energy_m0) + " kWh

"; - content += "

Nominal Energy Remaining m0: " + String(nominal_energy_remaining_m0) + " kWh

"; - content += "

Ideal Energy Remaining m0: " + String(ideal_energy_remaining_m0) + " kWh

"; - content += "

Energy to Charge Complete m1: " + String(energy_to_charge_complete_m1) + " kWh

"; - content += "

Energy Buffer m1: " + String(energy_buffer_m1) + " kWh

"; - + //0x2A4 676 PCS_thermalStatus + content += "

PCS dcdc Temp: " + String(PCS_dcdcTemp) + " DegC

"; + content += "

PCS Ambient Temp: " + String(PCS_ambientTemp) + " DegC

"; + //0x224 548 PCS_dcdcStatus + content += "

Precharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcPrechargeStatus]) + "

"; + content += "

12V Support Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdc12VSupportStatus]) + "

"; + content += "

HV Bus Discharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcHvBusDischargeStatus]) + "

"; + content += "

Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "

"; + content += "

Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "

"; + content += "

PCS Faulted: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcFaulted]) + "

"; + content += "

Output Is Limited: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + "

"; + content += "

Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A

"; + content += "

Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) + "

"; + content += "

12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) + "

"; + content += "

Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) + "

"; + content += "

PWM Enable Line: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + "

"; + content += "

Supporting Fixed LV Target: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "

"; + content += "

Precharge Restart Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "

"; + content += "

Initial Precharge Substate: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "

"; + //0x2C4 708 PCS_logging + content += "

PCS_dcdcMaxLvOutputCurrent: " + String(PCS_dcdcMaxLvOutputCurrent) + " A

"; + content += "

PCS_dcdcCurrentLimit: " + String(PCS_dcdcCurrentLimit) + " A

"; + content += "

PCS_dcdcLvOutputCurrentTempLimit: " + String(PCS_dcdcLvOutputCurrentTempLimit) + " A

"; + content += "

PCS_dcdcUnifiedCommand: " + String(PCS_dcdcUnifiedCommand) + "

"; + content += "

PCS_dcdcCLAControllerOutput: " + String(PCS_dcdcCLAControllerOutput) + "

"; + content += "

PCS_dcdcTankVoltage: " + String(PCS_dcdcTankVoltage) + " V

"; + content += "

PCS_dcdcTankVoltageTarget: " + String(PCS_dcdcTankVoltageTarget) + " V

"; + content += "

PCS_dcdcClaCurrentFreq: " + String(PCS_dcdcClaCurrentFreq) + " kHz

"; + content += "

PCS_dcdcTCommMeasured: " + String(PCS_dcdcTCommMeasured) + " us

"; + content += "

PCS_dcdcShortTimeUs: " + String(PCS_dcdcShortTimeUs) + " us

"; + content += "

PCS_dcdcHalfPeriodUs: " + String(PCS_dcdcHalfPeriodUs) + " us

"; + content += "

PCS_dcdcIntervalMaxFrequency: " + String(PCS_dcdcIntervalMaxFrequency) + " kHz

"; + content += "

PCS_dcdcIntervalMaxHvBusVolt: " + String(PCS_dcdcIntervalMaxHvBusVolt) + " V

"; + content += "

PCS_dcdcIntervalMaxLvBusVolt: " + String(PCS_dcdcIntervalMaxLvBusVolt) + " V

"; + content += "

PCS_dcdcIntervalMaxLvOutputCurr: " + String(PCS_dcdcIntervalMaxLvOutputCurr) + " A

"; + content += "

PCS_dcdcIntervalMinFrequency: " + String(PCS_dcdcIntervalMinFrequency) + " kHz

"; + content += "

PCS_dcdcIntervalMinHvBusVolt: " + String(PCS_dcdcIntervalMinHvBusVolt) + " V

"; + content += "

PCS_dcdcIntervalMinLvBusVolt: " + String(PCS_dcdcIntervalMinLvBusVolt) + " V

"; + content += "

PCS_dcdcIntervalMinLvOutputCurr: " + String(PCS_dcdcIntervalMinLvOutputCurr) + " A

"; + content += "

PCS_dcdc12vSupportLifetimekWh: " + String(PCS_dcdc12vSupportLifetimekWh) + " kWh

"; + //0x3D2 978 BMS_kwhCounter + content += "

Total Discharge: " + String(total_discharge) + " KWh

"; + content += "

Total Charge: " + String(total_charge) + " KWh

"; + //0x212 530 BMS_status + content += "

Isolation Resistance: " + String(isolationResistance) + " kOhms

"; + content += "

BMS Contactor State: " + String(BMS_contactorState[datalayer_extended.tesla.battery_BMS_contactorState]) + "

"; + content += "

BMS State: " + String(BMS_state[datalayer_extended.tesla.battery_BMS_state]) + "

"; + content += "

BMS HV State: " + String(BMS_hvState[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; + content += "

BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; + content += "

BMS PCS PWM Enabled: " + String(noYes[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; + //0x352 850 BMS_energyStatus + content += "

Early BMS 0x352"; + content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " KWh

"; + content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " KWh

"; + content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh

"; + content += "

Energy Buffer: " + String(energy_buffer) + " KWh

"; + content += "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; + //0x352 850 BMS_energyStatus + content += "

Late BMS 0x352 with Mux2021 and comment 0x352 with MUX + content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh

"; + content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh

"; + content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining_m0) + " KWh

"; + content += "

Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " KWh

"; + content += "

Energy Buffer: " + String(energy_buffer_m1) + " KWh

"; + content += "

Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " KWh

"; + content += "

Fully Charged: " + String(noYes[datalayer_extended.battery_fully_charged]) + "

"; + //0x392 BMS_packConfig content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; content += "

reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "

"; - content += "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "

"; - content += "

Total Discharge: " + String(total_discharge) + " kWh

"; - content += "

Total Charge: " + String(total_charge) + " kWh

"; content += "

Battery Pack Mass: " + String(packMass) + " KG

"; content += "

Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V

"; + //0x2D2 722 BMSVAlimits content += "

BMS Min Voltage: " + String(bms_min_voltage) + " V

"; content += "

BMS Max Voltage: " + String(bms_max_voltage) + " V

"; content += "

Max Charge Current: " + String(max_charge_current) + " A

"; content += "

Max Discharge Current: " + String(max_discharge_current) + " A

"; - content += "

Battery SOC Ave: " + String(soc_ave) + "

"; - content += "

Battery SOC Max: " + String(soc_max) + "

"; - content += "

Battery SOC Min: " + String(soc_min) + "

"; - content += "

Battery SOC UI: " + String(soc_ui) + "

"; + //0x332 818 BMS_bmbMinMax + content += "

Brick Voltage Max: " + String(BrickVoltageMax) + " V

"; + content += "

Brick Voltage Min: " + String(BrickVoltageMin) + " V

"; + content += "

Brick Temp Max Num: " + String(datalayer_extended.tesla.battery_BrickTempMaxNum) + "

"; + content += "

Brick Temp Min Num: " + String(datalayer_extended.tesla.battery_BrickTempMinNum) + "

"; + content += "

Brick Temp Max: " + String(BrickModelTMax) + " C

"; + content += "

Brick Temp Min: " + String(BrickModelTMin) + " C

"; + //0x252 594 BMS_powerAvailable + content += "

Max Regen Power: " + String(BMS_maxRegenPower) + " KW

"; + content += "

Max Discharge Power: " + String(BMS_maxDischargePower) + " KW

"; + content += "

Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh

"; + content += "

HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW

"; + content += "

Not Enough Power For Heat Pump: " + String(noYes[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + " KW

"; + content += "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; + content += "

Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "

"; + //0x312 786 BMS_thermalStatus + content += "

Power Dissipation: " + String(BMS_powerDissipation) + " kW

"; + content += "

Flow Request: " + String(BMS_flowRequest) + " LPM

"; + content += "

Inlet Active Cool Target Temp: " + String(BMS_inletActiveCoolTargetT) + " DegC

"; + content += "

Inlet Passive Target Temp: " + String(BMS_inletPassiveTargetT) + " DegC

"; + content += "

Inlet Active Heat Target Temp: " + String(BMS_inletActiveHeatTargetT) + " DegC

"; + content += "

Pack Temp Min: " + String(BMS_packTMin) + " DegC

"; + content += "

Pack Temp Max: " + String(BMS_packTMax) + " DegC

"; + content += "

PCS No Flow Request: " + String(falseTrue[ datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "

"; + content += "

BMS No Flow Request: " + String(falseTrue[datalayer_extended.tesla.BMS_noFlowRequest]) + "

"; + //0x7AA 1962 HVP_debugMessage + content += "

HVP_gpioPassivePyroDepl: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) + "

"; + content += "

HVP_gpioPyroIsoEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPyroIsoEn]) + "

"; + content += "

HVP_gpioCpFaultIn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpFaultIn]) + "

"; + content += "

HVP_gpioPackContPowerEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) + "

"; + content += "

HVP_gpioHvCablesOk: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvCablesOk]) + "

"; + content += "

HVP_gpioHvpSelfEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "

"; + content += "

HVP_gpioLed: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioLed]) + "

"; + content += "

HVP_gpioCrashSignal: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCrashSignal]) + "

"; + content += "

HVP_gpioShuntDataReady: " + String(falseTrue[ datalayer_extended.tesla.HVP_gpioShuntDataReady]) + "

"; + content += "

HVP_gpioFcContPosAux: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "

"; + content += "

HVP_gpioFcContNegAux: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "

"; + content += "

HVP_gpioBmsEout: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioBmsEout]) + "

"; + content += "

HVP_gpioCpFaultOut: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpFaultOut]) + "

"; + content += "

HVP_gpioPyroPor: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPyroPor]) + "

"; + content += "

HVP_gpioShuntEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioShuntEn]) + "

"; + content += "

HVP_gpioHvpVerEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvpVerEn]) + "

"; + content += "

HVP_gpioPackCoontPosFlywheel: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) + "

"; + content += "

HVP_gpioCpLatchEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "

"; + content += "

HVP_gpioPcsEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsEnable]) + "

"; + content += "

HVP_gpioPcsDcdcPwmEnable: " + String(falseTrue[ datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) + "

"; + content += "

HVP_gpioPcsChargePwmEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable]) + "

"; + content += "

HVP_gpioFcContPowerEnable: " + String(falseTrue[ datalayer_extended.tesla.HVP_gpioFcContPowerEnable]) + "

"; + content += "

HVP_gpioHvilEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvilEnable]) + "

"; + content += "

HVP_gpioSecDrdy: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioSecDrdy]) + "

"; + content += "

HVP_hvp1v5Ref: " + String(HVP_hvp1v5Ref) + " V

"; + content += "

HVP_shuntCurrentDebug: " + String(HVP_shuntCurrentDebug) + " A

"; + content += "

HVP_packCurrentMia: " + String(falseTrue[datalayer_extended.tesla.HVP_packCurrentMia]) + "

"; + content += "

HVP_auxCurrentMia: " + String(falseTrue[datalayer_extended.tesla.HVP_auxCurrentMia]) + "

"; + content += "

HVP_currentSenseMia: " + String(falseTrue[datalayer_extended.tesla.HVP_currentSenseMia]) + "

"; + content += "

HVP_shuntRefVoltageMismatch: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) + "

"; + content += "

HVP_shuntThermistorMia: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntThermistorMia]) + "

"; + content += "

HVP_shuntHwMia: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntHwMia]) + "

"; + content += "

HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V

"; + content += "

HVP_packVoltage: " + String(HVP_packVoltage) + " V

"; + content += "

HVP_fcLinkVoltage: " + String(HVP_fcLinkVoltage) + " V

"; + content += "

HVP_packContVoltage: " + String(HVP_packContVoltage) + " V

"; + content += "

HVP_packNegativeV: " + String(HVP_packNegativeV) + " V

"; + content += "

HVP_packPositiveV: " + String(HVP_packPositiveV) + " V

"; + content += "

HVP_pyroAnalog: " + String(HVP_pyroAnalog) + " V

"; + content += "

HVP_dcLinkNegativeV: " + String(HVP_dcLinkNegativeV) + " V

"; + content += "

HVP_dcLinkPositiveV: " + String(HVP_dcLinkPositiveV) + " V

"; + content += "

HVP_fcLinkNegativeV: " + String(HVP_fcLinkNegativeV) + " V

"; + content += "

HVP_fcContCoilCurrent: " + String(HVP_fcContCoilCurrent) + " A

"; + content += "

HVP_fcContVoltage: " + String(HVP_fcContVoltage) + " V

"; + content += "

HVP_hvilInVoltage: " + String(HVP_hvilInVoltage) + " V

"; + content += "

HVP_hvilOutVoltage: " + String(HVP_hvilOutVoltage) + " V

"; + content += "

HVP_fcLinkPositiveV: " + String(HVP_fcLinkPositiveV) + " V

"; + content += "

HVP_packContCoilCurrent: " + String(HVP_packContCoilCurrent) + " A

"; + content += "

HVP_battery12V: " + String(HVP_battery12V) + " V

"; + content += "

HVP_shuntRefVoltageDbg: " + String(HVP_shuntRefVoltageDbg) + " V

"; + content += "

HVP_shuntAuxCurrentDbg: " + String(HVP_shuntAuxCurrentDbg) + " A

"; + content += "

HVP_shuntBarTempDbg: " + String(HVP_shuntBarTempDbg) + " DegC

"; + content += "

HVP_shuntAsicTempDbg: " + String(HVP_shuntAsicTempDbg) + " DegC

"; + content += "

HVP_shuntAuxCurrentStatus: " + String(HVP_status) + "

"; + content += "

HVP_shuntBarTempStatus: " + String(HVP_status) + "

"; + content += "

HVP_shuntAsicTempStatus: " + String(HVP_status) + "

"; - static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", - "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", - "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"}; - content += "

Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "

"; - static const char* hvilStatusState[] = {"NOT OK", - "STATUS_OK", - "CURRENT_SOURCE_FAULT", - "INTERNAL_OPEN_FAULT", - "VEHICLE_OPEN_FAULT", - "PENTHOUSE_LID_OPEN_FAULT", - "UNKNOWN_LOCATION_OPEN_FAULT", - "VEHICLE_NODE_FAULT", - "NO_12V_SUPPLY", - "VEHICLE_OR_PENTHOUSE_LID_OPENFAULT", - "UNKNOWN(10)", - "UNKNOWN(11)", - "UNKNOWN(12)", - "UNKNOWN(13)", - "UNKNOWN(14)", - "UNKNOWN(15)"}; - content += "

HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "

"; - static const char* contactorState[] = {"SNA", "OPEN", "PRECHARGE", "BLOCKED", - "PULLED_IN", "OPENING", "ECONOMIZED", "WELDED", - "UNKNOWN(8)", "UNKNOWN(9)", "UNKNOWN(10)", "UNKNOWN(11)"}; - content += - "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; - content += - "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; - static const char* falseTrue[] = {"False", "True"}; - content += "

Closing allowed?: " + String(falseTrue[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; - content += "

Pyrotest: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "

"; #endif #ifdef NISSAN_LEAF_BATTERY From 320416e20458d7a5ad122a7fda4596c395902ba8 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sat, 21 Dec 2024 21:54:14 +1300 Subject: [PATCH 087/225] Update TESLA-BATTERY.cpp Update advance_battery_html.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 38 ++- .../webserver/advanced_battery_html.cpp | 253 +++++++++++++----- 2 files changed, 205 insertions(+), 86 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 7a46d0654..a9160a90e 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -51,10 +51,10 @@ static int16_t battery_amps = 0; // A static uint16_t battery_raw_amps = 0; // A static uint16_t battery_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable -static uint16_t BMS_maxRegenPower = 0; //rename from battery_regenerative_limit -static uint16_t BMS_maxDischargePower = 0; // rename from battery_discharge_limit -static uint16_t BMS_maxStationaryHeatPower = 0; //rename from battery_max_heat_park -static uint16_t BMS_hvacPowerBudget = 0; //rename from battery_hvac_max_power +static uint16_t BMS_maxRegenPower = 0; //rename from battery_regenerative_limit +static uint16_t BMS_maxDischargePower = 0; // rename from battery_discharge_limit +static uint16_t BMS_maxStationaryHeatPower = 0; //rename from battery_max_heat_park +static uint16_t BMS_hvacPowerBudget = 0; //rename from battery_hvac_max_power static uint8_t BMS_notEnoughPowerForHeatPump = 0; static uint8_t BMS_powerLimitState = 0; static uint8_t BMS_inverterTQF = 0; @@ -929,7 +929,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.battery_expected_energy_remaining_m1 = battery_expected_energy_remaining_m1; datalayer_extended.tesla.battery_full_charge_complete = battery_full_charge_complete; datalayer_extended.tesla.battery_fully_charged = battery_fully_charged; - //0x3D2 + //0x3D2 datalayer_extended.tesla.battery_total_discharge = battery_total_discharge; datalayer_extended.tesla.battery_total_charge = battery_total_charge; //0x392 @@ -987,7 +987,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.BMS_hvacPowerBudget = BMS_hvacPowerBudget; datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump = BMS_notEnoughPowerForHeatPump; datalayer_extended.tesla.BMS_powerLimitState = BMS_powerLimitState; - datalayer_extended.tesla.BMS_inverterTQF = BMS_inverterTQF; + datalayer_extended.tesla.BMS_inverterTQF = BMS_inverterTQF; //0x312 datalayer_extended.tesla.BMS_powerDissipation = BMS_powerDissipation; datalayer_extended.tesla.BMS_flowRequest = BMS_flowRequest; @@ -1150,7 +1150,7 @@ void receive_can_battery(CAN_frame rx_frame) { static uint16_t temp = 0; switch (rx_frame.ID) { - case 0x352: // 850 BMS_energyStatus newer BMS + case 0x352: // 850 BMS_energyStatus newer BMS mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X if (mux == 0) { @@ -1260,7 +1260,7 @@ void receive_can_battery(CAN_frame rx_frame) { battery_BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); battery_BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC break; - case 0x224: //548 PCS_dcdcStatus: + case 0x224: //548 PCS_dcdcStatus: battery_PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ; battery_PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" battery_PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" @@ -1288,12 +1288,22 @@ void receive_can_battery(CAN_frame rx_frame) { (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; break; case 0x252: //Limit //594 BMS_powerAvailable: - BMS_maxRegenPower = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW - BMS_maxDischargePower = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? - BMS_maxStationaryHeatPower = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]); //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW - BMS_hvacPowerBudget = (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))); //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? - BMS_notEnoughPowerForHeatPump = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver - BMS_powerLimitState = (rx_frame.data.u8[6] & (0x01U)); //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] 0 "NOT_CALCULATED_FOR_DRIVE" 1 "CALCULATED_FOR_DRIVE" + BMS_maxRegenPower = ((rx_frame.data.u8[1] << 8) | + rx_frame.data.u8[0]); //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW + BMS_maxDischargePower = + ((rx_frame.data.u8[3] << 8) | + rx_frame.data.u8[2]); //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? + BMS_maxStationaryHeatPower = + (((rx_frame.data.u8[5] & 0x03) << 8) | + rx_frame.data.u8[4]); //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW + BMS_hvacPowerBudget = + (((rx_frame.data.u8[7] << 6) | + ((rx_frame.data.u8[6] & 0xFC) >> 2))); //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? + BMS_notEnoughPowerForHeatPump = + ((rx_frame.data.u8[5] >> 2) & (0x01U)); //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver + BMS_powerLimitState = + (rx_frame.data.u8[6] & + (0x01U)); //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] 0 "NOT_CALCULATED_FOR_DRIVE" 1 "CALCULATED_FOR_DRIVE" BMS_inverterTQF = ((rx_frame.data.u8[7] >> 4) & (0x03U)); break; case 0x132: //battery amps/volts //HVBattAmpVolt diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 5959e761a..50d02dd81 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -294,21 +294,30 @@ String advanced_battery_processor(const String& var) { float dcdcLvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcLvBusVolt) * 0.0390625; float dcdcHvBusVolt = static_cast(datalayer_extended.tesla.battery_dcdcHvBusVolt) * 0.146484; float dcdcLvOutputCurrent = static_cast(datalayer_extended.tesla.battery_dcdcLvOutputCurrent) * 0.1; - float nominal_full_pack_energy = static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy) * 0.1; - float nominal_full_pack_energy_m0 = static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy_m0) * 0.02; - float nominal_energy_remaining = static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining) * 0.1; - float nominal_energy_remaining_m0 = static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining_m0) * 0.02; + float nominal_full_pack_energy = + static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy) * 0.1; + float nominal_full_pack_energy_m0 = + static_cast(datalayer_extended.tesla.battery_nominal_full_pack_energy_m0) * 0.02; + float nominal_energy_remaining = + static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining) * 0.1; + float nominal_energy_remaining_m0 = + static_cast(datalayer_extended.tesla.battery_nominal_energy_remaining_m0) * 0.02; float ideal_energy_remaining = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining) * 0.1; - float ideal_energy_remaining_m0 = static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining_m0) * 0.02; - float energy_to_charge_complete = static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete) * 0.1; - float energy_to_charge_complete_m1 = static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete_m1) * 0.02; + float ideal_energy_remaining_m0 = + static_cast(datalayer_extended.tesla.battery_ideal_energy_remaining_m0) * 0.02; + float energy_to_charge_complete = + static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete) * 0.1; + float energy_to_charge_complete_m1 = + static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete_m1) * 0.02; float energy_buffer = static_cast(datalayer_extended.tesla.battery_energy_buffer) * 0.1; float energy_buffer_m1 = static_cast(datalayer_extended.tesla.battery_energy_buffer_m1) * 0.01; - float expected_energy_remaining_m1 = static_cast(datalayer_extended.tesla.battery_expected_energy_remaining_m1) * 0.02; + float expected_energy_remaining_m1 = + static_cast(datalayer_extended.tesla.battery_expected_energy_remaining_m1) * 0.02; float total_discharge = static_cast(datalayer_extended.tesla.battery_total_discharge); float total_charge = static_cast(datalayer_extended.tesla.battery_total_charge); float packMass = static_cast(datalayer_extended.tesla.battery_packMass); - float platformMaxBusVoltage = static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage) * 0.1 + 375; + float platformMaxBusVoltage = + static_cast(datalayer_extended.tesla.battery_platformMaxBusVoltage) * 0.1 + 375; float bms_min_voltage = static_cast(datalayer_extended.tesla.battery_bms_min_voltage) * 0.01 * 2; float bms_max_voltage = static_cast(datalayer_extended.tesla.battery_bms_max_voltage) * 0.01 * 2; float max_charge_current = static_cast(datalayer_extended.tesla.battery_max_charge_current); @@ -322,25 +331,30 @@ String advanced_battery_processor(const String& var) { float BrickModelTMax = static_cast(datalayer_extended.tesla.battery_BrickTempMinNum) * 0.5 - 40; float BrickModelTMin = static_cast(datalayer_extended.tesla.battery_BrickModelTMin) * 0.5 - 40; float isolationResistance = static_cast(datalayer_extended.tesla.battery_BMS_isolationResistance) * 10; - float PCS_dcdcMaxOutputCurrentAllowed = static_cast(datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed) * 0.1; + float PCS_dcdcMaxOutputCurrentAllowed = + static_cast(datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed) * 0.1; float PCS_dcdcTemp = static_cast(datalayer_extended.tesla.PCS_dcdcTemp * 0.1 + 40); float PCS_ambientTemp = static_cast(datalayer_extended.tesla.PCS_ambientTemp) * 0.1 + 40; float BMS_maxRegenPower = static_cast(datalayer_extended.tesla.BMS_maxRegenPower) * 0.01; float BMS_maxDischargePower = static_cast(datalayer_extended.tesla.BMS_maxDischargePower) * 0.013; float BMS_maxStationaryHeatPower = static_cast(datalayer_extended.tesla.BMS_maxStationaryHeatPower) * 0.01; float BMS_hvacPowerBudget = static_cast(datalayer_extended.tesla.BMS_hvacPowerBudget) * 0.02; - float BMS_powerDissipation = static_cast(datalayer_extended.tesla.BMS_powerDissipation) * 0.02; + float BMS_powerDissipation = static_cast(datalayer_extended.tesla.BMS_powerDissipation) * 0.02; float BMS_flowRequest = static_cast(datalayer_extended.tesla.BMS_flowRequest) * 0.3; - float BMS_inletActiveCoolTargetT = static_cast(datalayer_extended.tesla.BMS_inletActiveCoolTargetT) * 0.25 - 25; + float BMS_inletActiveCoolTargetT = + static_cast(datalayer_extended.tesla.BMS_inletActiveCoolTargetT) * 0.25 - 25; float BMS_inletPassiveTargetT = static_cast(datalayer_extended.tesla.BMS_inletPassiveTargetT) * 0.25 - 25; - float BMS_inletActiveHeatTargetT = static_cast(datalayer_extended.tesla.BMS_inletActiveHeatTargetT) * 0.25 - 25; + float BMS_inletActiveHeatTargetT = + static_cast(datalayer_extended.tesla.BMS_inletActiveHeatTargetT) * 0.25 - 25; float BMS_packTMin = static_cast(datalayer_extended.tesla.BMS_packTMin); float BMS_packTMax = static_cast(datalayer_extended.tesla.BMS_packTMax); float PCS_dcdcMaxLvOutputCurrent = static_cast(datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent) * 0.1; float PCS_dcdcCurrentLimit = static_cast(datalayer_extended.tesla.PCS_dcdcCurrentLimit) * 0.1; - float PCS_dcdcLvOutputCurrentTempLimit = static_cast(datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit) * 0.1; + float PCS_dcdcLvOutputCurrentTempLimit = + static_cast(datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit) * 0.1; float PCS_dcdcUnifiedCommand = static_cast(datalayer_extended.tesla.PCS_dcdcUnifiedCommand) * 0.001; - float PCS_dcdcCLAControllerOutput = static_cast(datalayer_extended.tesla.PCS_dcdcCLAControllerOutput * 0.001); + float PCS_dcdcCLAControllerOutput = + static_cast(datalayer_extended.tesla.PCS_dcdcCLAControllerOutput * 0.001); float PCS_dcdcTankVoltage = static_cast(datalayer_extended.tesla.PCS_dcdcTankVoltage); float PCS_dcdcTankVoltageTarget = static_cast(datalayer_extended.tesla.PCS_dcdcTankVoltageTarget); float PCS_dcdcClaCurrentFreq = static_cast(datalayer_extended.tesla.PCS_dcdcClaCurrentFreq) * 0.0976563; @@ -348,14 +362,21 @@ String advanced_battery_processor(const String& var) { float PCS_dcdcShortTimeUs = static_cast(datalayer_extended.tesla.PCS_dcdcShortTimeUs) * 0.000488281; float PCS_dcdcHalfPeriodUs = static_cast(datalayer_extended.tesla.PCS_dcdcHalfPeriodUs) * 0.000488281; float PCS_dcdcIntervalMaxFrequency = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxFrequency); - float PCS_dcdcIntervalMaxHvBusVolt = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxHvBusVolt) * 0.1; - float PCS_dcdcIntervalMaxLvBusVolt = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvBusVolt) * 0.1; - float PCS_dcdcIntervalMaxLvOutputCurr = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvOutputCurr); + float PCS_dcdcIntervalMaxHvBusVolt = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxHvBusVolt) * 0.1; + float PCS_dcdcIntervalMaxLvBusVolt = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvBusVolt) * 0.1; + float PCS_dcdcIntervalMaxLvOutputCurr = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvOutputCurr); float PCS_dcdcIntervalMinFrequency = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinFrequency); - float PCS_dcdcIntervalMinHvBusVolt = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinHvBusVolt) * 0.1; - float PCS_dcdcIntervalMinLvBusVolt = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinLvBusVolt) * 0.1; - float PCS_dcdcIntervalMinLvOutputCurr = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr); - float PCS_dcdc12vSupportLifetimekWh = static_cast(datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh) * 0.01; + float PCS_dcdcIntervalMinHvBusVolt = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinHvBusVolt) * 0.1; + float PCS_dcdcIntervalMinLvBusVolt = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinLvBusVolt) * 0.1; + float PCS_dcdcIntervalMinLvOutputCurr = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr); + float PCS_dcdc12vSupportLifetimekWh = + static_cast(datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh) * 0.01; float HVP_hvp1v5Ref = static_cast(datalayer_extended.tesla.HVP_hvp1v5Ref) * 0.1; float HVP_shuntCurrentDebug = static_cast(datalayer_extended.tesla.HVP_shuntCurrentDebug) * 0.1; float HVP_dcLinkVoltage = static_cast(datalayer_extended.tesla.HVP_dcLinkVoltage) * 0.1; @@ -380,16 +401,57 @@ String advanced_battery_processor(const String& var) { float HVP_shuntBarTempDbg = static_cast(datalayer_extended.tesla.HVP_shuntBarTempDbg) * 0.01; float HVP_shuntAsicTempDbg = static_cast(datalayer_extended.tesla.HVP_shuntAsicTempDbg) * 0.01; - static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"}; - static const char* hvilStatusState[] = {"NOT Ok", "STATUS_OK", "CURRENT_SOURCE_FAULT", "INTERNAL_OPEN_FAULT", "VEHICLE_OPEN_FAULT", "PENTHOUSE_LID_OPEN_FAULT", "UNKNOWN_LOCATION_OPEN_FAULT", "VEHICLE_NODE_FAULT", "NO_12V_SUPPLY", "VEHICLE_OR_PENTHOUSE_LID_OPENFAULT", "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)", "UNKNOWN(13)", "UNKNOWN(14)", "UNKNOWN(15)"}; - static const char* contactorState[] = {"SNA", "OPEN", "PRECHARGE", "BLOCKED", "PULLED_IN", "OPENING", "ECONOMIZED", "WELDED", "UNKNOWN(8)", "UNKNOWN(9)", "UNKNOWN(10)", "UNKNOWN(11)"}; - static const char* BMS_state[] = {"STANDBY", "DRIVE", "SUPPORT", "CHARGE", "FEIM", "CLEAR_FAULT", "FAULT", "WELD", "TEST", "SNA"}; + static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", + "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", + "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"}; + static const char* hvilStatusState[] = {"NOT Ok", + "STATUS_OK", + "CURRENT_SOURCE_FAULT", + "INTERNAL_OPEN_FAULT", + "VEHICLE_OPEN_FAULT", + "PENTHOUSE_LID_OPEN_FAULT", + "UNKNOWN_LOCATION_OPEN_FAULT", + "VEHICLE_NODE_FAULT", + "NO_12V_SUPPLY", + "VEHICLE_OR_PENTHOUSE_LID_OPENFAULT", + "UNKNOWN(10)", + "UNKNOWN(11)", + "UNKNOWN(12)", + "UNKNOWN(13)", + "UNKNOWN(14)", + "UNKNOWN(15)"}; + static const char* contactorState[] = {"SNA", "OPEN", "PRECHARGE", "BLOCKED", + "PULLED_IN", "OPENING", "ECONOMIZED", "WELDED", + "UNKNOWN(8)", "UNKNOWN(9)", "UNKNOWN(10)", "UNKNOWN(11)"}; + static const char* BMS_state[] = {"STANDBY", "DRIVE", "SUPPORT", "CHARGE", "FEIM", + "CLEAR_FAULT", "FAULT", "WELD", "TEST", "SNA"}; static const char* BMS_contactorState[] = {"SNA", "OPEN", "OPENING", "CLOSING", "CLOSED", "WELDED", "BLOCKED"}; - static const char* BMS_hvState[] = {"DOWN", "COMING_UP", "GOING_DOWN", "UP_FOR_DRIVE", "UP_FOR_CHARGE", "UP_FOR_DC_CHARGE", "UP"}; - static const char* BMS_uiChargeStatus[] = {"DISCONNECTED", "NO_POWER", "ABOUT_TO_CHARGE", "CHARGING", "CHARGE_COMPLETE", "CHARGE_STOPPED"}; + static const char* BMS_hvState[] = {"DOWN", "COMING_UP", "GOING_DOWN", "UP_FOR_DRIVE", + "UP_FOR_CHARGE", "UP_FOR_DC_CHARGE", "UP"}; + static const char* BMS_uiChargeStatus[] = {"DISCONNECTED", "NO_POWER", "ABOUT_TO_CHARGE", + "CHARGING", "CHARGE_COMPLETE", "CHARGE_STOPPED"}; static const char* PCS_dcdcStatus[] = {"IDLE", "ACTIVE", "FAULTED"}; - static const char* PCS_dcdcMainState[] = {"STANDBY", "12V_SUPPORT_ACTIVE", "PRECHARGE_STARTUP", "PRECHARGE_ACTIVE", "DIS_HVBUS_ACTIVE", "SHUTDOWN", "FAULTED"}; - static const char* PCS_dcdcSubState[] = {"PWR_UP_INIT", "STANDBY", "12V_SUPPORT_ACTIVE", "DIS_HVBUS", "PCHG_FAST_DIS_HVBUS", "PCHG_SLOW_DIS_HVBUS", "PCHG_DWELL_CHARGE", "PCHG_DWELL_WAIT", "PCHG_DI_RECOVERY_WAIT", "PCHG_ACTIVE", "PCHG_FLT_FAST_DIS_HVBUS", "SHUTDOWN", "12V_SUPPORT_FAULTED", "DIS_HVBUS_FAULTED", "PCHG_FAULTED", "CLEAR_FAULTS", "FAULTED", "NUM"}; + static const char* PCS_dcdcMainState[] = {"STANDBY", "12V_SUPPORT_ACTIVE", "PRECHARGE_STARTUP", + "PRECHARGE_ACTIVE", "DIS_HVBUS_ACTIVE", "SHUTDOWN", + "FAULTED"}; + static const char* PCS_dcdcSubState[] = {"PWR_UP_INIT", + "STANDBY", + "12V_SUPPORT_ACTIVE", + "DIS_HVBUS", + "PCHG_FAST_DIS_HVBUS", + "PCHG_SLOW_DIS_HVBUS", + "PCHG_DWELL_CHARGE", + "PCHG_DWELL_WAIT", + "PCHG_DI_RECOVERY_WAIT", + "PCHG_ACTIVE", + "PCHG_FLT_FAST_DIS_HVBUS", + "SHUTDOWN", + "12V_SUPPORT_FAULTED", + "DIS_HVBUS_FAULTED", + "PCHG_FAULTED", + "CLEAR_FAULTS", + "FAULTED", + "NUM"}; static const char* BMS_powerLimitState[] = {"NOT_CALCULATED_FOR_DRIVE", "CALCULATED_FOR_DRIVE"}; static const char* HVP_status[] = {"INVALID", "NOT_AVAILABLE", "STALE", "VALID"}; static const char* falseTrue[] = {"False", "True"}; @@ -397,15 +459,22 @@ String advanced_battery_processor(const String& var) { //0x20A 522 HVP_contatorState content += "

Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "

"; content += "

HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "

"; - content += "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; - content += "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; + content += + "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; + content += + "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; content += "

Closing allowed?: " + String(falseTrue[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; content += "

Pyrotest in Progress: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "

"; - content += "

Contactors Open Now Requested: " + String(falseTrue[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; - content += "

Contactors Open Requested; " + String(falseTrue[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + "

"; - content += "

Contactors Request Status; " + String(falseTrue[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; - content += "

Contactors Reset Request Required; " + String(falseTrue[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; - content += "

DC Link Allowed to Energize;" + String(falseTrue[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + "

"; + content += "

Contactors Open Now Requested: " + + String(falseTrue[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; + content += "

Contactors Open Requested; " + + String(falseTrue[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + "

"; + content += "

Contactors Request Status; " + + String(falseTrue[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; + content += "

Contactors Reset Request Required; " + + String(falseTrue[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; + content += "

DC Link Allowed to Energize;" + + String(falseTrue[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + "

"; // Comment what data you would like to dislay, order can be changed. //0x292 658 BMS_socStates content += "

Battery Beginning of Life: " + String(beginning_of_life) + " KWh

"; @@ -422,21 +491,37 @@ String advanced_battery_processor(const String& var) { content += "

PCS dcdc Temp: " + String(PCS_dcdcTemp) + " DegC

"; content += "

PCS Ambient Temp: " + String(PCS_ambientTemp) + " DegC

"; //0x224 548 PCS_dcdcStatus - content += "

Precharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcPrechargeStatus]) + "

"; - content += "

12V Support Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdc12VSupportStatus]) + "

"; - content += "

HV Bus Discharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcHvBusDischargeStatus]) + "

"; - content += "

Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "

"; - content += "

Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "

"; + content += + "

Precharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcPrechargeStatus]) + + "

"; + content += + "

12V Support Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdc12VSupportStatus]) + + "

"; + content += "

HV Bus Discharge Status: " + + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcHvBusDischargeStatus]) + "

"; + content += + "

Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "

"; + content += + "

Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "

"; content += "

PCS Faulted: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcFaulted]) + "

"; - content += "

Output Is Limited: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + "

"; + content += + "

Output Is Limited: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + "

"; content += "

Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A

"; - content += "

Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) + "

"; - content += "

12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) + "

"; - content += "

Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) + "

"; - content += "

PWM Enable Line: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + "

"; - content += "

Supporting Fixed LV Target: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "

"; - content += "

Precharge Restart Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "

"; - content += "

Initial Precharge Substate: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "

"; + content += "

Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) + + "

"; + content += + "

12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) + + "

"; + content += "

Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) + + "

"; + content += + "

PWM Enable Line: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + "

"; + content += "

Supporting Fixed LV Target: " + + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "

"; + content += "

Precharge Restart Cnt: " + + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "

"; + content += "

Initial Precharge Substate: " + + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "

"; //0x2C4 708 PCS_logging content += "

PCS_dcdcMaxLvOutputCurrent: " + String(PCS_dcdcMaxLvOutputCurrent) + " A

"; content += "

PCS_dcdcCurrentLimit: " + String(PCS_dcdcCurrentLimit) + " A

"; @@ -463,21 +548,26 @@ String advanced_battery_processor(const String& var) { content += "

Total Charge: " + String(total_charge) + " KWh

"; //0x212 530 BMS_status content += "

Isolation Resistance: " + String(isolationResistance) + " kOhms

"; - content += "

BMS Contactor State: " + String(BMS_contactorState[datalayer_extended.tesla.battery_BMS_contactorState]) + "

"; + content += + "

BMS Contactor State: " + String(BMS_contactorState[datalayer_extended.tesla.battery_BMS_contactorState]) + + "

"; content += "

BMS State: " + String(BMS_state[datalayer_extended.tesla.battery_BMS_state]) + "

"; content += "

BMS HV State: " + String(BMS_hvState[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; - content += "

BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; - content += "

BMS PCS PWM Enabled: " + String(noYes[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; + content += "

BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) + + "

"; + content += + "

BMS PCS PWM Enabled: " + String(noYes[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; //0x352 850 BMS_energyStatus - content += "

Early BMS 0x352"; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " KWh

"; content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " KWh

"; content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer) + " KWh

"; - content += "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; + content += + "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; //0x352 850 BMS_energyStatus - content += "

Late BMS 0x352 with Mux2021 and comment 0x352 with MUX + content += "

Late BMS 0x352 with Mux2021 and comment 0x352 with MUX content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh

"; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh

"; content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining_m0) + " KWh

"; @@ -508,8 +598,11 @@ String advanced_battery_processor(const String& var) { content += "

Max Discharge Power: " + String(BMS_maxDischargePower) + " KW

"; content += "

Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh

"; content += "

HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW

"; - content += "

Not Enough Power For Heat Pump: " + String(noYes[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + " KW

"; - content += "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; + content += + "

Not Enough Power For Heat Pump: " + String(noYes[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + + " KW

"; + content += + "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; content += "

Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "

"; //0x312 786 BMS_thermalStatus content += "

Power Dissipation: " + String(BMS_powerDissipation) + " kW

"; @@ -519,31 +612,44 @@ String advanced_battery_processor(const String& var) { content += "

Inlet Active Heat Target Temp: " + String(BMS_inletActiveHeatTargetT) + " DegC

"; content += "

Pack Temp Min: " + String(BMS_packTMin) + " DegC

"; content += "

Pack Temp Max: " + String(BMS_packTMax) + " DegC

"; - content += "

PCS No Flow Request: " + String(falseTrue[ datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "

"; + content += "

PCS No Flow Request: " + String(falseTrue[datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "

"; content += "

BMS No Flow Request: " + String(falseTrue[datalayer_extended.tesla.BMS_noFlowRequest]) + "

"; //0x7AA 1962 HVP_debugMessage - content += "

HVP_gpioPassivePyroDepl: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) + "

"; + content += + "

HVP_gpioPassivePyroDepl: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) + "

"; content += "

HVP_gpioPyroIsoEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPyroIsoEn]) + "

"; content += "

HVP_gpioCpFaultIn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpFaultIn]) + "

"; - content += "

HVP_gpioPackContPowerEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) + "

"; + content += + "

HVP_gpioPackContPowerEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) + "

"; content += "

HVP_gpioHvCablesOk: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvCablesOk]) + "

"; - content += "

HVP_gpioHvpSelfEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "

"; + content += + "

HVP_gpioHvpSelfEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "

"; content += "

HVP_gpioLed: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioLed]) + "

"; content += "

HVP_gpioCrashSignal: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCrashSignal]) + "

"; - content += "

HVP_gpioShuntDataReady: " + String(falseTrue[ datalayer_extended.tesla.HVP_gpioShuntDataReady]) + "

"; - content += "

HVP_gpioFcContPosAux: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "

"; - content += "

HVP_gpioFcContNegAux: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "

"; + content += + "

HVP_gpioShuntDataReady: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioShuntDataReady]) + "

"; + content += + "

HVP_gpioFcContPosAux: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "

"; + content += + "

HVP_gpioFcContNegAux: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "

"; content += "

HVP_gpioBmsEout: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioBmsEout]) + "

"; content += "

HVP_gpioCpFaultOut: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpFaultOut]) + "

"; content += "

HVP_gpioPyroPor: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPyroPor]) + "

"; content += "

HVP_gpioShuntEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioShuntEn]) + "

"; content += "

HVP_gpioHvpVerEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvpVerEn]) + "

"; - content += "

HVP_gpioPackCoontPosFlywheel: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) + "

"; - content += "

HVP_gpioCpLatchEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "

"; + content += "

HVP_gpioPackCoontPosFlywheel: " + + String(falseTrue[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) + "

"; + content += + "

HVP_gpioCpLatchEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "

"; content += "

HVP_gpioPcsEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsEnable]) + "

"; - content += "

HVP_gpioPcsDcdcPwmEnable: " + String(falseTrue[ datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) + "

"; - content += "

HVP_gpioPcsChargePwmEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable]) + "

"; - content += "

HVP_gpioFcContPowerEnable: " + String(falseTrue[ datalayer_extended.tesla.HVP_gpioFcContPowerEnable]) + "

"; + content += "

HVP_gpioPcsDcdcPwmEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) + + "

"; + content += + "

HVP_gpioPcsChargePwmEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable]) + + "

"; + content += + "

HVP_gpioFcContPowerEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContPowerEnable]) + + "

"; content += "

HVP_gpioHvilEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvilEnable]) + "

"; content += "

HVP_gpioSecDrdy: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioSecDrdy]) + "

"; content += "

HVP_hvp1v5Ref: " + String(HVP_hvp1v5Ref) + " V

"; @@ -551,8 +657,11 @@ String advanced_battery_processor(const String& var) { content += "

HVP_packCurrentMia: " + String(falseTrue[datalayer_extended.tesla.HVP_packCurrentMia]) + "

"; content += "

HVP_auxCurrentMia: " + String(falseTrue[datalayer_extended.tesla.HVP_auxCurrentMia]) + "

"; content += "

HVP_currentSenseMia: " + String(falseTrue[datalayer_extended.tesla.HVP_currentSenseMia]) + "

"; - content += "

HVP_shuntRefVoltageMismatch: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) + "

"; - content += "

HVP_shuntThermistorMia: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntThermistorMia]) + "

"; + content += + "

HVP_shuntRefVoltageMismatch: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) + + "

"; + content += + "

HVP_shuntThermistorMia: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntThermistorMia]) + "

"; content += "

HVP_shuntHwMia: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntHwMia]) + "

"; content += "

HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V

"; content += "

HVP_packVoltage: " + String(HVP_packVoltage) + " V

"; From 1ea1746e326cb8b8edf5ce260caa0cd100ce936e Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sat, 21 Dec 2024 23:33:34 +1300 Subject: [PATCH 088/225] Update datalayer_extended.h --- Software/src/datalayer/datalayer_extended.h | 132 ++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 0d9b2d3fe..5bbedb29b 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -180,6 +180,11 @@ typedef struct { /** uint8_t */ /** Pyro test in progress */ uint8_t pyroTestInProgress = 0; + uint8_t battery_packCtrsOpenNowRequested = 0; + uint8_t battery_packCtrsOpenRequested = 0; + uint8_t battery_packCtrsRequestStatus = 0; + uint8_t battery_packCtrsResetRequestRequired = 0; + uint8_t battery_dcLinkAllowedToEnergize = 0; uint8_t battery_beginning_of_life = 0; uint8_t battery_battTempPct = 0; uint16_t battery_dcdcLvBusVolt = 0; @@ -195,10 +200,20 @@ typedef struct { uint16_t battery_energy_to_charge_complete_m1 = 0; uint16_t battery_energy_buffer = 0; uint16_t battery_energy_buffer_m1 = 0; + uint16_t battery_expected_energy_remaining = 0; + uint16_t battery_expected_energy_remaining_m1 = 0; uint16_t battery_full_charge_complete = 0; uint8_t battery_fully_charged = 0; uint16_t battery_total_discharge = 0; uint16_t battery_total_charge = 0; + uint16_t battery_BrickVoltageMax = 0; + uint16_t battery_BrickVoltageMin = 0; + uint8_t battery_BrickVoltageMaxNum = 0; + uint8_t battery_BrickVoltageMinNum = 0; + uint8_t battery_BrickTempMaxNum = 0; + uint8_t battery_BrickTempMinNum = 0; + uint8_t battery_BrickModelTMax = 0; + uint8_t battery_BrickModelTMin = 0; uint16_t battery_packConfigMultiplexer = 0; uint16_t battery_moduleType = 0; uint16_t battery_reservedConfig = 0; @@ -212,6 +227,123 @@ typedef struct { uint32_t battery_soc_max = 0; uint32_t battery_soc_ave = 0; uint32_t battery_soc_ui = 0; + uint8_t battery_BMS_contactorState = 0; + uint8_t battery_BMS_state = 0; + uint8_t battery_BMS_hvState = 0; + uint16_t battery_BMS_isolationResistance = 0; + uint8_t battery_BMS_uiChargeStatus = 0; + uint8_t battery_BMS_diLimpRequest = 0; + uint16_t battery_BMS_chgPowerAvailable = 0; + uint8_t battery_BMS_pcsPwmEnabled = 0; + uint8_t battery_PCS_dcdcPrechargeStatus = 0; + uint8_t battery_PCS_dcdc12VSupportStatus = 0; + uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0; + uint8_t battery_PCS_dcdcMainState = 0; + uint8_t battery_PCS_dcdcSubState = 0; + uint8_t battery_PCS_dcdcFaulted = 0; + uint8_t battery_PCS_dcdcOutputIsLimited = 0; + uint16_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0; + uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0; + uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0; + uint8_t battery_PCS_dcdcDischargeRtyCnt = 0; + uint8_t battery_PCS_dcdcPwmEnableLine = 0; + uint8_t battery_PCS_dcdcSupportingFixedLvTarget = 0; + uint8_t battery_PCS_dcdcPrechargeRestartCnt = 0; + uint8_t battery_PCS_dcdcInitialPrechargeSubState = 0; + uint16_t BMS_maxRegenPower = 0; + uint16_t BMS_maxDischargePower = 0; + uint16_t BMS_maxStationaryHeatPower = 0; + uint16_t BMS_hvacPowerBudget = 0; + uint8_t BMS_notEnoughPowerForHeatPump = 0; + uint8_t BMS_powerLimitState = 0; + uint8_t BMS_inverterTQF = 0; + uint16_t BMS_powerDissipation = 0; + uint8_t BMS_flowRequest = 0; + uint16_t BMS_inletActiveCoolTargetT = 0; + uint16_t BMS_inletPassiveTargetT = 0; + uint16_t BMS_inletActiveHeatTargetT = 0; + uint16_t BMS_packTMin = 0; + uint16_t BMS_packTMax = 0; + uint8_t BMS_pcsNoFlowRequest = 0; + uint8_t BMS_noFlowRequest = 0; + uint16_t PCS_dcdcTemp = 0; + uint16_t PCS_ambientTemp = 0; + uint16_t PCS_dcdcMaxLvOutputCurrent = 0; + uint16_t PCS_dcdcCurrentLimit = 0; + uint16_t PCS_dcdcLvOutputCurrentTempLimit = 0; + uint16_t PCS_dcdcUnifiedCommand = 0; + uint16_t PCS_dcdcCLAControllerOutput = 0; + uint16_t PCS_dcdcTankVoltage = 0; + uint16_t PCS_dcdcTankVoltageTarget = 0; + uint16_t PCS_dcdcClaCurrentFreq = 0; + uint16_t PCS_dcdcTCommMeasured = 0; + uint16_t PCS_dcdcShortTimeUs = 0; + uint16_t PCS_dcdcHalfPeriodUs = 0; + uint16_t PCS_dcdcIntervalMaxFrequency = 0; + uint16_t PCS_dcdcIntervalMaxHvBusVolt = 0; + uint16_t PCS_dcdcIntervalMaxLvBusVolt = 0; + uint16_t PCS_dcdcIntervalMaxLvOutputCurr = 0; + uint16_t PCS_dcdcIntervalMinFrequency = 0; + uint16_t PCS_dcdcIntervalMinHvBusVolt = 0; + uint16_t PCS_dcdcIntervalMinLvBusVolt = 0; + uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0; + uint32_t PCS_dcdc12vSupportLifetimekWh = 0; + uint8_t HVP_gpioPassivePyroDepl = 0; + uint8_t HVP_gpioPyroIsoEn = 0; + uint8_t HVP_gpioCpFaultIn = 0; + uint8_t HVP_gpioPackContPowerEn = 0; + uint8_t HVP_gpioHvCablesOk = 0; + uint8_t HVP_gpioHvpSelfEnable = 0; + uint8_t HVP_gpioLed = 0; + uint8_t HVP_gpioCrashSignal = 0; + uint8_t HVP_gpioShuntDataReady = 0; + uint8_t HVP_gpioFcContPosAux = 0; + uint8_t HVP_gpioFcContNegAux = 0; + uint8_t HVP_gpioBmsEout = 0; + uint8_t HVP_gpioCpFaultOut = 0; + uint8_t HVP_gpioPyroPor = 0; + uint8_t HVP_gpioShuntEn = 0; + uint8_t HVP_gpioHvpVerEn = 0; + uint8_t HVP_gpioPackCoontPosFlywheel = 0; + uint8_t HVP_gpioCpLatchEnable = 0; + uint8_t HVP_gpioPcsEnable = 0; + uint8_t HVP_gpioPcsDcdcPwmEnable = 0; + uint8_t HVP_gpioPcsChargePwmEnable = 0; + uint8_t HVP_gpioFcContPowerEnable = 0; + uint8_t HVP_gpioHvilEnable = 0; + uint8_t HVP_gpioSecDrdy = 0; + uint16_t HVP_hvp1v5Ref = 0; + uint16_t HVP_shuntCurrentDebug = 0; + uint8_t HVP_packCurrentMia = 0; + uint8_t HVP_auxCurrentMia = 0; + uint8_t HVP_currentSenseMia = 0; + uint8_t HVP_shuntRefVoltageMismatch = 0; + uint8_t HVP_shuntThermistorMia = 0; + uint8_t HVP_shuntHwMia = 0; + uint16_t HVP_dcLinkVoltage = 0; + uint16_t HVP_packVoltage = 0; + uint16_t HVP_fcLinkVoltage = 0; + uint16_t HVP_packContVoltage = 0; + uint16_t HVP_packNegativeV = 0; + uint16_t HVP_packPositiveV = 0; + uint16_t HVP_pyroAnalog = 0; + uint16_t HVP_dcLinkNegativeV = 0; + uint16_t HVP_dcLinkPositiveV = 0; + uint16_t HVP_fcLinkNegativeV = 0; + uint16_t HVP_fcContCoilCurrent = 0; + uint16_t HVP_fcContVoltage = 0; + uint16_t HVP_hvilInVoltage = 0; + uint16_t HVP_hvilOutVoltage = 0; + uint16_t HVP_fcLinkPositiveV = 0; + uint16_t HVP_packContCoilCurrent = 0; + uint16_t HVP_battery12V = 0; + uint16_t HVP_shuntRefVoltageDbg = 0; + uint16_t HVP_shuntAuxCurrentDbg = 0; + uint16_t HVP_shuntBarTempDbg = 0; + uint16_t HVP_shuntAsicTempDbg = 0; + uint8_t HVP_shuntAuxCurrentStatus = 0; + uint8_t HVP_shuntBarTempStatus = 0; + uint8_t HVP_shuntAsicTempStatus = 0; } DATALAYER_INFO_TESLA; typedef struct { From ff6727da113431ec3c89643c7e42b408d95429fb Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sun, 22 Dec 2024 00:00:41 +1300 Subject: [PATCH 089/225] Update advanced_battery_html.cpp --- Software/src/devboard/webserver/advanced_battery_html.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 649589295..01b84c6b0 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -574,7 +574,7 @@ String advanced_battery_processor(const String& var) { content += "

Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer_m1) + " KWh

"; content += "

Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " KWh

"; - content += "

Fully Charged: " + String(noYes[datalayer_extended.battery_fully_charged]) + "

"; + content += "

Fully Charged: " + String(noYes[datalayer_extended.tesla.battery_fully_charged]) + "

"; //0x392 BMS_packConfig content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; @@ -684,9 +684,9 @@ String advanced_battery_processor(const String& var) { content += "

HVP_shuntAuxCurrentDbg: " + String(HVP_shuntAuxCurrentDbg) + " A

"; content += "

HVP_shuntBarTempDbg: " + String(HVP_shuntBarTempDbg) + " DegC

"; content += "

HVP_shuntAsicTempDbg: " + String(HVP_shuntAsicTempDbg) + " DegC

"; - content += "

HVP_shuntAuxCurrentStatus: " + String(HVP_status) + "

"; - content += "

HVP_shuntBarTempStatus: " + String(HVP_status) + "

"; - content += "

HVP_shuntAsicTempStatus: " + String(HVP_status) + "

"; + content += "

HVP_shuntAuxCurrentStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAuxCurrentStatus]) + "

"; + content += "

HVP_shuntBarTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntBarTempStatus]) + "

"; + content += "

HVP_shuntAsicTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAsicTempStatus]) + "

"; #endif From 333bcef917fa91871887401d708931cdbee30e9a Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sun, 22 Dec 2024 00:00:59 +1300 Subject: [PATCH 090/225] Update advanced_battery_html.cpp --- .../src/devboard/webserver/advanced_battery_html.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 01b84c6b0..c8fc14c33 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -684,9 +684,13 @@ String advanced_battery_processor(const String& var) { content += "

HVP_shuntAuxCurrentDbg: " + String(HVP_shuntAuxCurrentDbg) + " A

"; content += "

HVP_shuntBarTempDbg: " + String(HVP_shuntBarTempDbg) + " DegC

"; content += "

HVP_shuntAsicTempDbg: " + String(HVP_shuntAsicTempDbg) + " DegC

"; - content += "

HVP_shuntAuxCurrentStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAuxCurrentStatus]) + "

"; - content += "

HVP_shuntBarTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntBarTempStatus]) + "

"; - content += "

HVP_shuntAsicTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAsicTempStatus]) + "

"; + content += + "

HVP_shuntAuxCurrentStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAuxCurrentStatus]) + + "

"; + content += + "

HVP_shuntBarTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntBarTempStatus]) + "

"; + content += "

HVP_shuntAsicTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAsicTempStatus]) + + "

"; #endif From 8870027d75770ae76bfe744b377200eb0b7731bf Mon Sep 17 00:00:00 2001 From: No-Signal Date: Sun, 8 Dec 2024 11:30:10 +0000 Subject: [PATCH 091/225] Moving secrets from USER_SETTINGS to USER_SECRETS.h --- .gitignore | 3 +++ README.md | 3 ++- Software/USER_SECRETS.TEMPLATE.h | 8 ++++++++ Software/USER_SETTINGS.cpp | 21 +++++++++++---------- Software/USER_SETTINGS.h | 1 - Software/src/devboard/mqtt/mqtt.cpp | 1 + 6 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 Software/USER_SECRETS.TEMPLATE.h diff --git a/.gitignore b/.gitignore index f4dd4582f..f0e530d2e 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ compile.bat # Ignore binary files *.bin + +# Ignore secret file +USER_SECRETS.h \ No newline at end of file diff --git a/README.md b/README.md index c2d9630c3..d3acd4be2 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,8 @@ For more examples showing wiring, see each battery types own Wiki page. For inst 5. The Arduino board should be set to `ESP32 Dev Module` (under `Tools` -> `Board` -> `ESP32 Arduino`) with the following settings: ![alt text](https://github.com/Xinyuan-LilyGO/T-CAN485/blob/main/img/arduino_setting.png) 6. Select which battery type you will use, along with other optional settings. This is done in the `USER_SETTINGS.h` file. -7. Press `Verify` and `Upload` to send the sketch to the board. +7. Copy the `USER_SECRETS.TEMPLATE.h` file to `USER_SECRETS.h` and update relevant secrets. +8. Press `Verify` and `Upload` to send the sketch to the board. NOTE: In some cases, the LilyGo must be powered through the main power connector instead of USB-C when performing the initial firmware upload. NOTE: On Mac, the following USB driver may need to be installed: https://github.com/WCHSoftGroup/ch34xser_macos diff --git a/Software/USER_SECRETS.TEMPLATE.h b/Software/USER_SECRETS.TEMPLATE.h new file mode 100644 index 000000000..eaf5ced13 --- /dev/null +++ b/Software/USER_SECRETS.TEMPLATE.h @@ -0,0 +1,8 @@ +#define WIFI_SSID "REPLACE_WITH_YOUR_SSID" // Maximum of 63 characters +#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD" // Minimum of 8 characters +#define AP_PASSWORD "123456789" // Minimum of 8 characters; set to blank if you want the access point to be open +#define HTTP_USERNAME "admin" // username to webserver authentication; +#define HTTP_PASSWORD "admin" // password to webserver authentication; +#define MQTT_SERVER "192.168.xxx.yyy" // mqtt server address +#define MQTT_USER NULL // mqtt username, leave blank for no authentication +#define MQTT_PASSWORD NULL // mqtt password, leave blank for no authentication diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 7c2309b4a..7c406893c 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -1,5 +1,6 @@ #include "USER_SETTINGS.h" #include +#include "USER_SECRETS.h" #include "src/devboard/hal/hal.h" /* This file contains all the battery settings and limits */ @@ -21,12 +22,12 @@ volatile CAN_Configuration can_config = { #ifdef WIFI -volatile uint8_t AccessPointEnabled = true; //Set to either true/false to enable direct wifi access point -std::string ssid = "REPLACE_WITH_YOUR_SSID"; // Maximum of 63 characters -std::string password = "REPLACE_WITH_YOUR_PASSWORD"; // Minimum of 8 characters -const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface -const char* passwordAP = "123456789"; // Minimum of 8 characters; set to NULL if you want the access point to be open -const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection +volatile uint8_t AccessPointEnabled = true; //Set to either true/false to enable direct wifi access point +std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h +std::string password = WIFI_PASSWORD; // Set in USER_SECRETS.h +const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface +const char* passwordAP = AP_PASSWORD; // Set in USER_SECRETS.h +const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection #ifdef WIFICONFIG // Set your Static IP address @@ -37,14 +38,14 @@ IPAddress gateway(192, 168, 10, 1); IPAddress subnet(255, 255, 255, 0); #endif #ifdef WEBSERVER -const char* http_username = "admin"; // username to webserver authentication; -const char* http_password = "admin"; // password to webserver authentication; +const char* http_username = HTTP_USERNAME; // Set in USER_SECRETS.h +const char* http_password = HTTP_PASSWORD; // Set in USER_SECRETS.h #endif // WEBSERVER // MQTT #ifdef MQTT -const char* mqtt_user = "REDACTED"; // Set NULL for no username -const char* mqtt_password = "REDACTED"; // Set NULL for no password +const char* mqtt_user = MQTT_USER; // Set in USER_SECRETS.h +const char* mqtt_password = MQTT_PASSWORD; // Set in USER_SECRETS.h #ifdef MQTT_MANUAL_TOPIC_OBJECT_NAME 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 d31582dd4..823d46a04 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -92,7 +92,6 @@ /* MQTT options */ // #define MQTT // Enable this line to enable MQTT -#define MQTT_SERVER "192.168.xxx.yyy" #define MQTT_PORT 1883 #define MQTT_MANUAL_TOPIC_OBJECT_NAME // Enable this to use custom MQTT topic, object ID prefix, and device name. \ // WARNING: If this is not defined, the previous default naming format \ diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index 95f5444a7..0779711c4 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "../../../USER_SECRETS.h" #include "../../../USER_SETTINGS.h" #include "../../battery/BATTERIES.h" #include "../../datalayer/datalayer.h" From 4f53a3b358990046e9232000017d02c9dcca672f Mon Sep 17 00:00:00 2001 From: No-Signal Date: Sat, 21 Dec 2024 10:48:39 +0000 Subject: [PATCH 092/225] Updating github workflows to copy template secrets file --- .github/workflows/compile-all-batteries.yml | 4 ++++ .../compile-all-combinations-part1-batteries-A-to-M.yml | 4 ++++ .../compile-all-combinations-part2-batteries-N-to-Z.yml | 4 ++++ .github/workflows/compile-all-inverters.yml | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index 3e04e5d45..80466e52e 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -86,6 +86,10 @@ jobs: # First we clone the repo using the `checkout` action. - name: Checkout uses: actions/checkout@v4 + + # 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 # We use the `arduino/setup-arduino-cli` action to install and # configure the Arduino CLI on the system. diff --git a/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml b/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml index 3fc077343..f9eda5bf4 100644 --- a/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml +++ b/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml @@ -92,6 +92,10 @@ jobs: # First we clone the repo using the `checkout` action. - name: Checkout uses: actions/checkout@v4 + + # 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 # We use the `arduino/setup-arduino-cli` action to install and # configure the Arduino CLI on the system. diff --git a/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml b/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml index 668f6db3b..8c77e2375 100644 --- a/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml +++ b/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml @@ -93,6 +93,10 @@ jobs: # First we clone the repo using the `checkout` action. - name: Checkout uses: actions/checkout@v4 + + # 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 # We use the `arduino/setup-arduino-cli` action to install and # configure the Arduino CLI on the system. diff --git a/.github/workflows/compile-all-inverters.yml b/.github/workflows/compile-all-inverters.yml index 6723c8030..b1f2afa10 100644 --- a/.github/workflows/compile-all-inverters.yml +++ b/.github/workflows/compile-all-inverters.yml @@ -78,6 +78,10 @@ jobs: # First we clone the repo using the `checkout` action. - name: Checkout uses: actions/checkout@v4 + + # 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 # We use the `arduino/setup-arduino-cli` action to install and # configure the Arduino CLI on the system. From bcc69647fed9190649ff3a4c6bea914da302d5c2 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 21 Dec 2024 19:22:04 +0200 Subject: [PATCH 093/225] Sbox --- Software/src/battery/BMW-SBOX.cpp | 198 ++++++++++-------- Software/src/battery/BMW-SBOX.h | 12 +- Software/src/datalayer/datalayer.h | 6 +- .../src/devboard/webserver/settings_html.cpp | 2 +- 4 files changed, 131 insertions(+), 87 deletions(-) diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp index bb8ff0c1e..0b28eecb9 100644 --- a/Software/src/battery/BMW-SBOX.cpp +++ b/Software/src/battery/BMW-SBOX.cpp @@ -3,24 +3,22 @@ #include "../datalayer/datalayer.h" #include "BMW-SBOX.h" - #define MAX_ALLOWED_FAULT_TICKS 1000 -/* NOTE: modify the precharge time constant below to account for the resistance and capacitance of the target system. - * t=3RC at minimum, t=5RC ideally - */ - -#define PRECHARGE_TIME_MS 160 // Time before negative contactor engages and precharging starts -#define NEGATIVE_CONTACTOR_TIME_MS 1000 // Precharge time before precharge resistor is bypassed by positive contactor -#define POSITIVE_CONTACTOR_TIME_MS 2000 // Precharge relay lead time after positive contactor has been engaged -enum State { DISCONNECTED, PRECHARGE, NEGATIVE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED }; -State contactorStatus = DISCONNECTED; +enum SboxState { DISCONNECTED, PRECHARGE, NEGATIVE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED }; +SboxState contactorStatus = DISCONNECTED; unsigned long prechargeStartTime = 0; unsigned long negativeStartTime = 0; unsigned long positiveStartTime = 0; unsigned long timeSpentInFaultedMode = 0; unsigned long LastMsgTime = 0; // will store last time a 20ms CAN Message was send +unsigned long LastAvgTime = 0; // Last current storage time + +uint32_t avg_mA_array[10]; +uint32_t avg_sum; + +uint8_t k; //avg array pointer uint8_t CAN100_cnt=0; @@ -46,6 +44,8 @@ uint8_t reverse_bits(uint8_t byte) { return reversed; } + +/** CRC8, both inverted, poly 0x31 **/ uint8_t calculateCRC(CAN_frame CAN) { uint8_t crc = 0; for (size_t i = 0; i < CAN.DLC; i++) { @@ -65,100 +65,131 @@ uint8_t calculateCRC(CAN_frame CAN) { } void receive_can_shunt(CAN_frame rx_frame) { + unsigned long currentTime = millis(); if(rx_frame.ID ==0x200) { datalayer.shunt.measured_amperage_mA=((rx_frame.data.u8[2]<<24)| (rx_frame.data.u8[1]<<16)| (rx_frame.data.u8[0]<<8))/256; + + /** Calculate 1S avg current **/ + if(LastAvgTime+1009) { + k=0; + } + avg_mA_array[k]=datalayer.shunt.measured_amperage_mA; + k++; + avg_sum=0; + for (uint8_t i = 0; i < 10; i++) + { + avg_sum=avg_sum+avg_mA_array[i]; + } + datalayer.shunt.measured_avg1S_amperage_mA=avg_sum/10; + } } - else if(rx_frame.ID ==0x210) //Battery voltage + else if(rx_frame.ID ==0x210) //SBOX input (battery side) voltage { - datalayer.shunt.measured_voltage_mV==((rx_frame.data.u8[2]<<24)| (rx_frame.data.u8[1]<<16)| (rx_frame.data.u8[0]<<8))/256; + datalayer.shunt.measured_voltage_mV=((rx_frame.data.u8[2]<<16)| (rx_frame.data.u8[1]<<8)| (rx_frame.data.u8[0])); } else if(rx_frame.ID ==0x220) //SBOX output voltage { - datalayer.shunt.measured_outvoltage_mV==((rx_frame.data.u8[2]<<24)| (rx_frame.data.u8[1]<<16)| (rx_frame.data.u8[0]<<8))/256; + datalayer.shunt.measured_outvoltage_mV=((rx_frame.data.u8[2]<<16)| (rx_frame.data.u8[1]<<8)| (rx_frame.data.u8[0])); } } void send_can_shunt() { - // First check if we have any active errors, incase we do, turn off the battery - if (datalayer.battery.status.bms_status == FAULT) { - timeSpentInFaultedMode++; - } else { - timeSpentInFaultedMode = 0; - } - - //handle contactor control SHUTDOWN_REQUESTED - if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) { - contactorStatus = SHUTDOWN_REQUESTED; - SBOX_100.data.u8[0]=0x55; // All open - } - - if (contactorStatus == SHUTDOWN_REQUESTED) { - datalayer.shunt.contactors_engaged = false; - return; // A fault scenario latches the contactor control. It is not possible to recover without a powercycle (and investigation why fault occured) - } + unsigned long currentTime = millis(); + // Send 20ms CAN Message + if (currentTime - LastMsgTime >= INTERVAL_20_MS) { + LastMsgTime = currentTime; + // First check if we have any active errors, incase we do, turn off the battery + if (datalayer.battery.status.bms_status == FAULT) { + timeSpentInFaultedMode++; + } else { + timeSpentInFaultedMode = 0; + } - // After that, check if we are OK to start turning on the battery - if (contactorStatus == DISCONNECTED) { - datalayer.shunt.contactors_engaged = false; - SBOX_100.data.u8[0]=0x55; // All open - if (datalayer.system.status.battery_allows_contactor_closing && - datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active && ( datalayer.shunt.measured_voltage_mV => MINIMUM_INPUT_VOLTAGE*1000)) { - contactorStatus = PRECHARGE; + //handle contactor control SHUTDOWN_REQUESTED + if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) { + contactorStatus = SHUTDOWN_REQUESTED; + SBOX_100.data.u8[0]=0x55; // All open } - } - // In case the inverter requests contactors to open, set the state accordingly - if (contactorStatus == COMPLETED) { - //Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable) - if (!datalayer.system.status.inverter_allows_contactor_closing || datalayer.system.settings.equipment_stop_active) { - contactorStatus = DISCONNECTED; + if (contactorStatus == SHUTDOWN_REQUESTED) { + datalayer.shunt.contactors_engaged = false; + return; // A fault scenario latches the contactor control. It is not possible to recover without a powercycle (and investigation why fault occured) } - } - unsigned long currentTime = millis(); - // Handle actual state machine. This first turns on Precharge, then Negative, then Positive, and finally turns OFF precharge - switch (contactorStatus) { - case PRECHARGE: - SBOX_100.data.u8[0]=0x86; // Precharge relay only - prechargeStartTime = currentTime; - contactorStatus = NEGATIVE; - break; - - case NEGATIVE: - if (currentTime - prechargeStartTime >= PRECHARGE_TIME_MS) { - SBOX_100.data.u8[0]=0xA6; // Precharge + Negative - negativeStartTime = currentTime; - contactorStatus = POSITIVE; - datalayer.shunt.precharging = true; + // After that, check if we are OK to start turning on the contactors + if (contactorStatus == DISCONNECTED) { + datalayer.shunt.contactors_engaged = false; + SBOX_100.data.u8[0]=0x55; // All open + + if (datalayer.system.status.battery_allows_contactor_closing && + datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active && ( datalayer.shunt.measured_voltage_mV > MINIMUM_INPUT_VOLTAGE*1000)) { + contactorStatus = PRECHARGE; } - break; - - case POSITIVE: - if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS && (datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < datalalyer.shunt.measured_outvoltage_mV)) { - SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive - positiveStartTime = currentTime; - contactorStatus = PRECHARGE_OFF; - datalayer.shunt.precharging = false; + } + + // In case the inverter requests contactors to open, set the state accordingly + if (contactorStatus == COMPLETED) { + //Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable) + if (!datalayer.system.status.inverter_allows_contactor_closing || datalayer.system.settings.equipment_stop_active) { + contactorStatus = DISCONNECTED; } - break; + } - case PRECHARGE_OFF: - if (currentTime - positiveStartTime >= POSITIVE_CONTACTOR_TIME_MS) { + // Handle actual state machine. This first turns on Precharge, then Negative, then Positive, and finally turns OFF precharge + switch (contactorStatus) { + case PRECHARGE: + SBOX_100.data.u8[0]=0x86; // Precharge relay only + prechargeStartTime = currentTime; + contactorStatus = NEGATIVE; +#ifdef DEBUG_VIA_USB + Serial.println("S-BOX Precharge relay engaged"); +#endif + break; + + case NEGATIVE: + if (currentTime - prechargeStartTime >= CONTACTOR_CONTROL_T1) { + SBOX_100.data.u8[0]=0xA6; // Precharge + Negative + negativeStartTime = currentTime; + contactorStatus = POSITIVE; + datalayer.shunt.precharging = true; +#ifdef DEBUG_VIA_USB + Serial.println("S-BOX Negative relay engaged"); +#endif + } + break; + + case POSITIVE: + if (currentTime - negativeStartTime >= CONTACTOR_CONTROL_T2 && (datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < datalayer.shunt.measured_outvoltage_mV)) { + SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive + positiveStartTime = currentTime; + contactorStatus = PRECHARGE_OFF; + datalayer.shunt.precharging = false; +#ifdef DEBUG_VIA_USB + Serial.println("S-BOX Positive relay engaged"); +#endif + } + break; + + case PRECHARGE_OFF: + if (currentTime - positiveStartTime >= CONTACTOR_CONTROL_T3) { + SBOX_100.data.u8[0]=0x6A; // Negative + Positive + contactorStatus = COMPLETED; +#ifdef DEBUG_VIA_USB + Serial.println("S-BOX Precharge relay released"); +#endif + datalayer.shunt.contactors_engaged = true; + } + break; + case COMPLETED: SBOX_100.data.u8[0]=0x6A; // Negative + Positive - contactorStatus = COMPLETED; - datalayer.shunt.contactors_engaged = true; - } - break; - case COMPLETED: - SBOX_100.data.u8[0]=0x6A; // Negative + Positive - default: - break; - } + default: + break; + } - // Send 20ms CAN Message - if (currentTime - LastMsgTime >= INTERVAL_20_MS) { - LastMsgTime = currentTime; CAN100_cnt++; if (CAN100_cnt>0x0E) { CAN100_cnt=0; @@ -172,6 +203,7 @@ void send_can_shunt() { } void setup_can_shunt() { - datalayer.system.info.shunt_protocol[63] = 'BMW SBOX\0'; + strncpy(datalayer.system.info.shunt_protocol, "BMW SBOX", 63); + datalayer.system.info.shunt_protocol[63] = '\0'; } #endif diff --git a/Software/src/battery/BMW-SBOX.h b/Software/src/battery/BMW-SBOX.h index 293f16859..2c54951fa 100644 --- a/Software/src/battery/BMW-SBOX.h +++ b/Software/src/battery/BMW-SBOX.h @@ -7,8 +7,16 @@ void transmit_can(CAN_frame* tx_frame, int interface); /** Minimum input voltage required to enable relay control **/ #define MINIMUM_INPUT_VOLTAGE 250 -/** Maximum allowable percentage of input voltage across the precharge resistor to close the positive relay **/ -#define MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT 96 +/** Maximum allowable percentage of input voltage across the precharge resistor to engage the positive relay. **/ +/** SAFETY FEATURE: If precharge resistor is faulty, positive contactor will not be engaged **/ +#define MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT 0.99 +/* NOTE: modify the T2 time constant below to account for the resistance and capacitance of the target system. + * t=3RC at minimum, t=5RC ideally + */ + +#define CONTACTOR_CONTROL_T1 5000 // Time before negative contactor engages and precharging starts +#define CONTACTOR_CONTROL_T2 5000 // Precharge time before precharge resistor is bypassed by positive contactor +#define CONTACTOR_CONTROL_T3 2000 // Precharge relay lead time after positive contactor has been engaged #endif diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 83ce189ef..d3b9f45b4 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -129,7 +129,11 @@ typedef struct { /** measured output voltage in mV (eg. S-BOX) **/ uint32_t measured_outvoltage_mV = 0; /** measured amperage in mA (eg. S-BOX) **/ - uint32_t measured_amperage_mA = 0; + int32_t measured_amperage_mA = 0; + /** Sum of current readings during measuring period **/ + int32_t measured_avg1S_amperage_mA = 0; + /** Number of samples **/ + uint16_t measured_sum_amperage_count = 0; /** True if contactors are precharging state */ bool precharging = false; /** True if the contactor controlled by battery-emulator is closed */ diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 90c83837f..f4f90895b 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -42,7 +42,7 @@ String settings_processor(const String& var) { #endif #ifdef CAN_SHUNT_SELECTED - content += "

Shunt Interface: " + + content += "

Shunt Interface: " + String(getCANInterfaceName(can_config.shunt)) + "

"; #endif //CAN_SHUNT_SELECTED From 774be64ce316051797d4fbdf1bbfcdb08456f694 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 21 Dec 2024 20:18:48 +0200 Subject: [PATCH 094/225] sbox merge cleanup --- Software/Software.ino | 1 - Software/USER_SETTINGS.h | 4 ++-- Software/src/battery/BMW-SBOX.cpp | 6 ------ 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 6570102e5..89d4d20e1 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -1,4 +1,3 @@ - /* 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" */ diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 73e534e1d..408b8f56c 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -33,7 +33,7 @@ //#define TESLA_MODEL_SX_BATTERY //#define TESLA_MODEL_3Y_BATTERY //#define VOLVO_SPA_BATTERY -#define TEST_FAKE_BATTERY +//#define TEST_FAKE_BATTERY //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires DUAL_CAN setup) /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ @@ -64,7 +64,7 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! /* Shunt/Contactor settings */ -#define BMW_SBOX // SBOX relay control & battery current/voltage measurement +//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp index 0b28eecb9..0fd449eb4 100644 --- a/Software/src/battery/BMW-SBOX.cpp +++ b/Software/src/battery/BMW-SBOX.cpp @@ -130,7 +130,6 @@ void send_can_shunt() { contactorStatus = PRECHARGE; } } - // In case the inverter requests contactors to open, set the state accordingly if (contactorStatus == COMPLETED) { //Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable) @@ -138,7 +137,6 @@ void send_can_shunt() { contactorStatus = DISCONNECTED; } } - // Handle actual state machine. This first turns on Precharge, then Negative, then Positive, and finally turns OFF precharge switch (contactorStatus) { case PRECHARGE: @@ -149,7 +147,6 @@ void send_can_shunt() { Serial.println("S-BOX Precharge relay engaged"); #endif break; - case NEGATIVE: if (currentTime - prechargeStartTime >= CONTACTOR_CONTROL_T1) { SBOX_100.data.u8[0]=0xA6; // Precharge + Negative @@ -161,7 +158,6 @@ void send_can_shunt() { #endif } break; - case POSITIVE: if (currentTime - negativeStartTime >= CONTACTOR_CONTROL_T2 && (datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < datalayer.shunt.measured_outvoltage_mV)) { SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive @@ -173,7 +169,6 @@ void send_can_shunt() { #endif } break; - case PRECHARGE_OFF: if (currentTime - positiveStartTime >= CONTACTOR_CONTROL_T3) { SBOX_100.data.u8[0]=0x6A; // Negative + Positive @@ -189,7 +184,6 @@ void send_can_shunt() { default: break; } - CAN100_cnt++; if (CAN100_cnt>0x0E) { CAN100_cnt=0; From b4be33e1790e00eae270622bc562fd54eeda69a6 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 21 Dec 2024 20:20:18 +0200 Subject: [PATCH 095/225] sbox merge cleanup --- Software/USER_SETTINGS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 408b8f56c..045d3ff22 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -69,7 +69,7 @@ /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) -//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to< be seated before starting +//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting //#define DUAL_CAN //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 //DUAL_CAN option, what is your MCP2515 add-on boards crystal frequency? //#define CAN_FD //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board From f85de389c33d302b5807be5723ea1642ed9f88c5 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 21 Dec 2024 20:27:20 +0200 Subject: [PATCH 096/225] sbox merge cleanup --- Software/src/datalayer/datalayer.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index d3b9f45b4..741c7a040 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -130,10 +130,8 @@ typedef struct { uint32_t measured_outvoltage_mV = 0; /** measured amperage in mA (eg. S-BOX) **/ int32_t measured_amperage_mA = 0; - /** Sum of current readings during measuring period **/ + /** Average current from last 1s **/ int32_t measured_avg1S_amperage_mA = 0; - /** Number of samples **/ - uint16_t measured_sum_amperage_count = 0; /** True if contactors are precharging state */ bool precharging = false; /** True if the contactor controlled by battery-emulator is closed */ From fe24c195c7e9e0e93539d9e33698287816c4cf10 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 21 Dec 2024 20:32:27 +0200 Subject: [PATCH 097/225] sbox merge cleanup --- Software/src/battery/BMW-SBOX.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/BMW-SBOX.h b/Software/src/battery/BMW-SBOX.h index 2c54951fa..70aa788b5 100644 --- a/Software/src/battery/BMW-SBOX.h +++ b/Software/src/battery/BMW-SBOX.h @@ -7,8 +7,8 @@ void transmit_can(CAN_frame* tx_frame, int interface); /** Minimum input voltage required to enable relay control **/ #define MINIMUM_INPUT_VOLTAGE 250 -/** Maximum allowable percentage of input voltage across the precharge resistor to engage the positive relay. **/ -/** SAFETY FEATURE: If precharge resistor is faulty, positive contactor will not be engaged **/ +/** Minimum required percentage of input voltage at the output port to engage the positive relay. **/ +/** Prevents engagement of the positive contactor if the precharge resistor is faulty. **/ #define MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT 0.99 /* NOTE: modify the T2 time constant below to account for the resistance and capacitance of the target system. From 4dbda150a1c35af03ed841589bb80702d15ee637 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 21 Dec 2024 22:23:53 +0200 Subject: [PATCH 098/225] . --- Software/Software.ino | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 89d4d20e1..df46dca04 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -198,9 +198,6 @@ void setup() { setup_battery(); #ifdef EQUIPMENT_STOP_BUTTON init_equipment_stop_button(); -#endif -#ifdef CAN_SHUNT_SELECTED - setup_can_shunt(); #endif // BOOT button at runtime is used as an input for various things pinMode(0, INPUT_PULLUP); @@ -733,10 +730,6 @@ void send_can() { #ifdef CHARGER_SELECTED send_can_charger(); #endif // CHARGER_SELECTED - -#ifdef CAN_SHUNT_SELECTED - send_can_shunt(); -#endif // CAN_SHUNT_SELECTED } #ifdef DUAL_CAN @@ -1015,7 +1008,6 @@ void update_values_inverter() { #ifdef MODBUS_INVERTER_SELECTED update_modbus_registers_inverter(); #endif - #ifdef RS485_INVERTER_SELECTED update_RS485_registers_inverter(); #endif @@ -1229,11 +1221,6 @@ void receive_can(CAN_frame* rx_frame, int interface) { if (interface == can_config.charger) { #ifdef CHARGER_SELECTED receive_can_charger(*rx_frame); -#endif - } - if (interface == can_config.shunt) { -#ifdef CAN_SHUNT_SELECTED - receive_can_shunt(*rx_frame); #endif } } From 605f41695411a6542b841361220bb7abb7f31fd2 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 21 Dec 2024 22:29:50 +0200 Subject: [PATCH 099/225] Merge fix --- Software/Software.ino | 3 +++ Software/src/communication/can/comm_can.cpp | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/Software/Software.ino b/Software/Software.ino index efcb4051b..70d9c76ac 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -110,6 +110,9 @@ void setup() { setup_battery(); #ifdef EQUIPMENT_STOP_BUTTON init_equipment_stop_button(); +#endif +#ifdef CAN_SHUNT_SELECTED + setup_can_shunt(); #endif // BOOT button at runtime is used as an input for various things pinMode(0, INPUT_PULLUP); diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index 8d7923fda..ac92faba1 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -177,6 +177,9 @@ void send_can() { #ifdef CHARGER_SELECTED send_can_charger(); #endif // CHARGER_SELECTED +#ifdef CAN_SHUNT_SELECTED + send_can_shunt(); +#endif // CAN_SHUNT_SELECTED } // Receive functions @@ -203,6 +206,11 @@ void receive_can(CAN_frame* rx_frame, int interface) { if (interface == can_config.charger) { #ifdef CHARGER_SELECTED receive_can_charger(*rx_frame); +#endif + } + if (interface == can_config.shunt) { +#ifdef CAN_SHUNT_SELECTED + receive_can_shunt(*rx_frame); #endif } } From fcedc4bb733512e61fd16c236aca1874b2c2fb34 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sun, 22 Dec 2024 16:28:40 +1300 Subject: [PATCH 100/225] Update advanced_battery_html.cpp --- .../webserver/advanced_battery_html.cpp | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index c8fc14c33..fbb2f29ea 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -333,8 +333,8 @@ String advanced_battery_processor(const String& var) { float isolationResistance = static_cast(datalayer_extended.tesla.battery_BMS_isolationResistance) * 10; float PCS_dcdcMaxOutputCurrentAllowed = static_cast(datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed) * 0.1; - float PCS_dcdcTemp = static_cast(datalayer_extended.tesla.PCS_dcdcTemp * 0.1 + 40); - float PCS_ambientTemp = static_cast(datalayer_extended.tesla.PCS_ambientTemp) * 0.1 + 40; + float PCS_dcdcTemp = static_cast(datalayer_extended.tesla.PCS_dcdcTemp) * 0.1 - 40; + float PCS_ambientTemp = static_cast(datalayer_extended.tesla.PCS_ambientTemp) * 0.1 - 40; float BMS_maxRegenPower = static_cast(datalayer_extended.tesla.BMS_maxRegenPower) * 0.01; float BMS_maxDischargePower = static_cast(datalayer_extended.tesla.BMS_maxDischargePower) * 0.013; float BMS_maxStationaryHeatPower = static_cast(datalayer_extended.tesla.BMS_maxStationaryHeatPower) * 0.01; @@ -346,8 +346,8 @@ String advanced_battery_processor(const String& var) { float BMS_inletPassiveTargetT = static_cast(datalayer_extended.tesla.BMS_inletPassiveTargetT) * 0.25 - 25; float BMS_inletActiveHeatTargetT = static_cast(datalayer_extended.tesla.BMS_inletActiveHeatTargetT) * 0.25 - 25; - float BMS_packTMin = static_cast(datalayer_extended.tesla.BMS_packTMin); - float BMS_packTMax = static_cast(datalayer_extended.tesla.BMS_packTMax); + float BMS_packTMin = static_cast(datalayer_extended.tesla.BMS_packTMin) * 0.25 - 25; + float BMS_packTMax = static_cast(datalayer_extended.tesla.BMS_packTMax) * 0.25 - 25; float PCS_dcdcMaxLvOutputCurrent = static_cast(datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent) * 0.1; float PCS_dcdcCurrentLimit = static_cast(datalayer_extended.tesla.PCS_dcdcCurrentLimit) * 0.1; float PCS_dcdcLvOutputCurrentTempLimit = @@ -454,6 +454,7 @@ String advanced_battery_processor(const String& var) { "NUM"}; static const char* BMS_powerLimitState[] = {"NOT_CALCULATED_FOR_DRIVE", "CALCULATED_FOR_DRIVE"}; static const char* HVP_status[] = {"INVALID", "NOT_AVAILABLE", "STALE", "VALID"}; + static const char* HVP_contactor[] = {"NOT_ACTIVE", "ACTIVE", "COMPLETED"}; static const char* falseTrue[] = {"False", "True"}; static const char* noYes[] = {"No", "Yes"}; //0x20A 522 HVP_contatorState @@ -466,15 +467,15 @@ String advanced_battery_processor(const String& var) { content += "

Closing allowed?: " + String(falseTrue[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; content += "

Pyrotest in Progress: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "

"; content += "

Contactors Open Now Requested: " + - String(falseTrue[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; - content += "

Contactors Open Requested; " + - String(falseTrue[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + "

"; - content += "

Contactors Request Status; " + - String(falseTrue[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; - content += "

Contactors Reset Request Required; " + - String(falseTrue[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; - content += "

DC Link Allowed to Energize;" + - String(falseTrue[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + "

"; + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; + content += "

Contactors Open Requested: " + + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + "

"; + content += "

Contactors Request Status: " + + String(HVP_contactor[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; + content += "

Contactors Reset Request Required: " + + String(noYes[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; + content += "

DC Link Allowed to Energize:" + + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + "

"; // Comment what data you would like to dislay, order can be changed. //0x292 658 BMS_socStates content += "

Battery Beginning of Life: " + String(beginning_of_life) + " KWh

"; @@ -558,7 +559,8 @@ String advanced_battery_processor(const String& var) { content += "

BMS PCS PWM Enabled: " + String(noYes[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; //0x352 850 BMS_energyStatus - content += "

Early BMS 0x352"; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " KWh

"; content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " KWh

"; @@ -567,7 +569,8 @@ String advanced_battery_processor(const String& var) { content += "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; //0x352 850 BMS_energyStatus - content += "

Late BMS 0x352 with Mux2021 and comment 0x352 with MUX + content += "

Late BMS 0x352 with Mux:""2021 and comment 0x352 with MUX + content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0) * 100 / (beginning_of_life); content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh

"; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh

"; content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining_m0) + " KWh

"; @@ -600,7 +603,7 @@ String advanced_battery_processor(const String& var) { content += "

HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW

"; content += "

Not Enough Power For Heat Pump: " + String(noYes[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + - " KW

"; + "

"; content += "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; content += "

Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "

"; From f55cad92f1cb32fdf2df863413eb58504b91b03c Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sun, 22 Dec 2024 16:29:06 +1300 Subject: [PATCH 101/225] Update advanced_battery_html.cpp --- .../webserver/advanced_battery_html.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index fbb2f29ea..e457f6bf9 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -468,14 +468,16 @@ String advanced_battery_processor(const String& var) { content += "

Pyrotest in Progress: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "

"; content += "

Contactors Open Now Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; - content += "

Contactors Open Requested: " + - String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + "

"; + content += + "

Contactors Open Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + + "

"; content += "

Contactors Request Status: " + String(HVP_contactor[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; content += "

Contactors Reset Request Required: " + String(noYes[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; - content += "

DC Link Allowed to Energize:" + - String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + "

"; + content += + "

DC Link Allowed to Energize:" + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + + "

"; // Comment what data you would like to dislay, order can be changed. //0x292 658 BMS_socStates content += "

Battery Beginning of Life: " + String(beginning_of_life) + " KWh

"; @@ -559,7 +561,9 @@ String advanced_battery_processor(const String& var) { content += "

BMS PCS PWM Enabled: " + String(noYes[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; //0x352 850 BMS_energyStatus - content += "

Early BMS 0x352:""Early BMS 0x352:" + ""; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " KWh

"; @@ -569,7 +573,9 @@ String advanced_battery_processor(const String& var) { content += "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; //0x352 850 BMS_energyStatus - content += "

Late BMS 0x352 with Mux:""2021 and comment 0x352 with MUX + content += + "

Late BMS 0x352 with Mux:" + "2021 and comment 0x352 with MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0) * 100 / (beginning_of_life); content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh

"; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh

"; From 6d96808de44c66af83f65edf2c8176f7dc3f6cba Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sun, 22 Dec 2024 18:35:12 +1300 Subject: [PATCH 102/225] factoring changes --- Software/src/battery/TESLA-BATTERY.cpp | 88 +++++++++---------- .../webserver/advanced_battery_html.cpp | 15 ++-- 2 files changed, 50 insertions(+), 53 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index a9160a90e..3d3daf7e9 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -48,7 +48,7 @@ static uint16_t battery_nominal_full_pack_energy_m0 = 600; // Kwh //0x132 306 HVBattAmpVolt static uint16_t battery_volts = 0; // V static int16_t battery_amps = 0; // A -static uint16_t battery_raw_amps = 0; // A +static int16_t battery_raw_amps = 0; // A static uint16_t battery_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable static uint16_t BMS_maxRegenPower = 0; //rename from battery_regenerative_limit @@ -167,11 +167,11 @@ static uint16_t BMS_packTMax = 0; static uint16_t BMS_pcsNoFlowRequest = 0; static uint16_t BMS_noFlowRequest = 0; //0x2A4; 676 PCS_thermalStatus -static uint16_t PCS_chgPhATemp = 0; -static uint16_t PCS_chgPhBTemp = 0; -static uint16_t PCS_chgPhCTemp = 0; -static uint16_t PCS_dcdcTemp = 0; -static uint16_t PCS_ambientTemp = 0; +static int16_t PCS_chgPhATemp = 0; +static int16_t PCS_chgPhBTemp = 0; +static int16_t PCS_chgPhCTemp = 0; +static int16_t PCS_dcdcTemp = 0; +static int16_t PCS_ambientTemp = 0; //0x2C4; 708 PCS_logging static uint16_t PCS_logMessageSelect = 0; static uint16_t PCS_dcdcMaxLvOutputCurrent = 0; @@ -179,10 +179,10 @@ static uint16_t PCS_dcdcCurrentLimit = 0; static uint16_t PCS_dcdcLvOutputCurrentTempLimit = 0; static uint16_t PCS_dcdcUnifiedCommand = 0; static uint16_t PCS_dcdcCLAControllerOutput = 0; -static uint16_t PCS_dcdcTankVoltage = 0; +static int16_t PCS_dcdcTankVoltage = 0; static uint16_t PCS_dcdcTankVoltageTarget = 0; static uint16_t PCS_dcdcClaCurrentFreq = 0; -static uint16_t PCS_dcdcTCommMeasured = 0; +static int16_t PCS_dcdcTCommMeasured = 0; static uint16_t PCS_dcdcShortTimeUs = 0; static uint16_t PCS_dcdcHalfPeriodUs = 0; static uint16_t PCS_dcdcIntervalMaxFrequency = 0; @@ -221,34 +221,34 @@ static uint8_t HVP_gpioFcContPowerEnable = 0; static uint8_t HVP_gpioHvilEnable = 0; static uint8_t HVP_gpioSecDrdy = 0; static uint16_t HVP_hvp1v5Ref = 0; -static uint16_t HVP_shuntCurrentDebug = 0; +static int16_t HVP_shuntCurrentDebug = 0; static uint8_t HVP_packCurrentMia = 0; static uint8_t HVP_auxCurrentMia = 0; static uint8_t HVP_currentSenseMia = 0; static uint8_t HVP_shuntRefVoltageMismatch = 0; static uint8_t HVP_shuntThermistorMia = 0; static uint8_t HVP_shuntHwMia = 0; -static uint16_t HVP_dcLinkVoltage = 0; -static uint16_t HVP_packVoltage = 0; -static uint16_t HVP_fcLinkVoltage = 0; +static int16_t HVP_dcLinkVoltage = 0; +static int16_t HVP_packVoltage = 0; +static int16_t HVP_fcLinkVoltage = 0; static uint16_t HVP_packContVoltage = 0; -static uint16_t HVP_packNegativeV = 0; -static uint16_t HVP_packPositiveV = 0; +static int16_t HVP_packNegativeV = 0; +static int16_t HVP_packPositiveV = 0; static uint16_t HVP_pyroAnalog = 0; -static uint16_t HVP_dcLinkNegativeV = 0; -static uint16_t HVP_dcLinkPositiveV = 0; -static uint16_t HVP_fcLinkNegativeV = 0; +static int16_t HVP_dcLinkNegativeV = 0; +static int16_t HVP_dcLinkPositiveV = 0; +static int16_t HVP_fcLinkNegativeV = 0; static uint16_t HVP_fcContCoilCurrent = 0; static uint16_t HVP_fcContVoltage = 0; static uint16_t HVP_hvilInVoltage = 0; static uint16_t HVP_hvilOutVoltage = 0; -static uint16_t HVP_fcLinkPositiveV = 0; +static int16_t HVP_fcLinkPositiveV = 0; static uint16_t HVP_packContCoilCurrent = 0; static uint16_t HVP_battery12V = 0; -static uint16_t HVP_shuntRefVoltageDbg = 0; -static uint16_t HVP_shuntAuxCurrentDbg = 0; -static uint16_t HVP_shuntBarTempDbg = 0; -static uint16_t HVP_shuntAsicTempDbg = 0; +static int16_t HVP_shuntRefVoltageDbg = 0; +static int16_t HVP_shuntAuxCurrentDbg = 0; +static int16_t HVP_shuntBarTempDbg = 0; +static int16_t HVP_shuntAsicTempDbg = 0; static uint8_t HVP_shuntAuxCurrentStatus = 0; static uint8_t HVP_shuntBarTempStatus = 0; static uint8_t HVP_shuntAsicTempStatus = 0; @@ -432,7 +432,7 @@ static uint16_t battery2_nominal_full_pack_energy_m0 = 600; // Kwh //0x132 306 HVBattAmpVolt static uint16_t battery2_volts = 0; // V static int16_t battery2_amps = 0; // A -static uint16_t battery2_raw_amps = 0; // A +static int16_t battery2_raw_amps = 0; // A static uint16_t battery2_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable static uint16_t BMS2_regenerative_limit = 0; @@ -547,11 +547,11 @@ static uint16_t BMS2_packTMax = 0; static uint16_t BMS2_pcsNoFlowRequest = 0; static uint16_t BMS2_noFlowRequest = 0; //0x2A4; 676 PCS_thermalStatus -static uint16_t PCS2_chgPhATemp = 0; -static uint16_t PCS2_chgPhBTemp = 0; -static uint16_t PCS2_chgPhCTemp = 0; -static uint16_t PCS2_dcdcTemp = 0; -static uint16_t PCS2_ambientTemp = 0; +static int16_t PCS2_chgPhATemp = 0; +static int16_t PCS2_chgPhBTemp = 0; +static int16_t PCS2_chgPhCTemp = 0; +static int16_t PCS2_dcdcTemp = 0; +static int16_t PCS2_ambientTemp = 0; //0x2C4; 708 PCS_logging static uint16_t PCS2_logMessageSelect = 0; static uint16_t PCS2_dcdcMaxLvOutputCurrent = 0; @@ -559,10 +559,10 @@ static uint16_t PCS2_dcdcCurrentLimit = 0; static uint16_t PCS2_dcdcLvOutputCurrentTempLimit = 0; static uint16_t PCS2_dcdcUnifiedCommand = 0; static uint16_t PCS2_dcdcCLAControllerOutput = 0; -static uint16_t PCS2_dcdcTankVoltage = 0; +static int16_t PCS2_dcdcTankVoltage = 0; static uint16_t PCS2_dcdcTankVoltageTarget = 0; static uint16_t PCS2_dcdcClaCurrentFreq = 0; -static uint16_t PCS2_dcdcTCommMeasured = 0; +static int16_t PCS2_dcdcTCommMeasured = 0; static uint16_t PCS2_dcdcShortTimeUs = 0; static uint16_t PCS2_dcdcHalfPeriodUs = 0; static uint16_t PCS2_dcdcIntervalMaxFrequency = 0; @@ -601,34 +601,34 @@ static uint8_t HVP2_gpioFcContPowerEnable = 0; static uint8_t HVP2_gpioHvilEnable = 0; static uint8_t HVP2_gpioSecDrdy = 0; static uint16_t HVP2_hvp1v5Ref = 0; -static uint16_t HVP2_shuntCurrentDebug = 0; +static int16_t HVP2_shuntCurrentDebug = 0; static uint8_t HVP2_packCurrentMia = 0; static uint8_t HVP2_auxCurrentMia = 0; static uint8_t HVP2_currentSenseMia = 0; static uint8_t HVP2_shuntRefVoltageMismatch = 0; static uint8_t HVP2_shuntThermistorMia = 0; static uint8_t HVP2_shuntHwMia = 0; -static uint16_t HVP2_dcLinkVoltage = 0; -static uint16_t HVP2_packVoltage = 0; -static uint16_t HVP2_fcLinkVoltage = 0; +static int16_t HVP2_dcLinkVoltage = 0; +static int16_t HVP2_packVoltage = 0; +static int16_t HVP2_fcLinkVoltage = 0; static uint16_t HVP2_packContVoltage = 0; -static uint16_t HVP2_packNegativeV = 0; -static uint16_t HVP2_packPositiveV = 0; +static int16_t HVP2_packNegativeV = 0; +static int16_t HVP2_packPositiveV = 0; static uint16_t HVP2_pyroAnalog = 0; -static uint16_t HVP2_dcLinkNegativeV = 0; -static uint16_t HVP2_dcLinkPositiveV = 0; -static uint16_t HVP2_fcLinkNegativeV = 0; +static int16_t HVP2_dcLinkNegativeV = 0; +static int16_t HVP2_dcLinkPositiveV = 0; +static int16_t HVP2_fcLinkNegativeV = 0; static uint16_t HVP2_fcContCoilCurrent = 0; static uint16_t HVP2_fcContVoltage = 0; static uint16_t HVP2_hvilInVoltage = 0; static uint16_t HVP2_hvilOutVoltage = 0; -static uint16_t HVP2_fcLinkPositiveV = 0; +static int16_t HVP2_fcLinkPositiveV = 0; static uint16_t HVP2_packContCoilCurrent = 0; static uint16_t HVP2_battery12V = 0; -static uint16_t HVP2_shuntRefVoltageDbg = 0; -static uint16_t HVP2_shuntAuxCurrentDbg = 0; -static uint16_t HVP2_shuntBarTempDbg = 0; -static uint16_t HVP2_shuntAsicTempDbg = 0; +static int16_t HVP2_shuntRefVoltageDbg = 0; +static int16_t HVP2_shuntAuxCurrentDbg = 0; +static int16_t HVP2_shuntBarTempDbg = 0; +static int16_t HVP2_shuntAsicTempDbg = 0; static uint8_t HVP2_shuntAuxCurrentStatus = 0; static uint8_t HVP2_shuntBarTempStatus = 0; static uint8_t HVP2_shuntAsicTempStatus = 0; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index e457f6bf9..a20e96f67 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -561,10 +561,8 @@ String advanced_battery_processor(const String& var) { content += "

BMS PCS PWM Enabled: " + String(noYes[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; //0x352 850 BMS_energyStatus - content += - "

Early BMS 0x352:" - ""; content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " KWh

"; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " KWh

"; content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " KWh

"; @@ -574,9 +572,8 @@ String advanced_battery_processor(const String& var) { "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; //0x352 850 BMS_energyStatus content += - "

Late BMS 0x352 with Mux:" - "2021 and comment 0x352 with MUX - content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0) * 100 / (beginning_of_life); + "

Late BMS 0x352 with Mux:

"; //if using newer BMS >2021 and comment 0x352 with MUX + content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "

"; content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh

"; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh

"; content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining_m0) + " KWh

"; @@ -600,8 +597,8 @@ String advanced_battery_processor(const String& var) { content += "

Brick Voltage Min: " + String(BrickVoltageMin) + " V

"; content += "

Brick Temp Max Num: " + String(datalayer_extended.tesla.battery_BrickTempMaxNum) + "

"; content += "

Brick Temp Min Num: " + String(datalayer_extended.tesla.battery_BrickTempMinNum) + "

"; - content += "

Brick Temp Max: " + String(BrickModelTMax) + " C

"; - content += "

Brick Temp Min: " + String(BrickModelTMin) + " C

"; + content += "

Brick Model Temp Max: " + String(BrickModelTMax) + " C

"; + content += "

Brick Model Temp Min: " + String(BrickModelTMin) + " C

"; //0x252 594 BMS_powerAvailable content += "

Max Regen Power: " + String(BMS_maxRegenPower) + " KW

"; content += "

Max Discharge Power: " + String(BMS_maxDischargePower) + " KW

"; From ad215a0a061a6decaaf27b5c0d90af06edffccca Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sun, 22 Dec 2024 18:35:48 +1300 Subject: [PATCH 103/225] Factoring changes --- Software/src/battery/TESLA-BATTERY.cpp | 4 ++-- Software/src/devboard/webserver/advanced_battery_html.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 3d3daf7e9..5ecd958e8 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -48,7 +48,7 @@ static uint16_t battery_nominal_full_pack_energy_m0 = 600; // Kwh //0x132 306 HVBattAmpVolt static uint16_t battery_volts = 0; // V static int16_t battery_amps = 0; // A -static int16_t battery_raw_amps = 0; // A +static int16_t battery_raw_amps = 0; // A static uint16_t battery_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable static uint16_t BMS_maxRegenPower = 0; //rename from battery_regenerative_limit @@ -432,7 +432,7 @@ static uint16_t battery2_nominal_full_pack_energy_m0 = 600; // Kwh //0x132 306 HVBattAmpVolt static uint16_t battery2_volts = 0; // V static int16_t battery2_amps = 0; // A -static int16_t battery2_raw_amps = 0; // A +static int16_t battery2_raw_amps = 0; // A static uint16_t battery2_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable static uint16_t BMS2_regenerative_limit = 0; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index a20e96f67..92d42020a 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -571,8 +571,7 @@ String advanced_battery_processor(const String& var) { content += "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; //0x352 850 BMS_energyStatus - content += - "

Late BMS 0x352 with Mux:

"; //if using newer BMS >2021 and comment 0x352 with MUX + content += "

Late BMS 0x352 with Mux:

"; //if using newer BMS >2021 and comment 0x352 with MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "

"; content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh

"; content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh

"; From 11752833c5e56b4b9fc2d5c3846dff5a6fdf1b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 22 Dec 2024 11:46:53 +0200 Subject: [PATCH 104/225] Change to use regen allowed value --- Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index 84a8463f5..22035cc5c 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -90,7 +90,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_discharge_power_W = LB_Discharge_allowed_W; - datalayer.battery.status.max_charge_power_W = LB_Charging_Power_W; + datalayer.battery.status.max_charge_power_W = LB_Regen_allowed_W; int16_t temperatures[] = {cell_1_temperature_polled, cell_2_temperature_polled, cell_3_temperature_polled, cell_4_temperature_polled, cell_5_temperature_polled, cell_6_temperature_polled, From b4474e504d38d65f2fc01affcf8599b1cbab0799 Mon Sep 17 00:00:00 2001 From: No-Signal Date: Sun, 22 Dec 2024 10:46:54 +0000 Subject: [PATCH 105/225] Moving additional sensitive settings to USER_SECRETS.h --- Software/USER_SECRETS.TEMPLATE.h | 11 ++++++++--- Software/USER_SETTINGS.h | 3 --- Software/src/devboard/webserver/webserver.cpp | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Software/USER_SECRETS.TEMPLATE.h b/Software/USER_SECRETS.TEMPLATE.h index eaf5ced13..1d1b05695 100644 --- a/Software/USER_SECRETS.TEMPLATE.h +++ b/Software/USER_SECRETS.TEMPLATE.h @@ -1,8 +1,13 @@ #define WIFI_SSID "REPLACE_WITH_YOUR_SSID" // Maximum of 63 characters #define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD" // Minimum of 8 characters -#define AP_PASSWORD "123456789" // Minimum of 8 characters; set to blank if you want the access point to be open -#define HTTP_USERNAME "admin" // username to webserver authentication; -#define HTTP_PASSWORD "admin" // password to webserver authentication; +#define AP_PASSWORD "123456789" // Minimum of 8 characters; set to blank if you want the access point to be open + +#define WEBSERVER_AUTH_REQUIRED \ + false //Set this line to true to activate webserver authentication (this line must not be commented). +#define HTTP_USERNAME "admin" // username to webserver authentication; +#define HTTP_PASSWORD "admin" // password to webserver authentication; + #define MQTT_SERVER "192.168.xxx.yyy" // mqtt server address +#define MQTT_PORT 1883 // mqtt server port #define MQTT_USER NULL // mqtt username, leave blank for no authentication #define MQTT_PASSWORD NULL // mqtt password, leave blank for no authentication diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 823d46a04..73e475c95 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -82,8 +82,6 @@ #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 WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WEBSERVER_AUTH_REQUIRED \ - false //Set this line to true to activate webserver authentication (this line must not be commented). Refer to USER_SETTINGS.cpp for setting the credentials. #define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future. #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/battery settings set below) @@ -92,7 +90,6 @@ /* MQTT options */ // #define MQTT // Enable this line to enable MQTT -#define MQTT_PORT 1883 #define MQTT_MANUAL_TOPIC_OBJECT_NAME // Enable this 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. \ diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 5468c7049..d5f3a3b2a 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -1,6 +1,7 @@ #include "webserver.h" #include #include +#include "../../../USER_SECRETS.h" #include "../../datalayer/datalayer.h" #include "../../datalayer/datalayer_extended.h" #include "../../lib/bblanchon-ArduinoJson/ArduinoJson.h" From c713d0a94ece00210bd7a090ce1025eaa5b5bbf5 Mon Sep 17 00:00:00 2001 From: mvgalen Date: Sun, 22 Dec 2024 22:48:35 +0100 Subject: [PATCH 106/225] Change Serial logging to flexible logging (#690) * Add Logging class Add Logging class which inherits from Print class, to be able to route logging to USB Serial or to memory for display in the webpage. Adds a log webpage only visible when DEBUG_VIA_WEB is defined. --- Software/Software.ino | 3 + Software/USER_SETTINGS.h | 5 + Software/src/battery/BMW-IX-BATTERY.cpp | 4 +- Software/src/battery/CHADEMO-BATTERY.cpp | 174 +++++++-------- Software/src/battery/CHADEMO-SHUNTS.cpp | 46 ++-- .../src/battery/IMIEV-CZERO-ION-BATTERY.cpp | 40 ++-- Software/src/battery/JAGUAR-IPACE-BATTERY.cpp | 30 +-- Software/src/battery/KIA-E-GMP-BATTERY.cpp | 102 ++++----- .../src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 100 ++++----- Software/src/battery/MG-5-BATTERY.cpp | 4 - .../src/battery/RENAULT-KANGOO-BATTERY.cpp | 60 ++--- .../src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp | 4 - Software/src/battery/RJXZS-BMS.cpp | 18 +- .../SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp | 114 +++++----- Software/src/battery/TESLA-BATTERY.cpp | 208 +++++++++--------- Software/src/battery/TEST-FAKE-BATTERY.cpp | 18 +- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 122 +++++----- Software/src/charger/CHEVY-VOLT-CHARGER.cpp | 16 +- Software/src/communication/can/comm_can.cpp | 72 +++--- Software/src/devboard/mqtt/mqtt.cpp | 56 ++--- Software/src/devboard/utils/events.cpp | 32 +-- .../devboard/utils/events_test_on_target.cpp | 66 +++--- Software/src/devboard/utils/logging.cpp | 86 ++++++++ Software/src/devboard/utils/logging.h | 16 ++ .../devboard/webserver/can_logging_html.cpp | 10 +- .../devboard/webserver/debug_logging_html.cpp | 36 +++ .../devboard/webserver/debug_logging_html.h | 16 ++ .../src/devboard/webserver/events_html.cpp | 10 +- Software/src/devboard/webserver/webserver.cpp | 110 ++++++--- Software/src/devboard/wifi/wifi.cpp | 71 +++--- Software/src/include.h | 1 + Software/src/inverter/BYD-CAN.cpp | 8 +- Software/src/inverter/FOXESS-CAN.cpp | 32 +-- Software/src/inverter/KOSTAL-RS485.cpp | 18 +- .../SERIAL-LINK-TRANSMITTER-INVERTER.cpp | 104 ++++----- Software/src/inverter/SOLAX-CAN.cpp | 16 +- 36 files changed, 1025 insertions(+), 803 deletions(-) create mode 100644 Software/src/devboard/utils/logging.cpp create mode 100644 Software/src/devboard/utils/logging.h create mode 100644 Software/src/devboard/webserver/debug_logging_html.cpp create mode 100644 Software/src/devboard/webserver/debug_logging_html.h diff --git a/Software/Software.ino b/Software/Software.ino index efcb4051b..60cc30d21 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -20,6 +20,7 @@ #include "src/datalayer/datalayer.h" #include "src/devboard/utils/events.h" #include "src/devboard/utils/led_handler.h" +#include "src/devboard/utils/logging.h" #include "src/devboard/utils/value_mapping.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" @@ -84,6 +85,8 @@ MyTimer check_pause_2s(INTERVAL_2_S); TaskHandle_t main_loop_task; TaskHandle_t connectivity_loop_task; +Logging logging; + // Initialization void setup() { init_serial(); diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index d31582dd4..2cefdb7aa 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -66,6 +66,11 @@ /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) +//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) +#if defined(DEBUG_VIA_USB) || defined(DEBUG_VIA_WEB) +#define DEBUG_LOG +#endif + //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) //#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting //#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery) diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index bcd229836..ebecb6dac 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -670,8 +670,8 @@ void receive_can_battery(CAN_frame rx_frame) { if ((rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]) == 10000 || (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]) == 10000) { //Qualifier Invalid Mode - Request Reboot -#ifdef DEBUG_VIA_USB - Serial.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); +#ifdef DEBUG_LOG + logging.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); #endif //set_event(EVENT_BATTERY_VALUE_UNAVAILABLE, (millis())); //Eventually need new Info level event type transmit_can(&BMWiX_6F4_REQUEST_HARD_RESET, can_config.battery); diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index 14720065c..a8faddfc4 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -197,13 +197,13 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { x102_chg_session.ChargingCurrentRequest = newChargingCurrentRequest; x102_chg_session.TargetBatteryVoltage = newTargetBatteryVoltage; -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG //Note on p131 uint8_t chargingrate = 0; if (x100_chg_lim.ConstantOfChargingRateIndication > 0) { chargingrate = x102_chg_session.StateOfCharge / x100_chg_lim.ConstantOfChargingRateIndication * 100; - Serial.print("Charge Rate (kW): "); - Serial.println(chargingrate); + logging.print("Charge Rate (kW): "); + logging.println(chargingrate); } #endif @@ -217,40 +217,40 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { */ if ((CHADEMO_Status == CHADEMO_INIT && vehicle_permission) || (x102_chg_session.s.status.StatusVehicleChargingEnabled && !vehicle_permission)) { -#ifdef DEBUG_VIA_USB - Serial.println("Inconsistent charge/discharge state."); +#ifdef DEBUG_LOG + logging.println("Inconsistent charge/discharge state."); #endif CHADEMO_Status = CHADEMO_FAULT; return; } if (x102_chg_session.f.fault.FaultBatteryOverVoltage) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle indicates fault, battery over voltage."); +#ifdef DEBUG_LOG + logging.println("Vehicle indicates fault, battery over voltage."); #endif CHADEMO_Status = CHADEMO_STOP; return; } if (x102_chg_session.f.fault.FaultBatteryUnderVoltage) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle indicates fault, battery under voltage."); +#ifdef DEBUG_LOG + logging.println("Vehicle indicates fault, battery under voltage."); #endif CHADEMO_Status = CHADEMO_STOP; return; } if (x102_chg_session.f.fault.FaultBatteryCurrentDeviation) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle indicates fault, battery current deviation. Possible EVSE issue?"); +#ifdef DEBUG_LOG + logging.println("Vehicle indicates fault, battery current deviation. Possible EVSE issue?"); #endif CHADEMO_Status = CHADEMO_STOP; return; } if (x102_chg_session.f.fault.FaultBatteryVoltageDeviation) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle indicates fault, battery voltage deviation. Possible EVSE issue?"); +#ifdef DEBUG_LOG + logging.println("Vehicle indicates fault, battery voltage deviation. Possible EVSE issue?"); #endif CHADEMO_Status = CHADEMO_STOP; return; @@ -264,8 +264,8 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { //FIXME condition nesting or more stanzas needed here for clear determination of cessation reason if (CHADEMO_Status == CHADEMO_POWERFLOW && EVSE_mode == CHADEMO_CHARGE && !vehicle_permission) { -#ifdef DEBUG_VIA_USB - Serial.println("State of charge ceiling reached or charging interrupted, stop charging"); +#ifdef DEBUG_LOG + logging.println("State of charge ceiling reached or charging interrupted, stop charging"); #endif CHADEMO_Status = CHADEMO_STOP; return; @@ -273,8 +273,8 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { if (vehicle_permission && CHADEMO_Status == CHADEMO_NEGOTIATE) { CHADEMO_Status = CHADEMO_EV_ALLOWED; -#ifdef DEBUG_VIA_USB - Serial.println("STATE shift to CHADEMO_EV_ALLOWED in process_vehicle_charging_session()"); +#ifdef DEBUG_LOG + logging.println("STATE shift to CHADEMO_EV_ALLOWED in process_vehicle_charging_session()"); #endif return; } @@ -284,22 +284,22 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { // consider relocating if (vehicle_permission && CHADEMO_Status == CHADEMO_EVSE_PREPARE && priorTargetBatteryVoltage == 0 && newTargetBatteryVoltage > 0 && x102_chg_session.s.status.StatusVehicleChargingEnabled) { -#ifdef DEBUG_VIA_USB - Serial.println("STATE SHIFT to EVSE_START reached in process_vehicle_charging_session()"); +#ifdef DEBUG_LOG + logging.println("STATE SHIFT to EVSE_START reached in process_vehicle_charging_session()"); #endif CHADEMO_Status = CHADEMO_EVSE_START; return; } if (vehicle_permission && evse_permission && CHADEMO_Status == CHADEMO_POWERFLOW) { -#ifdef DEBUG_VIA_USB - Serial.println("updating vehicle request in process_vehicle_charging_session()"); +#ifdef DEBUG_LOG + logging.println("updating vehicle request in process_vehicle_charging_session()"); #endif return; } -#ifdef DEBUG_VIA_USB - Serial.println("UNHANDLED STATE IN process_vehicle_charging_session()"); +#ifdef DEBUG_LOG + logging.println("UNHANDLED STATE IN process_vehicle_charging_session()"); #endif return; } @@ -312,20 +312,20 @@ inline void process_vehicle_charging_limits(CAN_frame rx_frame) { x200_discharge_limits.MinimumBatteryDischargeLevel = rx_frame.data.u8[6]; x200_discharge_limits.MaxRemainingCapacityForCharging = rx_frame.data.u8[7]; -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG /* unsigned long currentMillis = millis(); if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { previousMillis5000 = currentMillis; - Serial.println("x200 Max remaining capacity for charging/discharging:"); + logging.println("x200 Max remaining capacity for charging/discharging:"); // initially this is set to 0, which is represented as 0xFF - Serial.println(0xFF - x200_discharge_limits.MaxRemainingCapacityForCharging); + logging.println(0xFF - x200_discharge_limits.MaxRemainingCapacityForCharging); } */ #endif if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage && CHADEMO_Status > CHADEMO_NEGOTIATE) { -#ifdef DEBUG_VIA_USB - Serial.println("x200 minimum discharge voltage met or exceeded, stopping."); +#ifdef DEBUG_LOG + logging.println("x200 minimum discharge voltage met or exceeded, stopping."); #endif CHADEMO_Status = CHADEMO_STOP; } @@ -341,13 +341,13 @@ inline void process_vehicle_discharge_estimate(CAN_frame rx_frame) { x201_discharge_estimate.ApproxDischargeCompletionTime = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[1]); x201_discharge_estimate.AvailableVehicleEnergy = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[3]); -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { previousMillis5000 = currentMillis; - Serial.print("x201 availabile vehicle energy, completion time: "); - Serial.println(x201_discharge_estimate.AvailableVehicleEnergy); - Serial.print("x201 approx vehicle completion time: "); - Serial.println(x201_discharge_estimate.ApproxDischargeCompletionTime); + logging.print("x201 availabile vehicle energy, completion time: "); + logging.println(x201_discharge_estimate.AvailableVehicleEnergy); + logging.print("x201 approx vehicle completion time: "); + logging.println(x201_discharge_estimate.ApproxDischargeCompletionTime); } #endif } @@ -369,17 +369,17 @@ inline void process_vehicle_vendor_ID(CAN_frame rx_frame) { void receive_can_battery(CAN_frame rx_frame) { #ifdef CH_CAN_DEBUG - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); + logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D + logging.print(" "); + logging.print(rx_frame.ID, HEX); + logging.print(" "); + logging.print(rx_frame.DLC); + logging.print(" "); for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); + logging.print(rx_frame.data.u8[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); #endif // CHADEMO coexists with a CAN-based shunt. Only process CHADEMO-specific IDs @@ -713,9 +713,9 @@ void send_can_battery() { // TODO need an update_evse_dynamic_control(..) function above before we send 118 // 110.0.0 if (x102_chg_session.ControlProtocolNumberEV >= 0x03) { //Only send the following on Chademo 2.0 vehicles? -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG //FIXME REMOVE - Serial.println("REMOVE: proto 2.0"); + logging.println("REMOVE: proto 2.0"); #endif transmit_can(&CHADEMO_118, can_config.battery); } @@ -753,15 +753,15 @@ void handle_chademo_sequence() { /* ------------------- State override conditions checks ------------------- */ /* ------------------------------------------------------------------------------ */ if (CHADEMO_Status >= CHADEMO_EV_ALLOWED && x102_chg_session.s.status.StatusVehicleShifterPosition) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle is not parked, abort."); +#ifdef DEBUG_LOG + logging.println("Vehicle is not parked, abort."); #endif CHADEMO_Status = CHADEMO_STOP; } if (CHADEMO_Status >= CHADEMO_EV_ALLOWED && !vehicle_permission) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle charge/discharge permission ended, stop."); +#ifdef DEBUG_LOG + logging.println("Vehicle charge/discharge permission ended, stop."); #endif CHADEMO_Status = CHADEMO_STOP; } @@ -775,24 +775,24 @@ void handle_chademo_sequence() { plug_inserted = digitalRead(CHADEMO_PIN_7); if (!plug_inserted) { -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug -// Serial.println("CHADEMO plug is not inserted."); +// logging.println("CHADEMO plug is not inserted."); #endif return; } CHADEMO_Status = CHADEMO_CONNECTED; -#ifdef DEBUG_VIA_USB - Serial.println("CHADEMO plug is inserted. Provide EVSE power to vehicle to trigger initialization."); +#ifdef DEBUG_LOG + logging.println("CHADEMO plug is inserted. Provide EVSE power to vehicle to trigger initialization."); #endif break; case CHADEMO_CONNECTED: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - //Serial.println("CHADEMO_CONNECTED State"); + //logging.println("CHADEMO_CONNECTED State"); #endif /* plug_inserted is .. essentially a volatile of sorts, so verify */ if (plug_inserted) { @@ -810,8 +810,8 @@ void handle_chademo_sequence() { * with timers to have higher confidence of certain conditions hitting * a steady state */ -#ifdef DEBUG_VIA_USB - Serial.println("CHADEMO plug is not inserted, cannot connect d2 relay to begin initialization."); +#ifdef DEBUG_LOG + logging.println("CHADEMO plug is not inserted, cannot connect d2 relay to begin initialization."); #endif CHADEMO_Status = CHADEMO_IDLE; } @@ -821,8 +821,8 @@ void handle_chademo_sequence() { * Used for triggers/error handling elsewhere; * State change to CHADEMO_NEGOTIATE occurs in receive_can_battery(..) */ -#ifdef DEBUG_VIA_USB -// Serial.println("Awaiting initial vehicle CAN to trigger negotiation"); +#ifdef DEBUG_LOG +// logging.println("Awaiting initial vehicle CAN to trigger negotiation"); #endif evse_init(); break; @@ -830,16 +830,16 @@ void handle_chademo_sequence() { /* Vehicle and EVSE dance */ //TODO if pin 4 / j goes high, -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug -// Serial.println("CHADEMO_NEGOTIATE State"); +// logging.println("CHADEMO_NEGOTIATE State"); #endif x109_evse_state.s.status.ChgDischStopControl = 1; break; case CHADEMO_EV_ALLOWED: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_EV_ALLOWED State"); + logging.println("CHADEMO_EV_ALLOWED State"); #endif // If we are in this state, vehicle_permission was already set to true...but re-verify // that pin 4 (j) reads high @@ -855,9 +855,9 @@ void handle_chademo_sequence() { } break; case CHADEMO_EVSE_PREPARE: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_EVSE_PREPARE State"); + logging.println("CHADEMO_EVSE_PREPARE State"); #endif /* TODO voltage check of output < 20v * insulation test hypothetically happens here before triggering PIN 10 high @@ -878,7 +878,7 @@ void handle_chademo_sequence() { digitalWrite(CHADEMO_PIN_10, HIGH); evse_permission = true; } else { - Serial.println("Insulation check measures > 20v "); + logging.println("Insulation check measures > 20v "); } // likely unnecessary but just to be sure. consider removal @@ -891,9 +891,9 @@ void handle_chademo_sequence() { //state changes to CHADEMO_EVSE_START only upon receipt of charging session request break; case CHADEMO_EVSE_START: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_EVSE_START State"); + logging.println("CHADEMO_EVSE_START State"); #endif datalayer.system.status.battery_allows_contactor_closing = true; x109_evse_state.s.status.ChgDischStopControl = 1; @@ -901,8 +901,8 @@ void handle_chademo_sequence() { CHADEMO_Status = CHADEMO_EVSE_CONTACTORS_ENABLED; -#ifdef DEBUG_VIA_USB - Serial.println("Initiating contactors"); +#ifdef DEBUG_LOG + logging.println("Initiating contactors"); #endif /* break rather than fall through because contactors are not instantaneous; @@ -911,17 +911,17 @@ void handle_chademo_sequence() { break; case CHADEMO_EVSE_CONTACTORS_ENABLED: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_EVSE_CONTACTORS State"); + logging.println("CHADEMO_EVSE_CONTACTORS State"); #endif /* check whether contactors ready, because externally dependent upon inverter allow during discharge */ if (contactors_ready) { -#ifdef DEBUG_VIA_USB - Serial.println("Contactors ready"); - Serial.print("Voltage: "); - Serial.println(get_measured_voltage()); +#ifdef DEBUG_LOG + logging.println("Contactors ready"); + logging.print("Voltage: "); + logging.println(get_measured_voltage()); #endif /* transition to POWERFLOW state if discharge compatible on both sides */ if (x109_evse_state.discharge_compatible && x102_chg_session.s.status.StatusVehicleDischargeCompatible && @@ -941,9 +941,9 @@ void handle_chademo_sequence() { /* break or fall through ? TODO */ break; case CHADEMO_POWERFLOW: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_POWERFLOW State"); + logging.println("CHADEMO_POWERFLOW State"); #endif /* POWERFLOW for charging, discharging, and bidirectional */ /* Interpretation */ @@ -961,8 +961,8 @@ void handle_chademo_sequence() { } if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage) { -#ifdef DEBUG_VIA_USB - Serial.println("x200 minimum discharge voltage met or exceeded, stopping."); +#ifdef DEBUG_LOG + logging.println("x200 minimum discharge voltage met or exceeded, stopping."); #endif CHADEMO_Status = CHADEMO_STOP; } @@ -972,9 +972,9 @@ void handle_chademo_sequence() { x109_evse_state.s.status.EVSE_status = 1; break; case CHADEMO_STOP: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_STOP State"); + logging.println("CHADEMO_STOP State"); #endif /* back to CHADEMO_IDLE after teardown */ x109_evse_state.s.status.ChgDischStopControl = 1; @@ -1000,16 +1000,16 @@ void handle_chademo_sequence() { break; case CHADEMO_FAULT: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_FAULT State"); + logging.println("CHADEMO_FAULT State"); #endif /* Once faulted, never departs CHADEMO_FAULT state unless device is power cycled as a safety measure */ x109_evse_state.s.status.EVSE_error = 1; x109_evse_state.s.status.ChgDischError = 1; x109_evse_state.s.status.ChgDischStopControl = 1; -#ifdef DEBUG_VIA_USB - Serial.println("CHADEMO fault encountered, tearing down to make safe"); +#ifdef DEBUG_LOG + logging.println("CHADEMO fault encountered, tearing down to make safe"); #endif digitalWrite(CHADEMO_PIN_10, LOW); digitalWrite(CHADEMO_PIN_2, LOW); @@ -1020,8 +1020,8 @@ void handle_chademo_sequence() { break; default: -#ifdef DEBUG_VIA_USB - Serial.println("UNHANDLED CHADEMO_STATE, setting FAULT"); +#ifdef DEBUG_LOG + logging.println("UNHANDLED CHADEMO_STATE, setting FAULT"); #endif CHADEMO_Status = CHADEMO_FAULT; break; diff --git a/Software/src/battery/CHADEMO-SHUNTS.cpp b/Software/src/battery/CHADEMO-SHUNTS.cpp index 6ca55ca73..92c0da68f 100644 --- a/Software/src/battery/CHADEMO-SHUNTS.cpp +++ b/Software/src/battery/CHADEMO-SHUNTS.cpp @@ -91,17 +91,17 @@ void ISA_handleFrame(CAN_frame* frame) { case 0x510: case 0x511: - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(frame->ID, HEX); - Serial.print(" "); - Serial.print(frame->DLC); - Serial.print(" "); + 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) { - Serial.print(frame->data.u8[i], HEX); - Serial.print(" "); + logging.print(frame->data.u8[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); break; case 0x521: @@ -245,8 +245,8 @@ void ISA_initialize() { ISA_STOP(); delay(500); for (int i = 0; i < 8; i++) { - Serial.print("ISA Initialization "); - Serial.println(i); + logging.print("ISA Initialization "); + logging.println(i); outframe.data.u8[0] = (0x20 + i); outframe.data.u8[1] = 0x02; @@ -271,7 +271,7 @@ void ISA_initialize() { } void ISA_STOP() { - Serial.println("ISA STOP"); + logging.println("ISA STOP"); outframe.data.u8[0] = 0x34; outframe.data.u8[1] = 0x00; @@ -286,7 +286,7 @@ void ISA_STOP() { } void ISA_sendSTORE() { - Serial.println("ISA send STORE"); + logging.println("ISA send STORE"); outframe.data.u8[0] = 0x32; outframe.data.u8[1] = 0x00; @@ -301,7 +301,7 @@ void ISA_sendSTORE() { } void ISA_START() { - Serial.println("ISA START"); + logging.println("ISA START"); outframe.data.u8[0] = 0x34; outframe.data.u8[1] = 0x01; @@ -317,7 +317,7 @@ void ISA_START() { void ISA_RESTART() { //Has the effect of zeroing AH and KWH - Serial.println("ISA RESTART"); + logging.println("ISA RESTART"); outframe.data.u8[0] = 0x3F; outframe.data.u8[1] = 0x00; @@ -336,7 +336,7 @@ void ISA_deFAULT() { ISA_STOP(); delay(500); - Serial.println("ISA RESTART to default"); + logging.println("ISA RESTART to default"); outframe.data.u8[0] = 0x3D; outframe.data.u8[1] = 0x00; @@ -358,7 +358,7 @@ void ISA_initCurrent() { ISA_STOP(); delay(500); - Serial.println("ISA Initialization Current"); + logging.println("ISA Initialization Current"); outframe.data.u8[0] = 0x21; outframe.data.u8[1] = 0x02; @@ -382,8 +382,8 @@ void ISA_initCurrent() { } void ISA_getCONFIG(uint8_t i) { - Serial.print("ISA Get Config "); - Serial.println(i); + logging.print("ISA Get Config "); + logging.println(i); outframe.data.u8[0] = (0x60 + i); outframe.data.u8[1] = 0x00; @@ -398,8 +398,8 @@ void ISA_getCONFIG(uint8_t i) { } void ISA_getCAN_ID(uint8_t i) { - Serial.print("ISA Get CAN ID "); - Serial.println(i); + logging.print("ISA Get CAN ID "); + logging.println(i); outframe.data.u8[0] = (0x50 + i); if (i == 8) @@ -418,8 +418,8 @@ void ISA_getCAN_ID(uint8_t i) { } void ISA_getINFO(uint8_t i) { - Serial.print("ISA Get INFO "); - Serial.println(i, HEX); + logging.print("ISA Get INFO "); + logging.println(i, HEX); outframe.data.u8[0] = (0x70 + i); outframe.data.u8[1] = 0x00; diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index 05e6e7c69..64a75e6c8 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -103,29 +103,29 @@ void update_values_battery() { //This function maps all the values fetched via } if (!BMU_Detected) { -#ifdef DEBUG_VIA_USB - Serial.println("BMU not detected, check wiring!"); +#ifdef DEBUG_LOG + logging.println("BMU not detected, check wiring!"); #endif } -#ifdef DEBUG_VIA_USB - Serial.println("Battery Values"); - Serial.print("BMU SOC: "); - Serial.print(BMU_SOC); - Serial.print(" BMU Current: "); - Serial.print(BMU_Current); - Serial.print(" BMU Battery Voltage: "); - Serial.print(BMU_PackVoltage); - Serial.print(" BMU_Power: "); - Serial.print(BMU_Power); - Serial.print(" Cell max voltage: "); - Serial.print(max_volt_cel); - Serial.print(" Cell min voltage: "); - Serial.print(min_volt_cel); - Serial.print(" Cell max temp: "); - Serial.print(max_temp_cel); - Serial.print(" Cell min temp: "); - Serial.println(min_temp_cel); +#ifdef DEBUG_LOG + 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); + logging.print(" Cell max voltage: "); + logging.print(max_volt_cel); + logging.print(" Cell min voltage: "); + logging.print(min_volt_cel); + logging.print(" Cell max temp: "); + logging.print(max_temp_cel); + logging.print(" Cell min temp: "); + logging.println(min_temp_cel); #endif } diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp index eb13017c1..1292f0ccd 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp @@ -57,9 +57,9 @@ CAN_frame ipace_keep_alive = {.FD = false, .data = {0x9E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};*/ void print_units(char* header, int value, char* units) { - Serial.print(header); - Serial.print(value); - Serial.print(units); + logging.print(header); + logging.print(value); + logging.print(units); } void update_values_battery() { @@ -104,8 +104,8 @@ void update_values_battery() { } /*Finally print out values to serial if configured to do so*/ -#ifdef DEBUG_VIA_USB - Serial.println("Values going to inverter"); +#ifdef DEBUG_LOG + logging.println("Values going to inverter"); print_units("SOH%: ", (datalayer.battery.status.soh_pptt * 0.01), "% "); print_units(", SOC%: ", (datalayer.battery.status.reported_soc * 0.01), "% "); print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V "); @@ -115,7 +115,7 @@ void update_values_battery() { print_units(", Min temp: ", (datalayer.battery.status.temperature_min_dC * 0.1), "°C "); print_units(", Max cell voltage: ", datalayer.battery.status.cell_max_voltage_mV, "mV "); print_units(", Min cell voltage: ", datalayer.battery.status.cell_min_voltage_mV, "mV "); - Serial.println(""); + logging.println(""); #endif } @@ -229,17 +229,17 @@ void receive_can_battery(CAN_frame rx_frame) { } // All CAN messages recieved will be logged via serial - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); + logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D + logging.print(" "); + logging.print(rx_frame.ID, HEX); + logging.print(" "); + logging.print(rx_frame.DLC); + logging.print(" "); for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); + logging.print(rx_frame.data.u8[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); } void send_can_battery() { diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index a0715a26a..476459aae 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -690,63 +690,63 @@ void update_values_battery() { //This function maps all the values fetched via /* Safeties verified. Perform USB serial printout if configured to do so */ -#ifdef DEBUG_VIA_USB - Serial.println(); //sepatator - Serial.println("Values from battery: "); - Serial.print("SOC BMS: "); - Serial.print((uint16_t)SOC_BMS / 10.0, 1); - Serial.print("% | SOC Display: "); - Serial.print((uint16_t)SOC_Display / 10.0, 1); - Serial.print("% | SOH "); - Serial.print((uint16_t)batterySOH / 10.0, 1); - Serial.println("%"); - Serial.print((int16_t)batteryAmps / 10.0, 1); - Serial.print(" Amps | "); - Serial.print((uint16_t)batteryVoltage / 10.0, 1); - Serial.print(" Volts | "); - Serial.print((int16_t)datalayer.battery.status.active_power_W); - Serial.println(" Watts"); - Serial.print("Allowed Charge "); - Serial.print((uint16_t)allowedChargePower * 10); - Serial.print(" W | Allowed Discharge "); - Serial.print((uint16_t)allowedDischargePower * 10); - Serial.println(" W"); - Serial.print("MaxCellVolt "); - Serial.print(CellVoltMax_mV); - Serial.print(" mV No "); - Serial.print(CellVmaxNo); - Serial.print(" | MinCellVolt "); - Serial.print(CellVoltMin_mV); - Serial.print(" mV No "); - Serial.println(CellVminNo); - Serial.print("TempHi "); - Serial.print((int16_t)temperatureMax); - Serial.print("°C TempLo "); - Serial.print((int16_t)temperatureMin); - Serial.print("°C WaterInlet "); - Serial.print((int8_t)temperature_water_inlet); - Serial.print("°C PowerRelay "); - Serial.print((int8_t)powerRelayTemperature * 2); - Serial.println("°C"); - Serial.print("Aux12volt: "); - Serial.print((int16_t)leadAcidBatteryVoltage / 10.0, 1); - Serial.println("V | "); - Serial.print("BmsManagementMode "); - Serial.print((uint8_t)batteryManagementMode, BIN); +#ifdef DEBUG_LOG + 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) { - Serial.print(" | BmsIgnition ON"); + logging.print(" | BmsIgnition ON"); } else { - Serial.print(" | BmsIgnition OFF"); + logging.print(" | BmsIgnition OFF"); } if (bitRead((uint8_t)batteryRelay, 0) == 1) { - Serial.print(" | PowerRelay ON"); + logging.print(" | PowerRelay ON"); } else { - Serial.print(" | PowerRelay OFF"); + logging.print(" | PowerRelay OFF"); } - Serial.print(" | Inverter "); - Serial.print(inverterVoltage); - Serial.println(" Volts"); + logging.print(" | Inverter "); + logging.print(inverterVoltage); + logging.println(" Volts"); #endif } @@ -808,7 +808,7 @@ void receive_can_battery(CAN_frame rx_frame) { // print_canfd_frame(frame); switch (rx_frame.data.u8[0]) { case 0x10: //"PID Header" - // Serial.println ("Send ack"); + // logging.println ("Send ack"); poll_data_pid = rx_frame.data.u8[4]; // if (rx_frame.data.u8[4] == poll_data_pid) { transmit_can(&EGMP_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 3a6663c65..ea55a988a 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -142,63 +142,63 @@ void update_values_battery() { //This function maps all the values fetched via /* Safeties verified. Perform USB serial printout if configured to do so */ -#ifdef DEBUG_VIA_USB - Serial.println(); //sepatator - Serial.println("Values from battery: "); - Serial.print("SOC BMS: "); - Serial.print((uint16_t)SOC_BMS / 10.0, 1); - Serial.print("% | SOC Display: "); - Serial.print((uint16_t)SOC_Display / 10.0, 1); - Serial.print("% | SOH "); - Serial.print((uint16_t)batterySOH / 10.0, 1); - Serial.println("%"); - Serial.print((int16_t)batteryAmps / 10.0, 1); - Serial.print(" Amps | "); - Serial.print((uint16_t)batteryVoltage / 10.0, 1); - Serial.print(" Volts | "); - Serial.print((int16_t)datalayer.battery.status.active_power_W); - Serial.println(" Watts"); - Serial.print("Allowed Charge "); - Serial.print((uint16_t)allowedChargePower * 10); - Serial.print(" W | Allowed Discharge "); - Serial.print((uint16_t)allowedDischargePower * 10); - Serial.println(" W"); - Serial.print("MaxCellVolt "); - Serial.print(CellVoltMax_mV); - Serial.print(" mV No "); - Serial.print(CellVmaxNo); - Serial.print(" | MinCellVolt "); - Serial.print(CellVoltMin_mV); - Serial.print(" mV No "); - Serial.println(CellVminNo); - Serial.print("TempHi "); - Serial.print((int16_t)temperatureMax); - Serial.print("°C TempLo "); - Serial.print((int16_t)temperatureMin); - Serial.print("°C WaterInlet "); - Serial.print((int8_t)temperature_water_inlet); - Serial.print("°C PowerRelay "); - Serial.print((int8_t)powerRelayTemperature * 2); - Serial.println("°C"); - Serial.print("Aux12volt: "); - Serial.print((int16_t)leadAcidBatteryVoltage / 10.0, 1); - Serial.println("V | "); - Serial.print("BmsManagementMode "); - Serial.print((uint8_t)batteryManagementMode, BIN); +#ifdef DEBUG_LOG + 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) { - Serial.print(" | BmsIgnition ON"); + logging.print(" | BmsIgnition ON"); } else { - Serial.print(" | BmsIgnition OFF"); + logging.print(" | BmsIgnition OFF"); } if (bitRead((uint8_t)batteryRelay, 0) == 1) { - Serial.print(" | PowerRelay ON"); + logging.print(" | PowerRelay ON"); } else { - Serial.print(" | PowerRelay OFF"); + logging.print(" | PowerRelay OFF"); } - Serial.print(" | Inverter "); - Serial.print(inverterVoltage); - Serial.println(" Volts"); + logging.print(" | Inverter "); + logging.print(inverterVoltage); + logging.println(" Volts"); #endif } diff --git a/Software/src/battery/MG-5-BATTERY.cpp b/Software/src/battery/MG-5-BATTERY.cpp index 35c8ee965..006634ab6 100644 --- a/Software/src/battery/MG-5-BATTERY.cpp +++ b/Software/src/battery/MG-5-BATTERY.cpp @@ -42,10 +42,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.temperature_min_dC; datalayer.battery.status.temperature_max_dC; - -#ifdef DEBUG_VIA_USB - -#endif } void receive_can_battery(CAN_frame rx_frame) { diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index 096cb6292..6b3e35c36 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -103,36 +103,36 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.cell_max_voltage_mV = LB_Cell_Max_Voltage; -#ifdef DEBUG_VIA_USB - Serial.println("Values going to inverter:"); - Serial.print("SOH%: "); - Serial.print(datalayer.battery.status.soh_pptt); - Serial.print(", SOC% scaled: "); - Serial.print(datalayer.battery.status.reported_soc); - Serial.print(", Voltage: "); - Serial.print(datalayer.battery.status.voltage_dV); - Serial.print(", Max discharge power: "); - Serial.print(datalayer.battery.status.max_discharge_power_W); - Serial.print(", Max charge power: "); - Serial.print(datalayer.battery.status.max_charge_power_W); - Serial.print(", Max temp: "); - Serial.print(datalayer.battery.status.temperature_max_dC); - Serial.print(", Min temp: "); - Serial.print(datalayer.battery.status.temperature_min_dC); - Serial.print(", BMS Status (3=OK): "); - Serial.print(datalayer.battery.status.bms_status); - - Serial.println("Battery values: "); - Serial.print("Real SOC: "); - Serial.print(LB_SOC); - Serial.print(", Current: "); - Serial.print(LB_Current); - Serial.print(", kWh remain: "); - Serial.print(LB_kWh_Remaining); - Serial.print(", max mV: "); - Serial.print(LB_Cell_Max_Voltage); - Serial.print(", min mV: "); - Serial.print(LB_Cell_Min_Voltage); +#ifdef DEBUG_LOG + logging.println("Values going to inverter:"); + logging.print("SOH%: "); + logging.print(datalayer.battery.status.soh_pptt); + logging.print(", SOC% scaled: "); + logging.print(datalayer.battery.status.reported_soc); + logging.print(", Voltage: "); + logging.print(datalayer.battery.status.voltage_dV); + logging.print(", Max discharge power: "); + logging.print(datalayer.battery.status.max_discharge_power_W); + logging.print(", Max charge power: "); + logging.print(datalayer.battery.status.max_charge_power_W); + logging.print(", Max temp: "); + logging.print(datalayer.battery.status.temperature_max_dC); + logging.print(", Min temp: "); + logging.print(datalayer.battery.status.temperature_min_dC); + logging.print(", BMS Status (3=OK): "); + logging.print(datalayer.battery.status.bms_status); + + logging.println("Battery values: "); + logging.print("Real SOC: "); + logging.print(LB_SOC); + logging.print(", Current: "); + logging.print(LB_Current); + logging.print(", kWh remain: "); + logging.print(LB_kWh_Remaining); + logging.print(", max mV: "); + logging.print(LB_Cell_Max_Voltage); + logging.print(", min mV: "); + logging.print(LB_Cell_Min_Voltage); #endif } diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp index 08ac57bfe..9c35d7da0 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp @@ -216,10 +216,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.zoePH2.battery_pack_time = battery_pack_time; datalayer_extended.zoePH2.battery_soc_min = battery_soc_min; datalayer_extended.zoePH2.battery_soc_max = battery_soc_max; - -#ifdef DEBUG_VIA_USB - -#endif } void receive_can_battery(CAN_frame rx_frame) { diff --git a/Software/src/battery/RJXZS-BMS.cpp b/Software/src/battery/RJXZS-BMS.cpp index 85b96434c..c59a99f1a 100644 --- a/Software/src/battery/RJXZS-BMS.cpp +++ b/Software/src/battery/RJXZS-BMS.cpp @@ -162,17 +162,17 @@ void receive_can_battery(CAN_frame rx_frame) { /* // All CAN messages recieved will be logged via serial - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); + logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D + logging.print(" "); + logging.print(rx_frame.ID, HEX); + logging.print(" "); + logging.print(rx_frame.DLC); + logging.print(" "); for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); + logging.print(rx_frame.data.u8[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); */ switch (rx_frame.ID) { case 0xF5: // This is the only message is sent from BMS diff --git a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp index 41697c33b..349f4d82c 100644 --- a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp +++ b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp @@ -94,8 +94,8 @@ void manageSerialLinkReceiver() { bool readError = dataLinkReceive.checkReadError(true); // check for error & clear error flag if (readError) { - Serial.print(currentTime); - Serial.println(" - ERROR: SerialDataLink - Read Error"); + logging.print(currentTime); + logging.println(" - ERROR: SerialDataLink - Read Error"); lasterror = true; errors++; } @@ -112,8 +112,8 @@ void manageSerialLinkReceiver() { //bms_status = ACTIVE; // just testing if (lasterror) { lasterror = false; - Serial.print(currentTime); - Serial.println(" - RECOVERY: SerialDataLink - Read GOOD"); + logging.print(currentTime); + logging.println(" - RECOVERY: SerialDataLink - Read GOOD"); } } @@ -134,34 +134,34 @@ void manageSerialLinkReceiver() { // report Lost data & Max charge / Discharge reductions if (minutesLost != last_minutesLost) { last_minutesLost = minutesLost; - Serial.print(currentTime); + logging.print(currentTime); if (batteryFault) { - Serial.print("Battery Fault (minutes) : "); + logging.print("Battery Fault (minutes) : "); } else { - Serial.print(" - Minutes without data : "); + logging.print(" - Minutes without data : "); } - Serial.print(minutesLost); - Serial.print(", max Charge = "); - Serial.print(datalayer.battery.status.max_charge_power_W); - Serial.print(", max Discharge = "); - Serial.println(datalayer.battery.status.max_discharge_power_W); + logging.print(minutesLost); + logging.print(", max Charge = "); + logging.print(datalayer.battery.status.max_charge_power_W); + logging.print(", max Discharge = "); + logging.println(datalayer.battery.status.max_discharge_power_W); } } if (currentTime - reportTime > 59999) { reportTime = currentTime; - Serial.print(currentTime); - Serial.print(" SerialDataLink-Receiver - NewData :"); - Serial.print(reads); - Serial.print(" Errors : "); - Serial.println(errors); + logging.print(currentTime); + logging.print(" SerialDataLink-Receiver - NewData :"); + logging.print(reads); + logging.print(" Errors : "); + logging.println(errors); reads = 0; errors = 0; // --- printUsefullData(); -//Serial.print("SOC = "); -//Serial.println(SOC); -#ifdef DEBUG_VIA_USB +//logging.print("SOC = "); +//logging.println(SOC); +#ifdef DEBUG_LOG update_values_serial_link(); #endif } @@ -179,43 +179,43 @@ void manageSerialLinkReceiver() { } void update_values_serial_link() { - Serial.println("Values from battery: "); - Serial.print("SOC: "); - Serial.print(datalayer.battery.status.real_soc); - Serial.print(" SOH: "); - Serial.print(datalayer.battery.status.soh_pptt); - Serial.print(" Voltage: "); - Serial.print(datalayer.battery.status.voltage_dV); - Serial.print(" Current: "); - Serial.print(datalayer.battery.status.current_dA); - Serial.print(" Capacity: "); - Serial.print(datalayer.battery.info.total_capacity_Wh); - Serial.print(" Remain cap: "); - Serial.print(datalayer.battery.status.remaining_capacity_Wh); - Serial.print(" Max discharge W: "); - Serial.print(datalayer.battery.status.max_discharge_power_W); - Serial.print(" Max charge W: "); - Serial.print(datalayer.battery.status.max_charge_power_W); - Serial.print(" BMS status: "); - Serial.print(datalayer.battery.status.bms_status); - Serial.print(" Power: "); - Serial.print(datalayer.battery.status.active_power_W); - Serial.print(" Temp min: "); - Serial.print(datalayer.battery.status.temperature_min_dC); - Serial.print(" Temp max: "); - Serial.print(datalayer.battery.status.temperature_max_dC); - Serial.print(" Cell max: "); - Serial.print(datalayer.battery.status.cell_max_voltage_mV); - Serial.print(" Cell min: "); - Serial.print(datalayer.battery.status.cell_min_voltage_mV); - Serial.print(" LFP : "); - Serial.print(datalayer.battery.info.chemistry); - Serial.print(" Battery Allows Contactor Closing: "); - Serial.print(datalayer.system.status.battery_allows_contactor_closing); - Serial.print(" Inverter Allows Contactor Closing: "); - Serial.print(datalayer.system.status.inverter_allows_contactor_closing); - - Serial.println(""); + logging.println("Values from battery: "); + logging.print("SOC: "); + logging.print(datalayer.battery.status.real_soc); + logging.print(" SOH: "); + logging.print(datalayer.battery.status.soh_pptt); + logging.print(" Voltage: "); + logging.print(datalayer.battery.status.voltage_dV); + logging.print(" Current: "); + logging.print(datalayer.battery.status.current_dA); + logging.print(" Capacity: "); + logging.print(datalayer.battery.info.total_capacity_Wh); + logging.print(" Remain cap: "); + logging.print(datalayer.battery.status.remaining_capacity_Wh); + logging.print(" Max discharge W: "); + logging.print(datalayer.battery.status.max_discharge_power_W); + logging.print(" Max charge W: "); + logging.print(datalayer.battery.status.max_charge_power_W); + logging.print(" BMS status: "); + logging.print(datalayer.battery.status.bms_status); + logging.print(" Power: "); + logging.print(datalayer.battery.status.active_power_W); + logging.print(" Temp min: "); + logging.print(datalayer.battery.status.temperature_min_dC); + logging.print(" Temp max: "); + logging.print(datalayer.battery.status.temperature_max_dC); + logging.print(" Cell max: "); + logging.print(datalayer.battery.status.cell_max_voltage_mV); + logging.print(" Cell min: "); + logging.print(datalayer.battery.status.cell_min_voltage_mV); + logging.print(" LFP : "); + logging.print(datalayer.battery.info.chemistry); + logging.print(" Battery Allows Contactor Closing: "); + logging.print(datalayer.system.status.battery_allows_contactor_closing); + logging.print(" Inverter Allows Contactor Closing: "); + logging.print(datalayer.system.status.inverter_allows_contactor_closing); + + logging.println(""); } void setup_battery(void) { diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index f6db10a88..cd6afd08d 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -408,69 +408,69 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.battery_soc_min = battery_soc_min; datalayer_extended.tesla.battery_soc_ui = battery_soc_ui; -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG printFaultCodesIfActive(); - Serial.print("STATUS: Contactor: "); - Serial.print(contactorText[battery_contactor]); //Display what state the contactor is in - Serial.print(", HVIL: "); - Serial.print(hvilStatusState[battery_hvil_status]); - Serial.print(", NegativeState: "); - Serial.print(contactorState[battery_packContNegativeState]); - Serial.print(", PositiveState: "); - Serial.print(contactorState[battery_packContPositiveState]); - Serial.print(", setState: "); - Serial.print(contactorState[battery_packContactorSetState]); - Serial.print(", close allowed: "); - Serial.print(battery_packCtrsClosingAllowed); - Serial.print(", Pyrotest: "); - Serial.println(battery_pyroTestInProgress); - - Serial.print("Battery values: "); - Serial.print("Real SOC: "); - Serial.print(battery_soc_ui / 10.0, 1); + logging.print("STATUS: Contactor: "); + logging.print(contactorText[battery_contactor]); //Display what state the contactor is in + logging.print(", HVIL: "); + logging.print(hvilStatusState[battery_hvil_status]); + logging.print(", NegativeState: "); + logging.print(contactorState[battery_packContNegativeState]); + logging.print(", PositiveState: "); + logging.print(contactorState[battery_packContPositiveState]); + logging.print(", setState: "); + logging.print(contactorState[battery_packContactorSetState]); + logging.print(", close allowed: "); + logging.print(battery_packCtrsClosingAllowed); + logging.print(", Pyrotest: "); + logging.println(battery_pyroTestInProgress); + + logging.print("Battery values: "); + logging.print("Real SOC: "); + logging.print(battery_soc_ui / 10.0, 1); print_int_with_units(", Battery voltage: ", battery_volts, "V"); print_int_with_units(", Battery HV current: ", (battery_amps * 0.1), "A"); - Serial.print(", Fully charged?: "); + logging.print(", Fully charged?: "); if (battery_full_charge_complete) - Serial.print("YES, "); + logging.print("YES, "); else - Serial.print("NO, "); + logging.print("NO, "); if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { - Serial.print("LFP chemistry detected!"); + logging.print("LFP chemistry detected!"); } - Serial.println(""); - Serial.print("Cellstats, Max: "); - Serial.print(battery_cell_max_v); - Serial.print("mV (cell "); - Serial.print(battery_max_vno); - Serial.print("), Min: "); - Serial.print(battery_cell_min_v); - Serial.print("mV (cell "); - Serial.print(battery_min_vno); - Serial.print("), Imbalance: "); - Serial.print(battery_cell_deviation_mV); - Serial.println("mV."); + logging.println(""); + logging.print("Cellstats, Max: "); + logging.print(battery_cell_max_v); + logging.print("mV (cell "); + logging.print(battery_max_vno); + logging.print("), Min: "); + logging.print(battery_cell_min_v); + logging.print("mV (cell "); + logging.print(battery_min_vno); + logging.print("), Imbalance: "); + logging.print(battery_cell_deviation_mV); + logging.println("mV."); print_int_with_units("High Voltage Output Pins: ", battery_dcdcHvBusVolt, "V"); - Serial.print(", "); + logging.print(", "); print_int_with_units("Low Voltage: ", battery_dcdcLvBusVolt, "V"); - Serial.println(""); + logging.println(""); print_int_with_units("DC/DC 12V current: ", battery_dcdcLvOutputCurrent, "A"); - Serial.println(""); + logging.println(""); - Serial.println("Values passed to the inverter: "); + logging.println("Values passed to the inverter: "); print_SOC(" SOC: ", datalayer.battery.status.reported_soc); print_int_with_units(" Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W"); - Serial.print(", "); + logging.print(", "); print_int_with_units(" Max charge power: ", datalayer.battery.status.max_charge_power_W, "W"); - Serial.println(""); + logging.println(""); print_int_with_units(" Max temperature: ", ((int16_t)datalayer.battery.status.temperature_min_dC * 0.1), "°C"); - Serial.print(", "); + logging.print(", "); print_int_with_units(" Min temperature: ", ((int16_t)datalayer.battery.status.temperature_max_dC * 0.1), "°C"); - Serial.println(""); -#endif //DEBUG_VIA_USB + logging.println(""); +#endif //DEBUG_LOG } void receive_can_battery(CAN_frame rx_frame) { @@ -1087,69 +1087,69 @@ void update_values_battery2() { //This function maps all the values fetched via } #endif // TESLA_MODEL_3Y_BATTERY -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG printFaultCodesIfActive_battery2(); - Serial.print("STATUS: Contactor: "); - Serial.print(contactorText[battery2_contactor]); //Display what state the contactor is in - Serial.print(", HVIL: "); - Serial.print(hvilStatusState[battery2_hvil_status]); - Serial.print(", NegativeState: "); - Serial.print(contactorState[battery2_packContNegativeState]); - Serial.print(", PositiveState: "); - Serial.print(contactorState[battery2_packContPositiveState]); - Serial.print(", setState: "); - Serial.print(contactorState[battery2_packContactorSetState]); - Serial.print(", close allowed: "); - Serial.print(battery2_packCtrsClosingAllowed); - Serial.print(", Pyrotest: "); - Serial.println(battery2_pyroTestInProgress); - - Serial.print("Battery2 values: "); - Serial.print("Real SOC: "); - Serial.print(battery2_soc_ui / 10.0, 1); + logging.print("STATUS: Contactor: "); + logging.print(contactorText[battery2_contactor]); //Display what state the contactor is in + logging.print(", HVIL: "); + logging.print(hvilStatusState[battery2_hvil_status]); + logging.print(", NegativeState: "); + logging.print(contactorState[battery2_packContNegativeState]); + logging.print(", PositiveState: "); + logging.print(contactorState[battery2_packContPositiveState]); + logging.print(", setState: "); + logging.print(contactorState[battery2_packContactorSetState]); + logging.print(", close allowed: "); + logging.print(battery2_packCtrsClosingAllowed); + logging.print(", Pyrotest: "); + logging.println(battery2_pyroTestInProgress); + + logging.print("Battery2 values: "); + logging.print("Real SOC: "); + logging.print(battery2_soc_ui / 10.0, 1); print_int_with_units(", Battery2 voltage: ", battery2_volts, "V"); print_int_with_units(", Battery2 HV current: ", (battery2_amps * 0.1), "A"); - Serial.print(", Fully charged?: "); + logging.print(", Fully charged?: "); if (battery2_full_charge_complete) - Serial.print("YES, "); + logging.print("YES, "); else - Serial.print("NO, "); + logging.print("NO, "); if (datalayer.battery2.info.chemistry == battery_chemistry_enum::LFP) { - Serial.print("LFP chemistry detected!"); + logging.print("LFP chemistry detected!"); } - Serial.println(""); - Serial.print("Cellstats, Max: "); - Serial.print(battery2_cell_max_v); - Serial.print("mV (cell "); - Serial.print(battery2_max_vno); - Serial.print("), Min: "); - Serial.print(battery2_cell_min_v); - Serial.print("mV (cell "); - Serial.print(battery2_min_vno); - Serial.print("), Imbalance: "); - Serial.print(battery2_cell_deviation_mV); - Serial.println("mV."); + logging.println(""); + logging.print("Cellstats, Max: "); + logging.print(battery2_cell_max_v); + logging.print("mV (cell "); + logging.print(battery2_max_vno); + logging.print("), Min: "); + logging.print(battery2_cell_min_v); + logging.print("mV (cell "); + logging.print(battery2_min_vno); + logging.print("), Imbalance: "); + logging.print(battery2_cell_deviation_mV); + logging.println("mV."); print_int_with_units("High Voltage Output Pins: ", battery2_dcdcHvBusVolt, "V"); - Serial.print(", "); + logging.print(", "); print_int_with_units("Low Voltage: ", battery2_dcdcLvBusVolt, "V"); - Serial.println(""); + logging.println(""); print_int_with_units("DC/DC 12V current: ", battery2_dcdcLvOutputCurrent, "A"); - Serial.println(""); + logging.println(""); - Serial.println("Values passed to the inverter: "); + logging.println("Values passed to the inverter: "); print_SOC(" SOC: ", datalayer.battery2.status.reported_soc); print_int_with_units(" Max discharge power: ", datalayer.battery2.status.max_discharge_power_W, "W"); - Serial.print(", "); + logging.print(", "); print_int_with_units(" Max charge power: ", datalayer.battery2.status.max_charge_power_W, "W"); - Serial.println(""); + logging.println(""); print_int_with_units(" Max temperature: ", ((int16_t)datalayer.battery2.status.temperature_min_dC * 0.1), "°C"); - Serial.print(", "); + logging.print(", "); print_int_with_units(" Min temperature: ", ((int16_t)datalayer.battery2.status.temperature_max_dC * 0.1), "°C"); - Serial.println(""); -#endif // DEBUG_VIA_USB + logging.println(""); +#endif // DEBUG_LOG } #endif //DOUBLE_BATTERY @@ -1261,32 +1261,32 @@ the first, for a few cycles, then stop all messages which causes the contactor } void print_int_with_units(char* header, int value, char* units) { - Serial.print(header); - Serial.print(value); - Serial.print(units); + logging.print(header); + logging.print(value); + logging.print(units); } void print_SOC(char* header, int SOC) { - Serial.print(header); - Serial.print(SOC / 100); - Serial.print("."); + logging.print(header); + logging.print(SOC / 100); + logging.print("."); int hundredth = SOC % 100; if (hundredth < 10) - Serial.print(0); - Serial.print(hundredth); - Serial.println("%"); + logging.print(0); + logging.print(hundredth); + logging.println("%"); } void printFaultCodesIfActive() { if (battery_packCtrsClosingAllowed == 0) { - Serial.println( + logging.println( "ERROR: Check high voltage connectors and interlock circuit! Closing contactor not allowed! Values: "); } if (battery_pyroTestInProgress == 1) { - Serial.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!"); + logging.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!"); } if (datalayer.system.status.inverter_allows_contactor_closing == false) { - Serial.println( + logging.println( "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter " "OR " "disable the inverter protocol to proceed with contactor closing"); @@ -1355,14 +1355,14 @@ void printFaultCodesIfActive() { #ifdef DOUBLE_BATTERY void printFaultCodesIfActive_battery2() { if (battery2_packCtrsClosingAllowed == 0) { - Serial.println( + logging.println( "ERROR: Check high voltage connectors and interlock circuit! Closing contactor not allowed! Values: "); } if (battery2_pyroTestInProgress == 1) { - Serial.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!"); + logging.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!"); } if (datalayer.system.status.inverter_allows_contactor_closing == false) { - Serial.println( + logging.println( "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter " "OR " "disable the inverter protocol to proceed with contactor closing"); @@ -1433,7 +1433,7 @@ void printFaultCodesIfActive_battery2() { void printDebugIfActive(uint8_t symbol, const char* message) { if (symbol == 1) { - Serial.println(message); + logging.println(message); } } diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index 30d9119dc..52b19b327 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -15,9 +15,9 @@ CAN_frame TEST = {.FD = false, .data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}}; void print_units(char* header, int value, char* units) { - Serial.print(header); - Serial.print(value); - Serial.print(units); + logging.print(header); + logging.print(value); + logging.print(units); } void update_values_battery() { /* This function puts fake values onto the parameters sent towards the inverter */ @@ -54,8 +54,8 @@ void update_values_battery() { /* This function puts fake values onto the parame datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; /*Finally print out values to serial if configured to do so*/ -#ifdef DEBUG_VIA_USB - Serial.println("FAKE Values going to inverter"); +#ifdef DEBUG_LOG + logging.println("FAKE Values going to inverter"); print_units("SOH%: ", (datalayer.battery.status.soh_pptt * 0.01), "% "); print_units(", SOC%: ", (datalayer.battery.status.reported_soc * 0.01), "% "); print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V "); @@ -65,7 +65,7 @@ void update_values_battery() { /* This function puts fake values onto the parame print_units(", Min temp: ", (datalayer.battery.status.temperature_min_dC * 0.1), "°C "); print_units(", Max cell voltage: ", datalayer.battery.status.cell_max_voltage_mV, "mV "); print_units(", Min cell voltage: ", datalayer.battery.status.cell_min_voltage_mV, "mV "); - Serial.println(""); + logging.println(""); #endif } @@ -107,8 +107,8 @@ void update_values_battery2() { // Handle the values coming in from battery #2 datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; /*Finally print out values to serial if configured to do so*/ -#ifdef DEBUG_VIA_USB - Serial.println("FAKE Values battery 2 going to inverter"); +#ifdef DEBUG_LOG + logging.println("FAKE Values battery 2 going to inverter"); print_units("SOH 2 %: ", (datalayer.battery2.status.soh_pptt * 0.01), "% "); print_units(", SOC 2 %: ", (datalayer.battery2.status.reported_soc * 0.01), "% "); print_units(", Voltage 2: ", (datalayer.battery2.status.voltage_dV * 0.1), "V "); @@ -118,7 +118,7 @@ void update_values_battery2() { // Handle the values coming in from battery #2 print_units(", Min temp 2: ", (datalayer.battery2.status.temperature_min_dC * 0.1), "°C "); print_units(", Max cell voltage 2: ", datalayer.battery2.status.cell_max_voltage_mV, "mV "); print_units(", Min cell voltage 2: ", datalayer.battery2.status.cell_min_voltage_mV, "mV "); - Serial.println(""); + logging.println(""); #endif } diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index 839665c88..0c8b4e85c 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -94,49 +94,49 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.cell_voltages_mV[i] = cell_voltages[i]; } -#ifdef DEBUG_VIA_USB - Serial.print("BMS reported SOC%: "); - Serial.println(SOC_BMS); - Serial.print("Calculated SOC%: "); - Serial.println(SOC_CALC); - Serial.print("Rescaled SOC%: "); - Serial.println(datalayer.battery.status.reported_soc / 100); - Serial.print("Battery current: "); - Serial.println(BATT_I); - Serial.print("Battery voltage: "); - Serial.println(BATT_U); - Serial.print("Battery maximum voltage limit: "); - Serial.println(MAX_U); - Serial.print("Battery minimum voltage limit: "); - Serial.println(MIN_U); - Serial.print("Remaining Energy: "); - Serial.println(remaining_capacity); - Serial.print("Discharge limit: "); - Serial.println(HvBattPwrLimDchaSoft); - Serial.print("Battery Error Indication: "); - Serial.println(BATT_ERR_INDICATION); - Serial.print("Maximum battery temperature: "); - Serial.println(BATT_T_MAX / 10); - Serial.print("Minimum battery temperature: "); - Serial.println(BATT_T_MIN / 10); - Serial.print("Average battery temperature: "); - Serial.println(BATT_T_AVG / 10); - Serial.print("BMS Highest cell voltage: "); - Serial.println(CELL_U_MAX * 10); - Serial.print("BMS Lowest cell voltage: "); - Serial.println(CELL_U_MIN * 10); - Serial.print("BMS Highest cell nr: "); - Serial.println(CELL_ID_U_MAX); - Serial.print("Highest cell voltage: "); - Serial.println(min_max_voltage[1]); - Serial.print("Lowest cell voltage: "); - Serial.println(min_max_voltage[0]); - Serial.print("Cell voltage,"); +#ifdef DEBUG_LOG + logging.print("BMS reported SOC%: "); + logging.println(SOC_BMS); + logging.print("Calculated SOC%: "); + logging.println(SOC_CALC); + logging.print("Rescaled SOC%: "); + logging.println(datalayer.battery.status.reported_soc / 100); + logging.print("Battery current: "); + logging.println(BATT_I); + logging.print("Battery voltage: "); + logging.println(BATT_U); + logging.print("Battery maximum voltage limit: "); + logging.println(MAX_U); + logging.print("Battery minimum voltage limit: "); + logging.println(MIN_U); + logging.print("Remaining Energy: "); + logging.println(remaining_capacity); + logging.print("Discharge limit: "); + logging.println(HvBattPwrLimDchaSoft); + logging.print("Battery Error Indication: "); + logging.println(BATT_ERR_INDICATION); + logging.print("Maximum battery temperature: "); + logging.println(BATT_T_MAX / 10); + logging.print("Minimum battery temperature: "); + logging.println(BATT_T_MIN / 10); + logging.print("Average battery temperature: "); + logging.println(BATT_T_AVG / 10); + logging.print("BMS Highest cell voltage: "); + logging.println(CELL_U_MAX * 10); + logging.print("BMS Lowest cell voltage: "); + logging.println(CELL_U_MIN * 10); + logging.print("BMS Highest cell nr: "); + logging.println(CELL_ID_U_MAX); + logging.print("Highest cell voltage: "); + logging.println(min_max_voltage[1]); + logging.print("Lowest cell voltage: "); + logging.println(min_max_voltage[0]); + logging.print("Cell voltage,"); while (cnt < 108) { - Serial.print(cell_voltages[cnt++]); - Serial.print(","); + logging.print(cell_voltages[cnt++]); + logging.print(","); } - Serial.println(";"); + logging.println(";"); #endif } @@ -148,8 +148,8 @@ void receive_can_battery(CAN_frame rx_frame) { BATT_I = (0 - ((((rx_frame.data.u8[6] & 0x7F) * 256.0 + rx_frame.data.u8[7]) * 0.1) - 1638)); else { BATT_I = 0; -#ifdef DEBUG_VIA_USB - Serial.println("BATT_I not valid"); +#ifdef DEBUG_LOG + logging.println("BATT_I not valid"); #endif } @@ -157,22 +157,22 @@ void receive_can_battery(CAN_frame rx_frame) { MAX_U = (((rx_frame.data.u8[2] & 0x07) * 256.0 + rx_frame.data.u8[3]) * 0.25); else { //MAX_U = 0; - //Serial.println("MAX_U not valid"); // Value toggles between true/false from BMS + //logging.println("MAX_U not valid"); // Value toggles between true/false from BMS } if ((rx_frame.data.u8[4] & 0x08) == 0x08) MIN_U = (((rx_frame.data.u8[4] & 0x07) * 256.0 + rx_frame.data.u8[5]) * 0.25); else { //MIN_U = 0; - //Serial.println("MIN_U not valid"); // Value toggles between true/false from BMS + //logging.println("MIN_U not valid"); // Value toggles between true/false from BMS } if ((rx_frame.data.u8[0] & 0x08) == 0x08) BATT_U = (((rx_frame.data.u8[0] & 0x07) * 256.0 + rx_frame.data.u8[1]) * 0.25); else { BATT_U = 0; -#ifdef DEBUG_VIA_USB - Serial.println("BATT_U not valid"); +#ifdef DEBUG_LOG + logging.println("BATT_U not valid"); #endif } break; @@ -189,8 +189,8 @@ void receive_can_battery(CAN_frame rx_frame) { BATT_ERR_INDICATION = ((rx_frame.data.u8[0] & 0x40) >> 6); else { BATT_ERR_INDICATION = 0; -#ifdef DEBUG_VIA_USB - Serial.println("BATT_ERR_INDICATION not valid"); +#ifdef DEBUG_LOG + logging.println("BATT_ERR_INDICATION not valid"); #endif } if ((rx_frame.data.u8[0] & 0x20) == 0x20) { @@ -201,8 +201,8 @@ void receive_can_battery(CAN_frame rx_frame) { BATT_T_MAX = 0; BATT_T_MIN = 0; BATT_T_AVG = 0; -#ifdef DEBUG_VIA_USB - Serial.println("BATT_T not valid"); +#ifdef DEBUG_LOG + logging.println("BATT_T not valid"); #endif } break; @@ -211,8 +211,8 @@ void receive_can_battery(CAN_frame rx_frame) { HvBattPwrLimDchaSoft = (((rx_frame.data.u8[6] & 0x03) * 256 + rx_frame.data.u8[6]) >> 2); } else { HvBattPwrLimDchaSoft = 0; -#ifdef DEBUG_VIA_USB - Serial.println("HvBattPwrLimDchaSoft not valid"); +#ifdef DEBUG_LOG + logging.println("HvBattPwrLimDchaSoft not valid"); #endif } break; @@ -221,8 +221,8 @@ void receive_can_battery(CAN_frame rx_frame) { SOC_BMS = ((rx_frame.data.u8[6] & 0x03) * 256 + rx_frame.data.u8[7]); } else { SOC_BMS = 0; -#ifdef DEBUG_VIA_USB - Serial.println("SOC_BMS not valid"); +#ifdef DEBUG_LOG + logging.println("SOC_BMS not valid"); #endif } @@ -230,8 +230,8 @@ void receive_can_battery(CAN_frame rx_frame) { CELL_U_MAX = ((rx_frame.data.u8[2] & 0x01) * 256 + rx_frame.data.u8[3]); else { CELL_U_MAX = 0; -#ifdef DEBUG_VIA_USB - Serial.println("CELL_U_MAX not valid"); +#ifdef DEBUG_LOG + logging.println("CELL_U_MAX not valid"); #endif } @@ -239,8 +239,8 @@ void receive_can_battery(CAN_frame rx_frame) { CELL_U_MIN = ((rx_frame.data.u8[0] & 0x01) * 256.0 + rx_frame.data.u8[1]); else { CELL_U_MIN = 0; -#ifdef DEBUG_VIA_USB - Serial.println("CELL_U_MIN not valid"); +#ifdef DEBUG_LOG + logging.println("CELL_U_MIN not valid"); #endif } @@ -248,8 +248,8 @@ void receive_can_battery(CAN_frame rx_frame) { CELL_ID_U_MAX = ((rx_frame.data.u8[4] & 0x01) * 256.0 + rx_frame.data.u8[5]); else { CELL_ID_U_MAX = 0; -#ifdef DEBUG_VIA_USB - Serial.println("CELL_ID_U_MAX not valid"); +#ifdef DEBUG_LOG + logging.println("CELL_ID_U_MAX not valid"); #endif } break; diff --git a/Software/src/charger/CHEVY-VOLT-CHARGER.cpp b/Software/src/charger/CHEVY-VOLT-CHARGER.cpp index 75cfd0215..3b947d2dd 100644 --- a/Software/src/charger/CHEVY-VOLT-CHARGER.cpp +++ b/Software/src/charger/CHEVY-VOLT-CHARGER.cpp @@ -101,8 +101,8 @@ void receive_can_charger(CAN_frame rx_frame) { case 0x308: break; default: -#ifdef DEBUG_VIA_USB - Serial.printf("CAN Rcv unknown frame MsgID=%x\n", rx_frame.MsgID); +#ifdef DEBUG_LOG + logging.printf("CAN Rcv unknown frame MsgID=%x\n", rx_frame.MsgID); #endif break; } @@ -177,15 +177,15 @@ void send_can_charger() { transmit_can(&charger_set_targets, can_config.charger); } -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG /* Serial echo every 5s of charger stats */ if (currentMillis - previousMillis5000ms >= INTERVAL_5_S) { previousMillis5000ms = currentMillis; - Serial.printf("Charger AC in IAC=%fA VAC=%fV\n", charger_stat_ACcur, charger_stat_ACvol); - Serial.printf("Charger HV out IDC=%fA VDC=%fV\n", charger_stat_HVcur, charger_stat_HVvol); - Serial.printf("Charger LV out IDC=%fA VDC=%fV\n", charger_stat_LVcur, charger_stat_LVvol); - Serial.printf("Charger mode=%s\n", (charger_mode > MODE_DISABLED) ? "Enabled" : "Disabled"); - Serial.printf("Charger HVset=%uV,%uA finishCurrent=%uA\n", setpoint_HV_VDC, setpoint_HV_IDC, setpoint_HV_IDC_END); + logging.printf("Charger AC in IAC=%fA VAC=%fV\n", charger_stat_ACcur, charger_stat_ACvol); + logging.printf("Charger HV out IDC=%fA VDC=%fV\n", charger_stat_HVcur, charger_stat_HVvol); + logging.printf("Charger LV out IDC=%fA VDC=%fV\n", charger_stat_LVcur, charger_stat_LVvol); + logging.printf("Charger mode=%s\n", (charger_mode > MODE_DISABLED) ? "Enabled" : "Disabled"); + logging.printf("Charger HVset=%uV,%uA finishCurrent=%uA\n", setpoint_HV_VDC, setpoint_HV_IDC, setpoint_HV_IDC_END); } #endif } diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index 8d7923fda..8fa2ab3d9 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -35,31 +35,31 @@ void init_CAN() { ESP32Can.CANInit(); #ifdef CAN_ADDON -#ifdef DEBUG_VIA_USB - Serial.println("Dual CAN Bus (ESP32+MCP2515) selected"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Dual CAN Bus (ESP32+MCP2515) selected"); +#endif // DEBUG_LOG gBuffer.initWithSize(25); SPI.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); ACAN2515Settings settings(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s settings.mRequestedMode = ACAN2515Settings::NormalMode; const uint16_t errorCodeMCP = can.begin(settings, [] { can.isr(); }); if (errorCodeMCP == 0) { -#ifdef DEBUG_VIA_USB - Serial.println("Can ok"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Can ok"); +#endif // DEBUG_LOG } else { -#ifdef DEBUG_VIA_USB - Serial.print("Error Can: 0x"); - Serial.println(errorCodeMCP, HEX); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.print("Error Can: 0x"); + logging.println(errorCodeMCP, HEX); +#endif // DEBUG_LOG set_event(EVENT_CANMCP_INIT_FAILURE, (uint8_t)errorCodeMCP); } #endif // CAN_ADDON #ifdef CANFD_ADDON -#ifdef DEBUG_VIA_USB - Serial.println("CAN FD add-on (ESP32+MCP2517) selected"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("CAN FD add-on (ESP32+MCP2517) selected"); +#endif // DEBUG_LOG SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s @@ -71,29 +71,29 @@ void init_CAN() { const uint32_t errorCode = canfd.begin(settings, [] { canfd.isr(); }); canfd.poll(); if (errorCode == 0) { -#ifdef DEBUG_VIA_USB - Serial.print("Bit Rate prescaler: "); - Serial.println(settings.mBitRatePrescaler); - Serial.print("Arbitration Phase segment 1: "); - Serial.println(settings.mArbitrationPhaseSegment1); - Serial.print("Arbitration Phase segment 2: "); - Serial.println(settings.mArbitrationPhaseSegment2); - Serial.print("Arbitration SJW:"); - Serial.println(settings.mArbitrationSJW); - Serial.print("Actual Arbitration Bit Rate: "); - Serial.print(settings.actualArbitrationBitRate()); - Serial.println(" bit/s"); - Serial.print("Exact Arbitration Bit Rate ? "); - Serial.println(settings.exactArbitrationBitRate() ? "yes" : "no"); - Serial.print("Arbitration Sample point: "); - Serial.print(settings.arbitrationSamplePointFromBitStart()); - Serial.println("%"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.print("Bit Rate prescaler: "); + logging.println(settings.mBitRatePrescaler); + logging.print("Arbitration Phase segment 1: "); + logging.print(settings.mArbitrationPhaseSegment1); + logging.print(" segment 2: "); + logging.print(settings.mArbitrationPhaseSegment2); + logging.print(" SJW: "); + logging.println(settings.mArbitrationSJW); + logging.print("Actual Arbitration Bit Rate: "); + logging.print(settings.actualArbitrationBitRate()); + logging.print(" bit/s"); + logging.print(" (Exact:"); + logging.println(settings.exactArbitrationBitRate() ? "yes)" : "no)"); + logging.print("Arbitration Sample point: "); + logging.print(settings.arbitrationSamplePointFromBitStart()); + logging.println("%"); +#endif // DEBUG_LOG } else { -#ifdef DEBUG_VIA_USB - Serial.print("CAN-FD Configuration error 0x"); - Serial.println(errorCode, HEX); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.print("CAN-FD Configuration error 0x"); + logging.println(errorCode, HEX); +#endif // DEBUG_LOG set_event(EVENT_CANFD_INIT_FAILURE, (uint8_t)errorCode); } #endif // CANFD_ADDON @@ -153,6 +153,8 @@ void transmit_can(CAN_frame* tx_frame, int interface) { send_ok = canfd.tryToSend(MCP2518Frame); if (!send_ok) { set_event(EVENT_CANFD_BUFFER_FULL, interface); + } else { + clear_event(EVENT_CANFD_BUFFER_FULL); } #else // Interface not compiled, and settings try to use it set_event(EVENT_INTERFACE_MISSING, interface); diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index 95f5444a7..6e1b6bd10 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -194,9 +194,9 @@ static void publish_common_info(void) { #endif // DOUBLE_BATTERY serializeJson(doc, mqtt_msg); if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) { -#ifdef DEBUG_VIA_USB - Serial.println("Common info MQTT msg could not be sent"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Common info MQTT msg could not be sent"); +#endif // DEBUG_LOG } doc.clear(); #ifdef HA_AUTODISCOVERY @@ -292,9 +292,9 @@ static void publish_cell_voltages(void) { serializeJson(doc, mqtt_msg, sizeof(mqtt_msg)); if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) { -#ifdef DEBUG_VIA_USB - Serial.println("Cell voltage MQTT msg could not be sent"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Cell voltage MQTT msg could not be sent"); +#endif // DEBUG_LOG } doc.clear(); } @@ -312,9 +312,9 @@ static void publish_cell_voltages(void) { serializeJson(doc, mqtt_msg, sizeof(mqtt_msg)); if (!mqtt_publish(state_topic_2.c_str(), mqtt_msg, false)) { -#ifdef DEBUG_VIA_USB - Serial.println("Cell voltage MQTT msg could not be sent"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Cell voltage MQTT msg could not be sent"); +#endif // DEBUG_LOG } doc.clear(); } @@ -384,9 +384,9 @@ void publish_events() { serializeJson(doc, mqtt_msg); if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) { -#ifdef DEBUG_VIA_USB - Serial.println("Common info MQTT msg could not be sent"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Common info MQTT msg could not be sent"); +#endif // DEBUG_LOG } else { set_event_MQTTpublished(event_handle); } @@ -402,9 +402,9 @@ void publish_events() { /* If we lose the connection, get it back */ static bool reconnect() { // attempt one reconnection -#ifdef DEBUG_VIA_USB - Serial.print("Attempting MQTT connection... "); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.print("Attempting MQTT connection... "); +#endif // DEBUG_LOG char clientId[64]; // Adjust the size as needed snprintf(clientId, sizeof(clientId), "BatteryEmulatorClient-%s", WiFi.getHostname()); // Attempt to connect @@ -413,19 +413,19 @@ static bool reconnect() { clear_event(EVENT_MQTT_DISCONNECT); set_event(EVENT_MQTT_CONNECT, 0); reconnectAttempts = 0; // Reset attempts on successful connection -#ifdef DEBUG_VIA_USB - Serial.println("connected"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("connected"); +#endif // DEBUG_LOG clear_event(EVENT_MQTT_CONNECT); } else { if (connected_once) set_event(EVENT_MQTT_DISCONNECT, 0); reconnectAttempts++; // Count failed attempts -#ifdef DEBUG_VIA_USB - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.print("failed, rc="); + logging.print(client.state()); + logging.println(" try again in 5 seconds"); +#endif // DEBUG_LOG // Wait 5 seconds before retrying } return client.connected(); @@ -449,9 +449,9 @@ void init_mqtt(void) { #endif client.setServer(MQTT_SERVER, MQTT_PORT); -#ifdef DEBUG_VIA_USB - Serial.println("MQTT initialized"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("MQTT initialized"); +#endif // DEBUG_LOG client.setKeepAlive(30); // Increase keepalive to manage network latency better. default is 15 @@ -478,8 +478,8 @@ void mqtt_loop(void) { if (reconnect()) { lastReconnectAttempt = 0; } else if (reconnectAttempts >= maxReconnectAttempts) { -#ifdef DEBUG_VIA_USB - Serial.println("Too many failed reconnect attempts, restarting client."); +#ifdef DEBUG_LOG + logging.println("Too many failed reconnect attempts, restarting client."); #endif client.disconnect(); // Force close the MQTT client connection reconnectAttempts = 0; // Reset attempts to avoid infinite loop diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index d51bd1c4d..021b1660a 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -118,15 +118,15 @@ void init_events(void) { // Push changes to eeprom EEPROM.commit(); -#ifdef DEBUG_VIA_USB - Serial.println("EEPROM wasn't ready"); +#ifdef DEBUG_LOG + logging.println("EEPROM wasn't ready"); #endif } else { events.event_log_head_index = EEPROM.readUShort(EE_EVENT_LOG_HEAD_INDEX_ADDRESS); events.event_log_tail_index = EEPROM.readUShort(EE_EVENT_LOG_TAIL_INDEX_ADDRESS); -#ifdef DEBUG_VIA_USB - Serial.println("EEPROM was initialized for event logging"); - Serial.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index)); +#ifdef DEBUG_LOG + logging.println("EEPROM was initialized for event logging"); + logging.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index)); #endif print_event_log(); } @@ -471,6 +471,10 @@ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) { if (events.entries[event].log) { log_event(event, events.entries[event].millisrolloverCount, events.entries[event].timestamp, data); } +#ifdef DEBUG_LOG + logging.print("Event: "); + logging.println(get_event_message_string(event)); +#endif } // We should set the event, update event info @@ -484,10 +488,6 @@ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) { events.level = max(events.level, events.entries[event].level); update_bms_status(); - -#ifdef DEBUG_VIA_USB - Serial.println(get_event_message_string(event)); -#endif } static void update_bms_status(void) { @@ -561,8 +561,8 @@ static void log_event(EVENTS_ENUM_TYPE event, uint8_t millisrolloverCount, uint3 // Store the new indices EEPROM.writeUShort(EE_EVENT_LOG_HEAD_INDEX_ADDRESS, events.event_log_head_index); EEPROM.writeUShort(EE_EVENT_LOG_TAIL_INDEX_ADDRESS, events.event_log_tail_index); - //Serial.println("Wrote event " + String(event) + " to " + String(entry_address)); - //Serial.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index)); + //logging.println("Wrote event " + String(event) + " to " + String(entry_address)); + //logging.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index)); // We don't need the exact number, it's just for deciding to store or not events.nof_logged_events += (events.nof_logged_events < 255) ? 1 : 0; @@ -571,8 +571,8 @@ static void log_event(EVENTS_ENUM_TYPE event, uint8_t millisrolloverCount, uint3 static void print_event_log(void) { // If the head actually points to the tail, the log is probably blank if (events.event_log_head_index == events.event_log_tail_index) { -#ifdef DEBUG_VIA_USB - Serial.println("No events in log"); +#ifdef DEBUG_LOG + logging.println("No events in log"); #endif return; } @@ -588,9 +588,9 @@ static void print_event_log(void) { // The entry is a blank that has been left behind somehow continue; } -#ifdef DEBUG_VIA_USB - Serial.println("Event: " + String(get_event_enum_string(entry.event)) + ", data: " + String(entry.data) + - ", time: " + String(entry.timestamp)); +#ifdef DEBUG_LOG + logging.println("Event: " + String(get_event_enum_string(entry.event)) + ", data: " + String(entry.data) + + ", time: " + String(entry.timestamp)); #endif if (index == events.event_log_head_index) { break; diff --git a/Software/src/devboard/utils/events_test_on_target.cpp b/Software/src/devboard/utils/events_test_on_target.cpp index 9f91e8df6..980c3f1fc 100644 --- a/Software/src/devboard/utils/events_test_on_target.cpp +++ b/Software/src/devboard/utils/events_test_on_target.cpp @@ -25,9 +25,9 @@ void run_sequence_on_target(void) { case ETOT_INIT: timer.set_interval(10000); events_test_state = ETOT_FIRST_WAIT; - Serial.println("Events test: initialized"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test: initialized"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); break; case ETOT_FIRST_WAIT: if (timer.elapsed()) { @@ -35,9 +35,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_INFO; set_event(EVENT_DUMMY_INFO, 123); set_event(EVENT_DUMMY_INFO, 234); // 234 should show, occurrence 1 - Serial.println("Events test: info event set, data: 234"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test: info event set, data: 234"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_INFO: @@ -45,9 +45,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_INFO); events_test_state = ETOT_INFO_CLEAR; - Serial.println("Events test : info event cleared"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : info event cleared"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_INFO_CLEAR: @@ -56,9 +56,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_DEBUG; set_event(EVENT_DUMMY_DEBUG, 111); set_event(EVENT_DUMMY_DEBUG, 222); // 222 should show, occurrence 1 - Serial.println("Events test : debug event set, data: 222"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : debug event set, data: 222"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_DEBUG: @@ -66,9 +66,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_DEBUG); events_test_state = ETOT_DEBUG_CLEAR; - Serial.println("Events test : info event cleared"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : info event cleared"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_DEBUG_CLEAR: @@ -77,9 +77,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_WARNING; set_event(EVENT_DUMMY_WARNING, 234); set_event(EVENT_DUMMY_WARNING, 121); // 121 should show, occurrence 1 - Serial.println("Events test : warning event set, data: 121"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : warning event set, data: 121"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_WARNING: @@ -87,9 +87,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_WARNING); events_test_state = ETOT_WARNING_CLEAR; - Serial.println("Events test : warning event cleared"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : warning event cleared"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_WARNING_CLEAR: @@ -98,9 +98,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_ERROR; set_event(EVENT_DUMMY_ERROR, 221); set_event(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1 - Serial.println("Events test : error event set, data: 133"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : error event set, data: 133"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_ERROR: @@ -108,9 +108,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_ERROR); events_test_state = ETOT_ERROR_CLEAR; - Serial.println("Events test : error event cleared"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : error event cleared"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_ERROR_CLEAR: @@ -119,9 +119,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_ERROR_LATCHED; set_event_latched(EVENT_DUMMY_ERROR, 221); set_event_latched(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1 - Serial.println("Events test : latched error event set, data: 133"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : latched error event set, data: 133"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_ERROR_LATCHED: @@ -129,9 +129,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_ERROR); events_test_state = ETOT_DONE; - Serial.println("Events test : latched error event cleared?"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : latched error event cleared?"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_DONE: diff --git a/Software/src/devboard/utils/logging.cpp b/Software/src/devboard/utils/logging.cpp new file mode 100644 index 000000000..0f78956f7 --- /dev/null +++ b/Software/src/devboard/utils/logging.cpp @@ -0,0 +1,86 @@ +#include "logging.h" +#include "../../datalayer/datalayer.h" + +size_t Logging::write(const uint8_t* buffer, size_t size) { +#ifdef DEBUG_LOG + 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); + unsigned long currentTime = millis(); +#ifdef DEBUG_VIA_USB + size_t n = 0; + while (size--) { + if (Serial.write(*buffer++)) + n++; + else + break; + } + return n; +#endif +#ifdef DEBUG_VIA_WEB + if (datalayer.system.info.can_logging_active) { + return 0; + } + if (offset + size + 13 > sizeof(datalayer.system.info.logged_can_messages)) { + offset = 0; + } + if (buffer[0] != '\r' && buffer[0] != '\n' && + (offset == 0 || message_string[offset - 1] == '\r' || message_string[offset - 1] == '\n')) { + offset += snprintf(message_string + offset, message_string_size - offset - 1, "%8lu.%03lu ", currentTime / 1000, + currentTime % 1000); + } + memcpy(message_string + offset, buffer, size); + datalayer.system.info.logged_can_messages_offset = offset + size; // Update offset in buffer + return size; +#endif // DEBUG_VIA_WEB +#endif // DEBUG_LOG + return 0; +} + +void Logging::printf(const char* fmt, ...) { +#ifdef DEBUG_LOG + 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); +#ifdef DEBUG_VIA_USB + static char buf[128]; + message_string = buf; + offset = 0; + message_string_size = sizeof(buf); +#endif +#ifdef DEBUG_VIA_WEB + if (datalayer.system.info.can_logging_active) { + return; + } + message_string = datalayer.system.info.logged_can_messages; + offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer + message_string_size = sizeof(datalayer.system.info.logged_can_messages); +#endif + if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { + // Not enough space, reset and start from the beginning + offset = 0; + } + unsigned long currentTime = millis(); + // Add timestamp + offset += snprintf(message_string + offset, message_string_size - offset - 1, "%8lu.%03lu ", currentTime / 1000, + currentTime % 1000); + + va_list(args); + va_start(args, fmt); + offset += vsnprintf(message_string + offset, message_string_size - offset - 1, fmt, args); + va_end(args); + + if (datalayer.system.info.can_logging_active) { + size_t size = offset; + size_t n = 0; + while (size--) { + if (Serial.write(*message_string++)) + n++; + else + break; + } + } else { + datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer + } +#endif // DEBUG_LOG +} diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h new file mode 100644 index 000000000..09b914589 --- /dev/null +++ b/Software/src/devboard/utils/logging.h @@ -0,0 +1,16 @@ +#ifndef __LOGGING_H__ +#define __LOGGING_H__ + +#include +#include "Print.h" + +class Logging : public Print { + public: + virtual size_t write(const uint8_t* buffer, size_t size); + virtual size_t write(uint8_t) { return 0; } + void printf(const char* fmt, ...); + Logging() {} +}; + +extern Logging logging; +#endif // __LOGGING_H__ diff --git a/Software/src/devboard/webserver/can_logging_html.cpp b/Software/src/devboard/webserver/can_logging_html.cpp index 59f038239..77f1975e7 100644 --- a/Software/src/devboard/webserver/can_logging_html.cpp +++ b/Software/src/devboard/webserver/can_logging_html.cpp @@ -4,6 +4,10 @@ String can_logger_processor(const String& var) { if (var == "X") { + if (!datalayer.system.info.can_logging_active) { + datalayer.system.info.logged_can_messages_offset = 0; + datalayer.system.info.logged_can_messages[0] = '\0'; + } datalayer.system.info.can_logging_active = true; // Signal to main loop that we should log messages. Disabled by default for performance reasons String content = ""; @@ -19,7 +23,7 @@ String can_logger_processor(const String& var) { "monospace; }"; content += ""; content += " "; - content += " "; + content += " "; content += ""; // Start a new block for the CAN messages @@ -47,9 +51,9 @@ String can_logger_processor(const String& var) { // Add JavaScript for navigation content += ""; return content; diff --git a/Software/src/devboard/webserver/debug_logging_html.cpp b/Software/src/devboard/webserver/debug_logging_html.cpp new file mode 100644 index 000000000..7dd9ede44 --- /dev/null +++ b/Software/src/devboard/webserver/debug_logging_html.cpp @@ -0,0 +1,36 @@ +#include "debug_logging_html.h" +#include +#include "../../datalayer/datalayer.h" + +#ifdef DEBUG_VIA_WEB +String debug_logger_processor(const String& var) { + String content = ""; + // Page format + content += ""; + content += " "; + content += " "; + content += ""; + + // Start a new block for the debug log messages + content += "
";
+  content += String(datalayer.system.info.logged_can_messages);
+  content += "
"; + + // Add JavaScript for navigation + content += ""; + return content; +} +#endif // DEBUG_VIA_WEB diff --git a/Software/src/devboard/webserver/debug_logging_html.h b/Software/src/devboard/webserver/debug_logging_html.h new file mode 100644 index 000000000..0b6ebc692 --- /dev/null +++ b/Software/src/devboard/webserver/debug_logging_html.h @@ -0,0 +1,16 @@ +#ifndef DEBUGLOGGER_H +#define DEBUGLOGGER_H + +#include +#include + +/** + * @brief Replaces placeholder with content section in web page + * + * @param[in] var + * + * @return String + */ +String debug_logger_processor(const String& var); + +#endif diff --git a/Software/src/devboard/webserver/events_html.cpp b/Software/src/devboard/webserver/events_html.cpp index 3cb3edbe8..a602b938f 100644 --- a/Software/src/devboard/webserver/events_html.cpp +++ b/Software/src/devboard/webserver/events_html.cpp @@ -39,11 +39,11 @@ String events_processor(const String& var) { for (const auto& event : order_events) { EVENTS_ENUM_TYPE event_handle = event.event_handle; event_pointer = event.event_pointer; -#ifdef DEBUG_VIA_USB - Serial.println("Event: " + String(get_event_enum_string(event_handle)) + - " count: " + String(event_pointer->occurences) + " seconds: " + String(event_pointer->timestamp) + - " data: " + String(event_pointer->data) + - " level: " + String(get_event_level_string(event_handle))); +#ifdef DEBUG_LOG + logging.println("Showing Event: " + String(get_event_enum_string(event_handle)) + + " count: " + String(event_pointer->occurences) + " seconds: " + String(event_pointer->timestamp) + + " data: " + String(event_pointer->data) + + " level: " + String(get_event_level_string(event_handle))); #endif content.concat("
"); content.concat("
" + String(get_event_enum_string(event_handle)) + "
"); diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 5468c7049..290657dbc 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -17,6 +17,7 @@ unsigned long ota_progress_millis = 0; #include "advanced_battery_html.h" #include "can_logging_html.h" #include "cellmonitor_html.h" +#include "debug_logging_html.h" #include "events_html.h" #include "index_html.cpp" #include "settings_html.h" @@ -63,14 +64,21 @@ void init_webserver() { request->send_P(200, "text/html", index_html, can_logger_processor); }); - // Define the handler to stop logging - server.on("/stop_logging", HTTP_GET, [](AsyncWebServerRequest* request) { +#ifdef DEBUG_VIA_WEB + // Route for going to debug logging web page + server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) { + request->send_P(200, "text/html", index_html, debug_logger_processor); + }); +#endif // DEBUG_VIA_WEB + + // Define the handler to stop can logging + server.on("/stop_can_logging", HTTP_GET, [](AsyncWebServerRequest* request) { datalayer.system.info.can_logging_active = false; request->send_P(200, "text/plain", "Logging stopped"); }); - // Define the handler to export logs - server.on("/export_logs", HTTP_GET, [](AsyncWebServerRequest* request) { + // Define the handler to export can log + server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) { String logs = String(datalayer.system.info.logged_can_messages); if (logs.length() == 0) { logs = "No logs available."; @@ -96,6 +104,33 @@ void init_webserver() { request->send(response); }); + // Define the handler to export debug log + server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) { + String logs = String(datalayer.system.info.logged_can_messages); + if (logs.length() == 0) { + logs = "No logs available."; + } + + // Get the current time + time_t now = time(nullptr); + struct tm timeinfo; + localtime_r(&now, &timeinfo); + + // Ensure time retrieval was successful + char filename[32]; + if (strftime(filename, sizeof(filename), "log_%H-%M-%S.txt", &timeinfo)) { + // Valid filename created + } else { + // Fallback filename if automatic timestamping failed + strcpy(filename, "battery_emulator_log.txt"); + } + + // Use request->send with dynamic headers + AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", logs); + response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\""); + request->send(response); + }); + // Route for going to cellmonitor web page server.on("/cellmonitor", HTTP_GET, [](AsyncWebServerRequest* request) { if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) @@ -535,14 +570,15 @@ String processor(const String& var) { content += "
"; // Show version number - content += "

Software: " + String(version_number) + "

"; + content += "

Software: " + String(version_number); // Show hardware used: #ifdef HW_LILYGO - content += "

Hardware: LilyGo T-CAN485

"; + content += " Hardware: LilyGo T-CAN485"; #endif // HW_LILYGO #ifdef HW_STARK - content += "

Hardware: Stark CMR Module

"; + content += " Hardware: Stark CMR Module"; #endif // HW_STARK + content += ""; content += "

Uptime: " + uptime_formatter::getUptime() + "

"; #ifdef FUNCTION_TIME_MEASUREMENT // Load information @@ -566,11 +602,14 @@ String processor(const String& var) { wl_status_t status = WiFi.status(); // Display ssid of network connected to and, if connected to the WiFi, its own IP - content += "

SSID: " + String(ssid.c_str()) + "

"; + content += "

SSID: " + String(ssid.c_str()); if (status == WL_CONNECTED) { - content += "

IP: " + WiFi.localIP().toString() + "

"; // Get and display the signal strength (RSSI) and channel - content += "

Signal strength: " + String(WiFi.RSSI()) + " dBm, at channel " + String(WiFi.channel()) + "

"; + content += " RSSI:" + String(WiFi.RSSI()) + " dBm Ch: " + String(WiFi.channel()); + } + content += ""; + if (status == WL_CONNECTED) { + content += "

IP: " + WiFi.localIP().toString() + "

"; } else { content += "

Wifi state: " + getConnectResultString(status) + "

"; } @@ -692,13 +731,30 @@ String processor(const String& var) { } content += "

Temperature max: " + String(tempMaxFloat, 1) + " C

"; content += "

Temperature min: " + String(tempMinFloat, 1) + " C

"; - if (datalayer.battery.status.bms_status == ACTIVE) { - content += "

System status: OK

"; - } else if (datalayer.battery.status.bms_status == UPDATING) { - content += "

System status: UPDATING

"; - } else { - content += "

System status: FAULT

"; + + content += "

System status: "; + switch (datalayer.battery.status.bms_status) { + case ACTIVE: + content += String("OK"); + break; + case UPDATING: + content += String("UPDATING"); + break; + case FAULT: + content += String("FAULT"); + break; + case INACTIVE: + content += String("INACTIVE"); + break; + case STANDBY: + content += String("STANDBY"); + break; + default: + content += String("??"); + break; } + content += "

"; + if (datalayer.battery.status.current_dA == 0) { content += "

Battery idle

"; } else if (datalayer.battery.status.current_dA < 0) { @@ -977,6 +1033,9 @@ String processor(const String& var) { content += " "; content += " "; content += " "; +#ifdef DEBUG_VIA_WEB + content += " "; +#endif // DEBUG_VIA_WEB content += " "; content += " "; content += ""; @@ -1002,6 +1061,7 @@ String processor(const String& var) { content += "function Settings() { window.location.href = '/settings'; }"; content += "function Advanced() { window.location.href = '/advanced'; }"; content += "function CANlog() { window.location.href = '/canlog'; }"; + content += "function Log() { window.location.href = '/log'; }"; content += "function Events() { window.location.href = '/events'; }"; content += "function askReboot() { if (window.confirm('Are you sure you want to reboot the emulator? NOTE: If " @@ -1062,9 +1122,9 @@ void onOTAProgress(size_t current, size_t final) { // Log every 1 second if (millis() - ota_progress_millis > 1000) { ota_progress_millis = millis(); -#ifdef DEBUG_VIA_USB - Serial.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final); +#endif // DEBUG_LOG // Reset the "watchdog" ota_timeout_timer.reset(); } @@ -1081,13 +1141,13 @@ void onOTAEnd(bool success) { // Max Charge/Discharge = 0; CAN = stop; contactors = open setBatteryPause(true, true, true, false); // a reboot will be done by the OTA library. no need to do anything here -#ifdef DEBUG_VIA_USB - Serial.println("OTA update finished successfully!"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("OTA update finished successfully!"); +#endif // DEBUG_LOG } else { -#ifdef DEBUG_VIA_USB - Serial.println("There was an error during OTA update!"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("There was an error during OTA update!"); +#endif // DEBUG_LOG //try to Resume the battery pause and CAN communication setBatteryPause(false, false); } diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 91862e2a9..3dba4b724 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -72,28 +72,28 @@ void wifi_monitor() { // Increase the current check interval if it's not at the maximum if (current_check_interval + STEP_WIFI_CHECK_INTERVAL <= MAX_STEP_WIFI_CHECK_INTERVAL) current_check_interval += STEP_WIFI_CHECK_INTERVAL; -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi not connected, attempting to reconnect..."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi not connected, attempting to reconnect..."); #endif // Try WiFi.reconnect() if it was successfully connected at least once if (hasConnectedBefore) { lastReconnectAttempt = millis(); // Reset reconnection attempt timer -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi reconnect attempt..."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi reconnect attempt..."); #endif if (WiFi.reconnect()) { -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi reconnect attempt sucess..."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi reconnect attempt sucess..."); #endif reconnectAttempts = 0; // Reset the attempt counter on successful reconnect } else { -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi reconnect attempt error..."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi reconnect attempt error..."); #endif reconnectAttempts++; if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) { -#ifdef DEBUG_VIA_USB - Serial.println("Failed to reconnect multiple times, forcing a full connection attempt..."); +#ifdef DEBUG_LOG + logging.println("Failed to reconnect multiple times, forcing a full connection attempt..."); #endif FullReconnectToWiFi(); } @@ -101,8 +101,8 @@ void wifi_monitor() { } else { // If no previous connection, force a full connection attempt if (currentMillis - lastReconnectAttempt > current_full_reconnect_interval) { -#ifdef DEBUG_VIA_USB - Serial.println("No previous OK connection, force a full connection attempt..."); +#ifdef DEBUG_LOG + logging.println("No previous OK connection, force a full connection attempt..."); #endif FullReconnectToWiFi(); } @@ -127,13 +127,13 @@ static void FullReconnectToWiFi() { static void connectToWiFi() { if (WiFi.status() != WL_CONNECTED) { lastReconnectAttempt = millis(); // Reset the reconnect attempt timer -#ifdef DEBUG_VIA_USB - Serial.println("Connecting to Wi-Fi..."); +#ifdef DEBUG_LOG + logging.println("Connecting to Wi-Fi..."); #endif WiFi.begin(ssid.c_str(), password.c_str(), wifi_channel); } else { -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi already connected."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi already connected."); #endif } } @@ -143,10 +143,11 @@ static void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) { clear_event(EVENT_WIFI_DISCONNECT); set_event(EVENT_WIFI_CONNECT, 0); connected_once = true; -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi connected."); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); +#ifdef DEBUG_LOG + logging.print("Wi-Fi connected. RSSI: "); + logging.print(-WiFi.RSSI()); + logging.print(" dBm, IP address: "); + logging.println(WiFi.localIP().toString()); #endif hasConnectedBefore = true; // Mark as successfully connected at least once reconnectAttempts = 0; // Reset the attempt counter @@ -159,10 +160,10 @@ static void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) { static void onWifiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { //clear disconnects events if we got a IP clear_event(EVENT_WIFI_DISCONNECT); -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi Got IP."); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); +#ifdef DEBUG_LOG + logging.print("Wi-Fi Got IP. "); + logging.print("IP address: "); + logging.println(WiFi.localIP().toString()); #endif } @@ -170,8 +171,8 @@ static void onWifiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { static void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info) { if (connected_once) set_event(EVENT_WIFI_DISCONNECT, 0); -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi disconnected."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi disconnected."); #endif //we dont do anything here, the reconnect will be handled by the monitor //too many events received when the connection is lost @@ -188,8 +189,8 @@ void init_mDNS() { // Initialize mDNS .local resolution if (!MDNS.begin(mdnsHost)) { -#ifdef DEBUG_VIA_USB - Serial.println("Error setting up MDNS responder!"); +#ifdef DEBUG_LOG + logging.println("Error setting up MDNS responder!"); #endif } else { // Advertise via bonjour the service so we can auto discover these battery emulators on the local network. @@ -200,16 +201,16 @@ void init_mDNS() { #ifdef WIFIAP void init_WiFi_AP() { -#ifdef DEBUG_VIA_USB - Serial.println("Creating Access Point: " + String(ssidAP)); - Serial.println("With password: " + String(passwordAP)); +#ifdef DEBUG_LOG + logging.println("Creating Access Point: " + String(ssidAP)); + logging.println("With password: " + String(passwordAP)); #endif WiFi.softAP(ssidAP, passwordAP); IPAddress IP = WiFi.softAPIP(); -#ifdef DEBUG_VIA_USB - Serial.println("Access Point created."); - Serial.print("IP address: "); - Serial.println(IP); +#ifdef DEBUG_LOG + logging.println("Access Point created."); + logging.print("IP address: "); + logging.println(IP); #endif } #endif // WIFIAP diff --git a/Software/src/include.h b/Software/src/include.h index 5d5520d88..c8ae60dfc 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -9,6 +9,7 @@ #include "devboard/hal/hal.h" #include "devboard/safety/safety.h" +#include "devboard/utils/logging.h" #include "devboard/utils/time_meas.h" #include "devboard/utils/types.h" diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index d7a4028ff..6d558edbd 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -153,13 +153,13 @@ void update_values_can_inverter() { //This function maps all the values fetched BYD_210.data.u8[2] = (datalayer.battery.status.temperature_min_dC >> 8); BYD_210.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF); -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG if (inverter_name[0] != 0) { - Serial.print("Detected inverter: "); + logging.print("Detected inverter: "); for (uint8_t i = 0; i < 7; i++) { - Serial.print((char)inverter_name[i]); + logging.print((char)inverter_name[i]); } - Serial.println(); + logging.println(); } #endif } diff --git a/Software/src/inverter/FOXESS-CAN.cpp b/Software/src/inverter/FOXESS-CAN.cpp index e23f90062..9522a6a08 100644 --- a/Software/src/inverter/FOXESS-CAN.cpp +++ b/Software/src/inverter/FOXESS-CAN.cpp @@ -595,8 +595,8 @@ void send_can_inverter() { // This function loops as fast as possible // Send a subset of messages per iteration to avoid overloading the CAN bus / transmit buffer switch (can_message_cellvolt_index) { case 0: -#ifdef DEBUG_VIA_USB - Serial.println("Sending large batch"); +#ifdef DEBUG_LOG + logging.println("Sending large batch"); #endif transmit_can(&FOXESS_0C1D, can_config.inverter); transmit_can(&FOXESS_0C21, can_config.inverter); @@ -655,8 +655,8 @@ void send_can_inverter() { // This function loops as fast as possible transmit_can(&FOXESS_0D49, can_config.inverter); transmit_can(&FOXESS_0D51, can_config.inverter); transmit_can(&FOXESS_0D59, can_config.inverter); -#ifdef DEBUG_VIA_USB - Serial.println("Sending completed"); +#ifdef DEBUG_LOG + logging.println("Sending completed"); #endif send_cellvoltages = false; break; @@ -679,14 +679,14 @@ void receive_can_inverter(CAN_frame rx_frame) { if (rx_frame.data.u8[0] == 0x03) { //0x1871 [0x03, 0x06, 0x17, 0x05, 0x09, 0x09, 0x28, 0x22] //This message is sent by the inverter every '6' seconds (0.5s after the pack serial numbers) //and contains a timestamp in bytes 2-7 i.e. ,,
,,, -#ifdef DEBUG_VIA_USB - Serial.println("Inverter sends current time and date"); +#ifdef DEBUG_LOG + logging.println("Inverter sends current time and date"); #endif } else if (rx_frame.data.u8[0] == 0x01) { if (rx_frame.data.u8[4] == 0x00) { // Inverter wants to know bms info (every 1s) -#ifdef DEBUG_VIA_USB - Serial.println("Inverter requests 1s BMS info, we reply"); +#ifdef DEBUG_LOG + logging.println("Inverter requests 1s BMS info, we reply"); #endif transmit_can(&FOXESS_1872, can_config.inverter); transmit_can(&FOXESS_1873, can_config.inverter); @@ -698,8 +698,8 @@ void receive_can_inverter(CAN_frame rx_frame) { transmit_can(&FOXESS_1879, can_config.inverter); } else if (rx_frame.data.u8[4] == 0x01) { // b4 0x01 , 0x1871 [0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00] //Inverter wants to know all individual cellvoltages (occurs 6 seconds after valid BMS reply) -#ifdef DEBUG_VIA_USB - Serial.println("Inverter requests individual battery pack status, we reply"); +#ifdef DEBUG_LOG + logging.println("Inverter requests individual battery pack status, we reply"); #endif transmit_can(&FOXESS_0C05, can_config.inverter); //TODO, should we limit this incase NUMBER_OF_PACKS =! 8? transmit_can(&FOXESS_0C06, can_config.inverter); @@ -711,19 +711,19 @@ void receive_can_inverter(CAN_frame rx_frame) { transmit_can(&FOXESS_0C0C, can_config.inverter); } else if (rx_frame.data.u8[4] == 0x04) { // b4 0x01 , 0x1871 [0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00] //Inverter wants to know all individual cellvoltages (occurs 6 seconds after valid BMS reply) -#ifdef DEBUG_VIA_USB - Serial.println("Inverter requests cellvoltages and temps, we reply"); +#ifdef DEBUG_LOG + logging.println("Inverter requests cellvoltages and temps, we reply"); #endif send_cellvoltages = true; } } else if (rx_frame.data.u8[0] == 0x02) { //0x1871 [0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00] // Ack message -#ifdef DEBUG_VIA_USB - Serial.println("Inverter acks, no reply needed"); +#ifdef DEBUG_LOG + logging.println("Inverter acks, no reply needed"); #endif } else if (rx_frame.data.u8[0] == 0x05) { //0x1871 [0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00] -#ifdef DEBUG_VIA_USB - Serial.println("Inverter wants to know serial numbers, we reply"); +#ifdef DEBUG_LOG + logging.println("Inverter wants to know serial numbers, we reply"); #endif for (uint8_t i = 0; i < (NUMBER_OF_PACKS + 1); i++) { FOXESS_1881.data.u8[0] = (uint8_t)i; diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 7df23ff1f..fc45c1b9f 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -119,15 +119,15 @@ void float2frameMSB(byte* arr, float value, byte framepointer) { void send_kostal(byte* arr, int alen) { #ifdef DEBUG_KOSTAL_RS485_DATA - Serial.print("TX: "); + logging.print("TX: "); for (int i = 0; i < alen; i++) { if (arr[i] < 0x10) { - Serial.print("0"); + logging.print("0"); } - Serial.print(arr[i], HEX); - Serial.print(" "); + logging.print(arr[i], HEX); + logging.print(" "); } - Serial.println("\n"); + logging.println("\n"); #endif Serial2.write(arr, alen); } @@ -274,12 +274,12 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream if (RS485_RXFRAME[rx_index - 1] == 0x00) { if ((rx_index == 10) && (RS485_RXFRAME[0] == 0x09) && register_content_ok) { #ifdef DEBUG_KOSTAL_RS485_DATA - Serial.print("RX: "); + logging.print("RX: "); for (uint8_t i = 0; i < 10; i++) { - Serial.print(RS485_RXFRAME[i], HEX); - Serial.print(" "); + logging.print(RS485_RXFRAME[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); #endif rx_index = 0; if (check_kostal_frame_crc()) { diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp index a61ea7dc0..35772e4a4 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp @@ -60,8 +60,8 @@ void manageSerialLinkTransmitter() { } bool sendError = dataLinkTransmit.checkTransmissionError(true); if (sendError) { - Serial.print(currentTime); - Serial.println(" - ERROR: Serial Data Link - SEND Error"); + logging.print(currentTime); + logging.println(" - ERROR: Serial Data Link - SEND Error"); lasterror = true; transmitGoodSince = currentTime; } @@ -82,17 +82,17 @@ void manageSerialLinkTransmitter() { if (lasterror && (ackReceived > 0)) { lasterror = false; - Serial.print(currentTime); - Serial.println(" - RECOVERY: Serial Data Link - Send GOOD"); + logging.print(currentTime); + logging.println(" - RECOVERY: Serial Data Link - Send GOOD"); } //--- reporting every 60 seconds that transmission is good if (currentTime - transmitGoodSince > INTERVAL_60_S) { transmitGoodSince = currentTime; - Serial.print(currentTime); - Serial.println(" - Transmit Good"); + logging.print(currentTime); + logging.println(" - Transmit Good"); // printUsefullData(); -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG void printSendingValues(); #endif } @@ -100,13 +100,13 @@ void manageSerialLinkTransmitter() { //--- report that Errors been ocurring for > 60 seconds if (currentTime - lastGood > INTERVAL_60_S) { lastGood = currentTime; - Serial.print(currentTime); - Serial.println(" - Transmit Failed : 60 seconds"); + logging.print(currentTime); + logging.println(" - Transmit Failed : 60 seconds"); // print the max_ data - Serial.println("SerialDataLink : bms_status=4"); - Serial.println("SerialDataLink : LEDcolor = RED"); - Serial.println("SerialDataLink : max_target_discharge_power = 0"); - Serial.println("SerialDataLink : max_target_charge_power = 0"); + logging.println("SerialDataLink : bms_status=4"); + logging.println("SerialDataLink : LEDcolor = RED"); + logging.println("SerialDataLink : max_target_discharge_power = 0"); + logging.println("SerialDataLink : max_target_charge_power = 0"); datalayer.battery.status.max_discharge_power_W = 0; datalayer.battery.status.max_charge_power_W = 0; @@ -117,8 +117,8 @@ void manageSerialLinkTransmitter() { // lastMessageReceived from CAN bus (Battery) if (currentTime - lastMessageReceived > (5 * 60000) ) // 5 minutes { - Serial.print(millis()); - Serial.println(" - Data Stale : 5 minutes"); + logging.print(millis()); + logging.println(" - Data Stale : 5 minutes"); // throw error // stop transmitting until fresh @@ -154,42 +154,42 @@ void manageSerialLinkTransmitter() { } void printSendingValues() { - Serial.println("Values from battery: "); - Serial.print("SOC: "); - Serial.print(datalayer.battery.status.real_soc); - Serial.print(" SOH: "); - Serial.print(datalayer.battery.status.soh_pptt); - Serial.print(" Voltage: "); - Serial.print(datalayer.battery.status.voltage_dV); - Serial.print(" Current: "); - Serial.print(datalayer.battery.status.current_dA); - Serial.print(" Capacity: "); - Serial.print(datalayer.battery.info.total_capacity_Wh); - Serial.print(" Remain cap: "); - Serial.print(datalayer.battery.status.remaining_capacity_Wh); - Serial.print(" Max discharge W: "); - Serial.print(datalayer.battery.status.max_discharge_power_W); - Serial.print(" Max charge W: "); - Serial.print(datalayer.battery.status.max_charge_power_W); - Serial.print(" BMS status: "); - Serial.print(datalayer.battery.status.bms_status); - Serial.print(" Power: "); - Serial.print(datalayer.battery.status.active_power_W); - Serial.print(" Temp min: "); - Serial.print(datalayer.battery.status.temperature_min_dC); - Serial.print(" Temp max: "); - Serial.print(datalayer.battery.status.temperature_max_dC); - Serial.print(" Cell max: "); - Serial.print(datalayer.battery.status.cell_max_voltage_mV); - Serial.print(" Cell min: "); - Serial.print(datalayer.battery.status.cell_min_voltage_mV); - Serial.print(" LFP : "); - Serial.print(datalayer.battery.info.chemistry); - Serial.print(" Battery Allows Contactor Closing: "); - Serial.print(datalayer.system.status.battery_allows_contactor_closing); - Serial.print(" Inverter Allows Contactor Closing: "); - Serial.print(datalayer.system.status.inverter_allows_contactor_closing); - - Serial.println(""); + logging.println("Values from battery: "); + logging.print("SOC: "); + logging.print(datalayer.battery.status.real_soc); + logging.print(" SOH: "); + logging.print(datalayer.battery.status.soh_pptt); + logging.print(" Voltage: "); + logging.print(datalayer.battery.status.voltage_dV); + logging.print(" Current: "); + logging.print(datalayer.battery.status.current_dA); + logging.print(" Capacity: "); + logging.print(datalayer.battery.info.total_capacity_Wh); + logging.print(" Remain cap: "); + logging.print(datalayer.battery.status.remaining_capacity_Wh); + logging.print(" Max discharge W: "); + logging.print(datalayer.battery.status.max_discharge_power_W); + logging.print(" Max charge W: "); + logging.print(datalayer.battery.status.max_charge_power_W); + logging.print(" BMS status: "); + logging.print(datalayer.battery.status.bms_status); + logging.print(" Power: "); + logging.print(datalayer.battery.status.active_power_W); + logging.print(" Temp min: "); + logging.print(datalayer.battery.status.temperature_min_dC); + logging.print(" Temp max: "); + logging.print(datalayer.battery.status.temperature_max_dC); + logging.print(" Cell max: "); + logging.print(datalayer.battery.status.cell_max_voltage_mV); + logging.print(" Cell min: "); + logging.print(datalayer.battery.status.cell_min_voltage_mV); + logging.print(" LFP : "); + logging.print(datalayer.battery.info.chemistry); + logging.print(" Battery Allows Contactor Closing: "); + logging.print(datalayer.system.status.battery_allows_contactor_closing); + logging.print(" Inverter Allows Contactor Closing: "); + logging.print(datalayer.system.status.inverter_allows_contactor_closing); + + logging.println(""); } #endif diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp index da036517e..60f684b96 100644 --- a/Software/src/inverter/SOLAX-CAN.cpp +++ b/Software/src/inverter/SOLAX-CAN.cpp @@ -207,8 +207,8 @@ void receive_can_inverter(CAN_frame rx_frame) { LastFrameTime = millis(); switch (STATE) { case (BATTERY_ANNOUNCE): -#ifdef DEBUG_VIA_USB - Serial.println("Solax Battery State: Announce"); +#ifdef DEBUG_LOG + logging.println("Solax Battery State: Announce"); #endif datalayer.system.status.inverter_allows_contactor_closing = false; SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on. @@ -239,8 +239,8 @@ void receive_can_inverter(CAN_frame rx_frame) { transmit_can(&SOLAX_1878, can_config.inverter); transmit_can(&SOLAX_1801, can_config.inverter); // Announce that the battery will be connected STATE = CONTACTOR_CLOSED; // Jump to Contactor Closed State -#ifdef DEBUG_VIA_USB - Serial.println("Solax Battery State: Contactor Closed"); +#ifdef DEBUG_LOG + logging.println("Solax Battery State: Contactor Closed"); #endif break; @@ -267,13 +267,13 @@ void receive_can_inverter(CAN_frame rx_frame) { if (rx_frame.ID == 0x1871 && rx_frame.data.u64 == __builtin_bswap64(0x0500010000000000)) { transmit_can(&SOLAX_1881, can_config.inverter); transmit_can(&SOLAX_1882, can_config.inverter); -#ifdef DEBUG_VIA_USB - Serial.println("1871 05-frame received from inverter"); +#ifdef DEBUG_LOG + logging.println("1871 05-frame received from inverter"); #endif } if (rx_frame.ID == 0x1871 && rx_frame.data.u8[0] == (0x03)) { -#ifdef DEBUG_VIA_USB - Serial.println("1871 03-frame received from inverter"); +#ifdef DEBUG_LOG + logging.println("1871 03-frame received from inverter"); #endif } } From ce2b714d30699b4570aa02b45ed74e13ad146972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 23 Dec 2024 15:35:38 +0200 Subject: [PATCH 107/225] Restore Async lib, implement Mutex locking --- README.md | 2 +- Software/USER_SETTINGS.h | 6 +- Software/src/devboard/webserver/webserver.h | 2 +- .../ayushsharma82-ElegantOTA/src/ElegantOTA.h | 2 +- .../mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md | 129 -- .../src/lib/mathieucarbou-AsyncTCP/README.md | 62 - .../lib/mathieucarbou-AsyncTCP/library.json | 38 - .../mathieucarbou-AsyncTCP/library.properties | 10 - .../lib/mathieucarbou-AsyncTCP/platformio.ini | 43 - .../mathieucarbou-AsyncTCP/src/AsyncTCP.cpp | 1661 ----------------- .../lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h | 347 ---- .../src/lib/me-no-dev-AsyncTCP/.gitignore | 2 + .../src/lib/me-no-dev-AsyncTCP/.travis.yml | 34 + .../CMakeLists.txt | 0 .../lib/me-no-dev-AsyncTCP/Kconfig.projbuild | 30 + .../LICENSE | 0 Software/src/lib/me-no-dev-AsyncTCP/README.md | 15 + .../component.mk | 0 .../src/lib/me-no-dev-AsyncTCP/library.json | 22 + .../lib/me-no-dev-AsyncTCP/library.properties | 9 + .../lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp | 1387 ++++++++++++++ .../src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h | 220 +++ .../src/AsyncEventSource.h | 2 +- .../src/AsyncWebSocket.h | 2 +- .../src/ESPAsyncWebServer.h | 4 +- 25 files changed, 1729 insertions(+), 2300 deletions(-) delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/README.md delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/library.json delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/library.properties delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp delete mode 100644 Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h create mode 100644 Software/src/lib/me-no-dev-AsyncTCP/.gitignore create mode 100644 Software/src/lib/me-no-dev-AsyncTCP/.travis.yml rename Software/src/lib/{mathieucarbou-AsyncTCP => me-no-dev-AsyncTCP}/CMakeLists.txt (100%) create mode 100644 Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild rename Software/src/lib/{mathieucarbou-AsyncTCP => me-no-dev-AsyncTCP}/LICENSE (100%) create mode 100644 Software/src/lib/me-no-dev-AsyncTCP/README.md rename Software/src/lib/{mathieucarbou-AsyncTCP => me-no-dev-AsyncTCP}/component.mk (100%) create mode 100644 Software/src/lib/me-no-dev-AsyncTCP/library.json create mode 100644 Software/src/lib/me-no-dev-AsyncTCP/library.properties create mode 100644 Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp create mode 100644 Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h diff --git a/README.md b/README.md index c2d9630c3..3d86f1202 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ This code uses the following excellent libraries: - [eModbus/eModbus](https://github.com/eModbus/eModbus) MIT-License - [knolleary/pubsubclient](https://github.com/knolleary/pubsubclient) MIT-License - [mackelec/SerialDataLink](https://github.com/mackelec/SerialDataLink) -- [mathieucarbou/AsyncTCP](https://github.com/mathieucarbou/AsyncTCP) LGPL-3.0 license +- [me-no-dev/AsyncTCP](https://github.com/me-no-dev/AsyncTCP) LGPL-3.0 license - [me-no-dev/ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) - [miwagner/ESP32-Arduino-CAN](https://github.com/miwagner/ESP32-Arduino-CAN/) MIT-License - [pierremolinaro/acan2515](https://github.com/pierremolinaro/acan2515) MIT-License diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 2cefdb7aa..90cb37f7f 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -33,7 +33,7 @@ //#define TESLA_MODEL_3Y_BATTERY //#define TESLA_MODEL_SX_BATTERY //#define VOLVO_SPA_BATTERY -//#define TEST_FAKE_BATTERY +#define TEST_FAKE_BATTERY //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires CAN_ADDON setup) /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ @@ -53,8 +53,8 @@ //#define SOLAX_CAN //Enable this line to emulate a "SolaX Triple Power LFP" over CAN bus /* Select hardware used for Battery-Emulator */ -#define HW_LILYGO -//#define HW_STARK +//#define HW_LILYGO +#define HW_STARK //#define HW_3LB /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h index 86b5a763a..a75ef8fb6 100644 --- a/Software/src/devboard/webserver/webserver.h +++ b/Software/src/devboard/webserver/webserver.h @@ -6,7 +6,7 @@ #include "../../include.h" #include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h" -#include "../../lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../lib/me-no-dev-AsyncTCP/src/AsyncTCP.h" #include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" diff --git a/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h b/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h index 48833d99c..f8770a076 100644 --- a/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h +++ b/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h @@ -64,7 +64,7 @@ _____ _ _ ___ _____ _ #include "Update.h" #include "StreamString.h" #if ELEGANTOTA_USE_ASYNC_WEBSERVER == 1 - #include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" + #include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #include "../../me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #define ELEGANTOTA_WEBSERVER AsyncWebServer #else diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md b/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md deleted file mode 100644 index 0a5f91417..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,129 +0,0 @@ - -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -https://sidweb.nl/cms3/en/contact. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/README.md b/Software/src/lib/mathieucarbou-AsyncTCP/README.md deleted file mode 100644 index d90814a1d..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# AsyncTCP - -[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/) -[![Continuous Integration](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml) -[![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/AsyncTCP.svg)](https://registry.platformio.org/libraries/mathieucarbou/AsyncTCP) - -A fork of the [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) library by [@me-no-dev](https://github.com/me-no-dev). - -### Async TCP Library for ESP32 Arduino - -This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs. - -This library is the base for [ESPAsyncWebServer](https://github.com/mathieucarbou/ESPAsyncWebServer) - -## AsyncClient and AsyncServer - -The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. - -## Changes in this fork - -- Based on [ESPHome fork](https://github.com/esphome/AsyncTCP) - -- `library.properties` for Arduino IDE users -- Add `CONFIG_ASYNC_TCP_MAX_ACK_TIME` -- Add `CONFIG_ASYNC_TCP_PRIORITY` -- Add `CONFIG_ASYNC_TCP_QUEUE_SIZE` -- Add `setKeepAlive()` -- Arduino 3 / ESP-IDF 5 compatibility -- Better CI -- Better example -- Customizable macros -- Fix for "Required to lock TCPIP core functionality". Ref: https://github.com/mathieucarbou/AsyncTCP/issues/27 and https://github.com/espressif/arduino-esp32/issues/10526 -- Fix for "ack timeout 4" client disconnects. -- Fix from https://github.com/me-no-dev/AsyncTCP/pull/173 (partially applied) -- Fix from https://github.com/me-no-dev/AsyncTCP/pull/184 -- IPv6 -- LIBRETINY support -- LibreTuya -- Reduce logging of non critical messages -- Use IPADDR6_INIT() macro to set connecting IPv6 address -- xTaskCreateUniversal function - -## Coordinates - -``` -mathieucarbou/AsyncTCP @ ^3.3.1 -``` - -## Important recommendations - -Most of the crashes are caused by improper configuration of the library for the project. -Here are some recommendations to avoid them. - -I personally use the following configuration in my projects: - -```c++ - -D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 // (keep default) - -D CONFIG_ASYNC_TCP_PRIORITY=10 // (keep default) - -D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 // (keep default) - -D CONFIG_ASYNC_TCP_RUNNING_CORE=1 // force async_tcp task to be on same core as the app (default is core 0) - -D CONFIG_ASYNC_TCP_STACK_SIZE=4096 // reduce the stack size (default is 16K) -``` diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/library.json b/Software/src/lib/mathieucarbou-AsyncTCP/library.json deleted file mode 100644 index 5d6e228b4..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/library.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "AsyncTCP", - "version": "3.3.1", - "description": "Asynchronous TCP Library for ESP32", - "keywords": "async,tcp", - "repository": { - "type": "git", - "url": "https://github.com/mathieucarbou/AsyncTCP.git" - }, - "authors": [ - { - "name": "Hristo Gochkov" - }, - { - "name": "Mathieu Carbou", - "maintainer": true - } - ], - "license": "LGPL-3.0", - "frameworks": "arduino", - "platforms": [ - "espressif32", - "libretiny" - ], - "build": { - "libCompatMode": 2 - }, - "export": { - "include": [ - "examples", - "src", - "library.json", - "library.properties", - "LICENSE", - "README.md" - ] - } -} \ No newline at end of file diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/library.properties b/Software/src/lib/mathieucarbou-AsyncTCP/library.properties deleted file mode 100644 index dd945f8de..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=Async TCP -includes=AsyncTCP.h -version=3.3.1 -author=Me-No-Dev -maintainer=Mathieu Carbou -sentence=Async TCP Library for ESP32 -paragraph=Async TCP Library for ESP32 -category=Other -url=https://github.com/mathieucarbou/AsyncTCP.git -architectures=* diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini b/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini deleted file mode 100644 index ec65a3674..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini +++ /dev/null @@ -1,43 +0,0 @@ -[platformio] -default_envs = arduino-2, arduino-3, arduino-310 -lib_dir = . -src_dir = examples/Client - -[env] -framework = arduino -build_flags = - -Wall -Wextra - -D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 - -D CONFIG_ASYNC_TCP_PRIORITY=10 - -D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 - -D CONFIG_ASYNC_TCP_RUNNING_CORE=1 - -D CONFIG_ASYNC_TCP_STACK_SIZE=4096 - -D CONFIG_ARDUHAL_LOG_COLORS - -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -upload_protocol = esptool -monitor_speed = 115200 -monitor_filters = esp32_exception_decoder, log2file -board = esp32dev - -[env:arduino-2] -platform = espressif32@6.9.0 - -[env:arduino-3] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip - -[env:arduino-310] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip - -; CI - -[env:ci-arduino-2] -platform = espressif32@6.9.0 -board = ${sysenv.PIO_BOARD} - -[env:ci-arduino-3] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip -board = ${sysenv.PIO_BOARD} - -[env:ci-arduino-310] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip -board = ${sysenv.PIO_BOARD} diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp b/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp deleted file mode 100644 index 9addb135e..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp +++ /dev/null @@ -1,1661 +0,0 @@ -/* - Asynchronous TCP library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "Arduino.h" - -#include "AsyncTCP.h" - -extern "C" { -#include "lwip/dns.h" -#include "lwip/err.h" -#include "lwip/inet.h" -#include "lwip/opt.h" -#include "lwip/tcp.h" -} - -#if CONFIG_ASYNC_TCP_USE_WDT - #include "esp_task_wdt.h" -#endif - -// Required for: -// https://github.com/espressif/arduino-esp32/blob/3.0.3/libraries/Network/src/NetworkInterface.cpp#L37-L47 -#if ESP_IDF_VERSION_MAJOR >= 5 - #include -#endif - -#define TAG "AsyncTCP" - -// https://github.com/espressif/arduino-esp32/issues/10526 -#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING - #define TCP_MUTEX_LOCK() \ - if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ - LOCK_TCPIP_CORE(); \ - } - - #define TCP_MUTEX_UNLOCK() \ - if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ - UNLOCK_TCPIP_CORE(); \ - } -#else // CONFIG_LWIP_TCPIP_CORE_LOCKING - #define TCP_MUTEX_LOCK() - #define TCP_MUTEX_UNLOCK() -#endif // CONFIG_LWIP_TCPIP_CORE_LOCKING - -#define INVALID_CLOSED_SLOT -1 - -/* - TCP poll interval is specified in terms of the TCP coarse timer interval, which is called twice a second - https://github.com/espressif/esp-lwip/blob/2acf959a2bb559313cd2bf9306c24612ba3d0e19/src/core/tcp.c#L1895 -*/ -#define CONFIG_ASYNC_TCP_POLL_TIMER 1 - -/* - * TCP/IP Event Task - * */ - -typedef enum { - LWIP_TCP_SENT, - LWIP_TCP_RECV, - LWIP_TCP_FIN, - LWIP_TCP_ERROR, - LWIP_TCP_POLL, - LWIP_TCP_CLEAR, - LWIP_TCP_ACCEPT, - LWIP_TCP_CONNECTED, - LWIP_TCP_DNS -} lwip_event_t; - -typedef struct { - lwip_event_t event; - void* arg; - union { - struct { - tcp_pcb* pcb; - int8_t err; - } connected; - struct { - int8_t err; - } error; - struct { - tcp_pcb* pcb; - uint16_t len; - } sent; - struct { - tcp_pcb* pcb; - pbuf* pb; - int8_t err; - } recv; - struct { - tcp_pcb* pcb; - int8_t err; - } fin; - struct { - tcp_pcb* pcb; - } poll; - struct { - AsyncClient* client; - } accept; - struct { - const char* name; - ip_addr_t addr; - } dns; - }; -} lwip_event_packet_t; - -static QueueHandle_t _async_queue; -static TaskHandle_t _async_service_task_handle = NULL; - -SemaphoreHandle_t _slots_lock; -const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP; -static uint32_t _closed_slots[_number_of_closed_slots]; -static uint32_t _closed_index = []() { - _slots_lock = xSemaphoreCreateBinary(); - xSemaphoreGive(_slots_lock); - for (int i = 0; i < _number_of_closed_slots; ++i) { - _closed_slots[i] = 1; - } - return 1; -}(); - -static inline bool _init_async_event_queue() { - if (!_async_queue) { - _async_queue = xQueueCreate(CONFIG_ASYNC_TCP_QUEUE_SIZE, sizeof(lwip_event_packet_t*)); - if (!_async_queue) { - return false; - } - } - return true; -} - -static inline bool _send_async_event(lwip_event_packet_t** e, TickType_t wait = portMAX_DELAY) { - return _async_queue && xQueueSend(_async_queue, e, wait) == pdPASS; -} - -static inline bool _prepend_async_event(lwip_event_packet_t** e, TickType_t wait = portMAX_DELAY) { - return _async_queue && xQueueSendToFront(_async_queue, e, wait) == pdPASS; -} - -static inline bool _get_async_event(lwip_event_packet_t** e) { - if (!_async_queue) { - return false; - } - -#if CONFIG_ASYNC_TCP_USE_WDT - // need to return periodically to feed the dog - if (xQueueReceive(_async_queue, e, pdMS_TO_TICKS(1000)) != pdPASS) - return false; -#else - if (xQueueReceive(_async_queue, e, portMAX_DELAY) != pdPASS) - return false; -#endif - - if ((*e)->event != LWIP_TCP_POLL) - return true; - - /* - Let's try to coalesce two (or more) consecutive poll events into one - this usually happens with poor implemented user-callbacks that are runs too long and makes poll events to stack in the queue - if consecutive user callback for a same connection runs longer that poll time then it will fill the queue with events until it deadlocks. - This is a workaround to mitigate such poor designs and won't let other events/connections to starve the task time. - It won't be effective if user would run multiple simultaneous long running callbacks due to message interleaving. - todo: implement some kind of fair dequeing or (better) simply punish user for a bad designed callbacks by resetting hog connections - */ - lwip_event_packet_t* next_pkt = NULL; - while (xQueuePeek(_async_queue, &next_pkt, 0) == pdPASS) { - if (next_pkt->arg == (*e)->arg && next_pkt->event == LWIP_TCP_POLL) { - if (xQueueReceive(_async_queue, &next_pkt, 0) == pdPASS) { - free(next_pkt); - next_pkt = NULL; - log_d("coalescing polls, network congestion or async callbacks might be too slow!"); - continue; - } - } - - // quit while loop if next event can't be discarded - break; - } - - /* - now we have to decide if to proceed with poll callback handler or discard it? - poor designed apps using asynctcp without proper dataflow control could flood the queue with interleaved pool/ack events. - I.e. on each poll app would try to generate more data to send, which in turn results in additional ack event triggering chain effect - for long connections. Or poll callback could take long time starving other connections. Anyway our goal is to keep the queue length - grows under control (if possible) and poll events are the safest to discard. - Let's discard poll events processing using linear-increasing probability curve when queue size grows over 3/4 - Poll events are periodic and connection could get another chance next time - */ - if (uxQueueMessagesWaiting(_async_queue) > (rand() % CONFIG_ASYNC_TCP_QUEUE_SIZE / 4 + CONFIG_ASYNC_TCP_QUEUE_SIZE * 3 / 4)) { - free(*e); - *e = NULL; - log_d("discarding poll due to queue congestion"); - // evict next event from a queue - return _get_async_event(e); - } - - // last resort return - return true; -} - -static bool _remove_events_with_arg(void* arg) { - if (!_async_queue) { - return false; - } - - lwip_event_packet_t* first_packet = NULL; - lwip_event_packet_t* packet = NULL; - - // figure out which is the first non-matching packet so we can keep the order - while (!first_packet) { - if (xQueueReceive(_async_queue, &first_packet, 0) != pdPASS) { - return false; - } - // discard packet if matching - if ((int)first_packet->arg == (int)arg) { - free(first_packet); - first_packet = NULL; - } else if (xQueueSend(_async_queue, &first_packet, 0) != pdPASS) { - // try to return first packet to the back of the queue - // we can't wait here if queue is full, because this call has been done from the only consumer task of this queue - // otherwise it would deadlock, we have to discard the event - free(first_packet); - first_packet = NULL; - return false; - } - } - - while (xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet) { - if (xQueueReceive(_async_queue, &packet, 0) != pdPASS) { - return false; - } - if ((int)packet->arg == (int)arg) { - // remove matching event - free(packet); - packet = NULL; - // otherwise try to requeue it - } else if (xQueueSend(_async_queue, &packet, 0) != pdPASS) { - // we can't wait here if queue is full, because this call has been done from the only consumer task of this queue - // otherwise it would deadlock, we have to discard the event - free(packet); - packet = NULL; - return false; - } - } - return true; -} - -static void _handle_async_event(lwip_event_packet_t* e) { - if (e->arg == NULL) { - // do nothing when arg is NULL - // ets_printf("event arg == NULL: 0x%08x\n", e->recv.pcb); - } else if (e->event == LWIP_TCP_CLEAR) { - _remove_events_with_arg(e->arg); - } else if (e->event == LWIP_TCP_RECV) { - // ets_printf("-R: 0x%08x\n", e->recv.pcb); - AsyncClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err); - } else if (e->event == LWIP_TCP_FIN) { - // ets_printf("-F: 0x%08x\n", e->fin.pcb); - AsyncClient::_s_fin(e->arg, e->fin.pcb, e->fin.err); - } else if (e->event == LWIP_TCP_SENT) { - // ets_printf("-S: 0x%08x\n", e->sent.pcb); - AsyncClient::_s_sent(e->arg, e->sent.pcb, e->sent.len); - } else if (e->event == LWIP_TCP_POLL) { - // ets_printf("-P: 0x%08x\n", e->poll.pcb); - AsyncClient::_s_poll(e->arg, e->poll.pcb); - } else if (e->event == LWIP_TCP_ERROR) { - // ets_printf("-E: 0x%08x %d\n", e->arg, e->error.err); - AsyncClient::_s_error(e->arg, e->error.err); - } else if (e->event == LWIP_TCP_CONNECTED) { - // ets_printf("C: 0x%08x 0x%08x %d\n", e->arg, e->connected.pcb, e->connected.err); - AsyncClient::_s_connected(e->arg, e->connected.pcb, e->connected.err); - } else if (e->event == LWIP_TCP_ACCEPT) { - // ets_printf("A: 0x%08x 0x%08x\n", e->arg, e->accept.client); - AsyncServer::_s_accepted(e->arg, e->accept.client); - } else if (e->event == LWIP_TCP_DNS) { - // ets_printf("D: 0x%08x %s = %s\n", e->arg, e->dns.name, ipaddr_ntoa(&e->dns.addr)); - AsyncClient::_s_dns_found(e->dns.name, &e->dns.addr, e->arg); - } - free((void*)(e)); -} - -static void _async_service_task(void* pvParameters) { -#if CONFIG_ASYNC_TCP_USE_WDT - if (esp_task_wdt_add(NULL) != ESP_OK) { - log_w("Failed to add async task to WDT"); - } -#endif - lwip_event_packet_t* packet = NULL; - for (;;) { - if (_get_async_event(&packet)) { - _handle_async_event(packet); - } -#if CONFIG_ASYNC_TCP_USE_WDT - esp_task_wdt_reset(); -#endif - } -#if CONFIG_ASYNC_TCP_USE_WDT - esp_task_wdt_delete(NULL); -#endif - vTaskDelete(NULL); - _async_service_task_handle = NULL; -} -/* -static void _stop_async_task(){ - if(_async_service_task_handle){ - vTaskDelete(_async_service_task_handle); - _async_service_task_handle = NULL; - } -} -*/ - -static bool customTaskCreateUniversal( - TaskFunction_t pxTaskCode, - const char* const pcName, - const uint32_t usStackDepth, - void* const pvParameters, - UBaseType_t uxPriority, - TaskHandle_t* const pxCreatedTask, - const BaseType_t xCoreID) { -#ifndef CONFIG_FREERTOS_UNICORE - if (xCoreID >= 0 && xCoreID < 2) { - return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID); - } else { -#endif - return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask); -#ifndef CONFIG_FREERTOS_UNICORE - } -#endif -} - -static bool _start_async_task() { - if (!_init_async_event_queue()) { - return false; - } - if (!_async_service_task_handle) { - customTaskCreateUniversal(_async_service_task, "async_tcp", CONFIG_ASYNC_TCP_STACK_SIZE, NULL, TASK_CONNECTIVITY_PRIO, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); - if (!_async_service_task_handle) { - return false; - } - } - return true; -} - -/* - * LwIP Callbacks - * */ - -static int8_t _tcp_clear_events(void* arg) { - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_CLEAR; - e->arg = arg; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_connected(void* arg, tcp_pcb* pcb, int8_t err) { - // ets_printf("+C: 0x%08x\n", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_CONNECTED; - e->arg = arg; - e->connected.pcb = pcb; - e->connected.err = err; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_poll(void* arg, struct tcp_pcb* pcb) { - // throttle polling events queing when event queue is getting filled up, let it handle _onack's - // log_d("qs:%u", uxQueueMessagesWaiting(_async_queue)); - if (uxQueueMessagesWaiting(_async_queue) > (rand() % CONFIG_ASYNC_TCP_QUEUE_SIZE / 2 + CONFIG_ASYNC_TCP_QUEUE_SIZE / 4)) { - log_d("throttling"); - return ERR_OK; - } - - // ets_printf("+P: 0x%08x\n", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_POLL; - e->arg = arg; - e->poll.pcb = pcb; - // poll events are not critical 'cause those are repetitive, so we may not wait the queue in any case - if (!_send_async_event(&e, 0)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* pb, int8_t err) { - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->arg = arg; - if (pb) { - // ets_printf("+R: 0x%08x\n", pcb); - e->event = LWIP_TCP_RECV; - e->recv.pcb = pcb; - e->recv.pb = pb; - e->recv.err = err; - } else { - // ets_printf("+F: 0x%08x\n", pcb); - e->event = LWIP_TCP_FIN; - e->fin.pcb = pcb; - e->fin.err = err; - // close the PCB in LwIP thread - AsyncClient::_s_lwip_fin(e->arg, e->fin.pcb, e->fin.err); - } - if (!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_sent(void* arg, struct tcp_pcb* pcb, uint16_t len) { - // ets_printf("+S: 0x%08x\n", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_SENT; - e->arg = arg; - e->sent.pcb = pcb; - e->sent.len = len; - if (!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static void _tcp_error(void* arg, int8_t err) { - // ets_printf("+E: 0x%08x\n", arg); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_ERROR; - e->arg = arg; - e->error.err = err; - if (!_send_async_event(&e)) { - free((void*)(e)); - } -} - -static void _tcp_dns_found(const char* name, struct ip_addr* ipaddr, void* arg) { - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - // ets_printf("+DNS: name=%s ipaddr=0x%08x arg=%x\n", name, ipaddr, arg); - e->event = LWIP_TCP_DNS; - e->arg = arg; - e->dns.name = name; - if (ipaddr) { - memcpy(&e->dns.addr, ipaddr, sizeof(struct ip_addr)); - } else { - memset(&e->dns.addr, 0, sizeof(e->dns.addr)); - } - if (!_send_async_event(&e)) { - free((void*)(e)); - } -} - -// Used to switch out from LwIP thread -static int8_t _tcp_accept(void* arg, AsyncClient* client) { - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_ACCEPT; - e->arg = arg; - e->accept.client = client; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -/* - * TCP/IP API Calls - * */ - -#include "lwip/priv/tcpip_priv.h" - -typedef struct { - struct tcpip_api_call_data call; - tcp_pcb* pcb; - int8_t closed_slot; - int8_t err; - union { - struct { - const char* data; - size_t size; - uint8_t apiflags; - } write; - size_t received; - struct { - ip_addr_t* addr; - uint16_t port; - tcp_connected_fn cb; - } connect; - struct { - ip_addr_t* addr; - uint16_t port; - } bind; - uint8_t backlog; - }; -} tcp_api_call_t; - -static err_t _tcp_output_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_output(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_output(tcp_pcb* pcb, int8_t closed_slot) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_write_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); - } - return msg->err; -} - -static esp_err_t _tcp_write(tcp_pcb* pcb, int8_t closed_slot, const char* data, size_t size, uint8_t apiflags) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.write.data = data; - msg.write.size = size; - msg.write.apiflags = apiflags; - tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_recved_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - // if(msg->closed_slot != INVALID_CLOSED_SLOT && !_closed_slots[msg->closed_slot]) { - // if(msg->closed_slot != INVALID_CLOSED_SLOT) { - msg->err = 0; - tcp_recved(msg->pcb, msg->received); - } - return msg->err; -} - -static esp_err_t _tcp_recved(tcp_pcb* pcb, int8_t closed_slot, size_t len) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.received = len; - tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_close_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_close(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_close(tcp_pcb* pcb, int8_t closed_slot) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_abort_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - tcp_abort(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_abort(tcp_pcb* pcb, int8_t closed_slot) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_connect_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); - return msg->err; -} - -static esp_err_t _tcp_connect(tcp_pcb* pcb, int8_t closed_slot, ip_addr_t* addr, uint16_t port, tcp_connected_fn cb) { - if (!pcb) { - return ESP_FAIL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.connect.addr = addr; - msg.connect.port = port; - msg.connect.cb = cb; - tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_bind_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); - return msg->err; -} - -static esp_err_t _tcp_bind(tcp_pcb* pcb, ip_addr_t* addr, uint16_t port) { - if (!pcb) { - return ESP_FAIL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = -1; - msg.bind.addr = addr; - msg.bind.port = port; - tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_listen_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = 0; - msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); - return msg->err; -} - -static tcp_pcb* _tcp_listen_with_backlog(tcp_pcb* pcb, uint8_t backlog) { - if (!pcb) { - return NULL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = -1; - msg.backlog = backlog ? backlog : 0xFF; - tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); - return msg.pcb; -} - -/* - Async TCP Client - */ - -AsyncClient::AsyncClient(tcp_pcb* pcb) - : _connect_cb(0), _connect_cb_arg(0), _discard_cb(0), _discard_cb_arg(0), _sent_cb(0), _sent_cb_arg(0), _error_cb(0), _error_cb_arg(0), _recv_cb(0), _recv_cb_arg(0), _pb_cb(0), _pb_cb_arg(0), _timeout_cb(0), _timeout_cb_arg(0), _ack_pcb(true), _tx_last_packet(0), _rx_timeout(0), _rx_last_ack(0), _ack_timeout(CONFIG_ASYNC_TCP_MAX_ACK_TIME), _connect_port(0), prev(NULL), next(NULL) { - _pcb = pcb; - _closed_slot = INVALID_CLOSED_SLOT; - if (_pcb) { - _rx_last_packet = millis(); - tcp_arg(_pcb, this); - tcp_recv(_pcb, &_tcp_recv); - tcp_sent(_pcb, &_tcp_sent); - tcp_err(_pcb, &_tcp_error); - tcp_poll(_pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); - if (!_allocate_closed_slot()) { - _close(); - } - } -} - -AsyncClient::~AsyncClient() { - if (_pcb) { - _close(); - } - _free_closed_slot(); -} - -/* - * Operators - * */ - -AsyncClient& AsyncClient::operator=(const AsyncClient& other) { - if (_pcb) { - _close(); - } - - _pcb = other._pcb; - _closed_slot = other._closed_slot; - if (_pcb) { - _rx_last_packet = millis(); - tcp_arg(_pcb, this); - tcp_recv(_pcb, &_tcp_recv); - tcp_sent(_pcb, &_tcp_sent); - tcp_err(_pcb, &_tcp_error); - tcp_poll(_pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); - } - return *this; -} - -bool AsyncClient::operator==(const AsyncClient& other) { - return _pcb == other._pcb; -} - -AsyncClient& AsyncClient::operator+=(const AsyncClient& other) { - if (next == NULL) { - next = (AsyncClient*)(&other); - next->prev = this; - } else { - AsyncClient* c = next; - while (c->next != NULL) { - c = c->next; - } - c->next = (AsyncClient*)(&other); - c->next->prev = c; - } - return *this; -} - -/* - * Callback Setters - * */ - -void AsyncClient::onConnect(AcConnectHandler cb, void* arg) { - _connect_cb = cb; - _connect_cb_arg = arg; -} - -void AsyncClient::onDisconnect(AcConnectHandler cb, void* arg) { - _discard_cb = cb; - _discard_cb_arg = arg; -} - -void AsyncClient::onAck(AcAckHandler cb, void* arg) { - _sent_cb = cb; - _sent_cb_arg = arg; -} - -void AsyncClient::onError(AcErrorHandler cb, void* arg) { - _error_cb = cb; - _error_cb_arg = arg; -} - -void AsyncClient::onData(AcDataHandler cb, void* arg) { - _recv_cb = cb; - _recv_cb_arg = arg; -} - -void AsyncClient::onPacket(AcPacketHandler cb, void* arg) { - _pb_cb = cb; - _pb_cb_arg = arg; -} - -void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg) { - _timeout_cb = cb; - _timeout_cb_arg = arg; -} - -void AsyncClient::onPoll(AcConnectHandler cb, void* arg) { - _poll_cb = cb; - _poll_cb_arg = arg; -} - -/* - * Main Public Methods - * */ - -bool AsyncClient::_connect(ip_addr_t addr, uint16_t port) { - if (_pcb) { - log_d("already connected, state %d", _pcb->state); - return false; - } - if (!_start_async_task()) { - log_e("failed to start task"); - return false; - } - - if (!_allocate_closed_slot()) { - log_e("failed to allocate: closed slot full"); - return false; - } - - TCP_MUTEX_LOCK(); - tcp_pcb* pcb = tcp_new_ip_type(addr.type); - if (!pcb) { - TCP_MUTEX_UNLOCK(); - log_e("pcb == NULL"); - return false; - } - tcp_arg(pcb, this); - tcp_err(pcb, &_tcp_error); - tcp_recv(pcb, &_tcp_recv); - tcp_sent(pcb, &_tcp_sent); - tcp_poll(pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); - TCP_MUTEX_UNLOCK(); - - esp_err_t err = _tcp_connect(pcb, _closed_slot, &addr, port, (tcp_connected_fn)&_tcp_connected); - return err == ESP_OK; -} - -bool AsyncClient::connect(const IPAddress& ip, uint16_t port) { - ip_addr_t addr; -#if ESP_IDF_VERSION_MAJOR < 5 - addr.u_addr.ip4.addr = ip; - addr.type = IPADDR_TYPE_V4; -#else - ip.to_ip_addr_t(&addr); -#endif - - return _connect(addr, port); -} - -#if LWIP_IPV6 && ESP_IDF_VERSION_MAJOR < 5 -bool AsyncClient::connect(const IPv6Address& ip, uint16_t port) { - auto ipaddr = static_cast(ip); - ip_addr_t addr = IPADDR6_INIT(ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - - return _connect(addr, port); -} -#endif - -bool AsyncClient::connect(const char* host, uint16_t port) { - ip_addr_t addr; - - if (!_start_async_task()) { - log_e("failed to start task"); - return false; - } - - TCP_MUTEX_LOCK(); - err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); - TCP_MUTEX_UNLOCK(); - if (err == ERR_OK) { -#if ESP_IDF_VERSION_MAJOR < 5 - #if LWIP_IPV6 - if (addr.type == IPADDR_TYPE_V6) { - return connect(IPv6Address(addr.u_addr.ip6.addr), port); - } - return connect(IPAddress(addr.u_addr.ip4.addr), port); - #else - return connect(IPAddress(addr.addr), port); - #endif -#else - return _connect(addr, port); -#endif - } else if (err == ERR_INPROGRESS) { - _connect_port = port; - return true; - } - log_d("error: %d", err); - return false; -} - -void AsyncClient::close(bool now) { - if (_pcb) { - _tcp_recved(_pcb, _closed_slot, _rx_ack_len); - } - _close(); -} - -int8_t AsyncClient::abort() { - if (_pcb) { - _tcp_abort(_pcb, _closed_slot); - _pcb = NULL; - } - return ERR_ABRT; -} - -size_t AsyncClient::space() { - if ((_pcb != NULL) && (_pcb->state == ESTABLISHED)) { - return tcp_sndbuf(_pcb); - } - return 0; -} - -size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { - if (!_pcb || size == 0 || data == NULL) { - return 0; - } - size_t room = space(); - if (!room) { - return 0; - } - size_t will_send = (room < size) ? room : size; - int8_t err = ERR_OK; - err = _tcp_write(_pcb, _closed_slot, data, will_send, apiflags); - if (err != ERR_OK) { - return 0; - } - return will_send; -} - -bool AsyncClient::send() { - auto backup = _tx_last_packet; - _tx_last_packet = millis(); - if (_tcp_output(_pcb, _closed_slot) == ERR_OK) { - return true; - } - _tx_last_packet = backup; - return false; -} - -size_t AsyncClient::ack(size_t len) { - if (len > _rx_ack_len) - len = _rx_ack_len; - if (len) { - _tcp_recved(_pcb, _closed_slot, len); - } - _rx_ack_len -= len; - return len; -} - -void AsyncClient::ackPacket(struct pbuf* pb) { - if (!pb) { - return; - } - _tcp_recved(_pcb, _closed_slot, pb->len); - pbuf_free(pb); -} - -/* - * Main Private Methods - * */ - -int8_t AsyncClient::_close() { - // ets_printf("X: 0x%08x\n", (uint32_t)this); - int8_t err = ERR_OK; - if (_pcb) { - TCP_MUTEX_LOCK(); - tcp_arg(_pcb, NULL); - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - TCP_MUTEX_UNLOCK(); - _tcp_clear_events(this); - err = _tcp_close(_pcb, _closed_slot); - if (err != ERR_OK) { - err = abort(); - } - _free_closed_slot(); - _pcb = NULL; - if (_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - } - return err; -} - -bool AsyncClient::_allocate_closed_slot() { - if (_closed_slot != INVALID_CLOSED_SLOT) { - return true; - } - xSemaphoreTake(_slots_lock, portMAX_DELAY); - uint32_t closed_slot_min_index = 0; - for (int i = 0; i < _number_of_closed_slots; ++i) { - if ((_closed_slot == INVALID_CLOSED_SLOT || _closed_slots[i] <= closed_slot_min_index) && _closed_slots[i] != 0) { - closed_slot_min_index = _closed_slots[i]; - _closed_slot = i; - } - } - if (_closed_slot != INVALID_CLOSED_SLOT) { - _closed_slots[_closed_slot] = 0; - } - xSemaphoreGive(_slots_lock); - return (_closed_slot != INVALID_CLOSED_SLOT); -} - -void AsyncClient::_free_closed_slot() { - xSemaphoreTake(_slots_lock, portMAX_DELAY); - if (_closed_slot != INVALID_CLOSED_SLOT) { - _closed_slots[_closed_slot] = _closed_index; - _closed_slot = INVALID_CLOSED_SLOT; - ++_closed_index; - } - xSemaphoreGive(_slots_lock); -} - -/* - * Private Callbacks - * */ - -int8_t AsyncClient::_connected(tcp_pcb* pcb, int8_t err) { - _pcb = reinterpret_cast(pcb); - if (_pcb) { - _rx_last_packet = millis(); - } - if (_connect_cb) { - _connect_cb(_connect_cb_arg, this); - } - return ERR_OK; -} - -void AsyncClient::_error(int8_t err) { - if (_pcb) { - TCP_MUTEX_LOCK(); - tcp_arg(_pcb, NULL); - if (_pcb->state == LISTEN) { - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - } - TCP_MUTEX_UNLOCK(); - _free_closed_slot(); - _pcb = NULL; - } - if (_error_cb) { - _error_cb(_error_cb_arg, this, err); - } - if (_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } -} - -// In LwIP Thread -int8_t AsyncClient::_lwip_fin(tcp_pcb* pcb, int8_t err) { - if (!_pcb || pcb != _pcb) { - log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - return ERR_OK; - } - tcp_arg(_pcb, NULL); - if (_pcb->state == LISTEN) { - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - } - if (tcp_close(_pcb) != ERR_OK) { - tcp_abort(_pcb); - } - _free_closed_slot(); - _pcb = NULL; - return ERR_OK; -} - -// In Async Thread -int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) { - _tcp_clear_events(this); - if (_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - return ERR_OK; -} - -int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { - _rx_last_ack = _rx_last_packet = millis(); - if (_sent_cb) { - _sent_cb(_sent_cb_arg, this, len, (_rx_last_packet - _tx_last_packet)); - } - return ERR_OK; -} - -int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { - while (pb != NULL) { - _rx_last_packet = millis(); - // we should not ack before we assimilate the data - _ack_pcb = true; - pbuf* b = pb; - pb = b->next; - b->next = NULL; - if (_pb_cb) { - _pb_cb(_pb_cb_arg, this, b); - } else { - if (_recv_cb) { - _recv_cb(_recv_cb_arg, this, b->payload, b->len); - } - if (!_ack_pcb) { - _rx_ack_len += b->len; - } else if (_pcb) { - _tcp_recved(_pcb, _closed_slot, b->len); - } - } - pbuf_free(b); - } - return ERR_OK; -} - -int8_t AsyncClient::_poll(tcp_pcb* pcb) { - if (!_pcb) { - // log_d("pcb is NULL"); - return ERR_OK; - } - if (pcb != _pcb) { - log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - return ERR_OK; - } - - uint32_t now = millis(); - - // ACK Timeout - if (_ack_timeout) { - const uint32_t one_day = 86400000; - bool last_tx_is_after_last_ack = (_rx_last_ack - _tx_last_packet + one_day) < one_day; - if (last_tx_is_after_last_ack && (now - _tx_last_packet) >= _ack_timeout) { - log_d("ack timeout %d", pcb->state); - if (_timeout_cb) - _timeout_cb(_timeout_cb_arg, this, (now - _tx_last_packet)); - return ERR_OK; - } - } - // RX Timeout - if (_rx_timeout && (now - _rx_last_packet) >= (_rx_timeout * 1000)) { - log_d("rx timeout %d", pcb->state); - _close(); - return ERR_OK; - } - // Everything is fine - if (_poll_cb) { - _poll_cb(_poll_cb_arg, this); - } - return ERR_OK; -} - -void AsyncClient::_dns_found(struct ip_addr* ipaddr) { -#if ESP_IDF_VERSION_MAJOR < 5 - if (ipaddr && IP_IS_V4(ipaddr)) { - connect(IPAddress(ip_addr_get_ip4_u32(ipaddr)), _connect_port); - #if LWIP_IPV6 - } else if (ipaddr && ipaddr->u_addr.ip6.addr) { - connect(IPv6Address(ipaddr->u_addr.ip6.addr), _connect_port); - #endif -#else - if (ipaddr) { - IPAddress ip; - ip.from_ip_addr_t(ipaddr); - connect(ip, _connect_port); -#endif - } else { - if (_error_cb) { - _error_cb(_error_cb_arg, this, -55); - } - if (_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - } -} - -/* - * Public Helper Methods - * */ - -bool AsyncClient::free() { - if (!_pcb) { - return true; - } - if (_pcb->state == CLOSED || _pcb->state > ESTABLISHED) { - return true; - } - return false; -} - -size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) { - size_t will_send = add(data, size, apiflags); - if (!will_send || !send()) { - return 0; - } - return will_send; -} - -void AsyncClient::setRxTimeout(uint32_t timeout) { - _rx_timeout = timeout; -} - -uint32_t AsyncClient::getRxTimeout() { - return _rx_timeout; -} - -uint32_t AsyncClient::getAckTimeout() { - return _ack_timeout; -} - -void AsyncClient::setAckTimeout(uint32_t timeout) { - _ack_timeout = timeout; -} - -void AsyncClient::setNoDelay(bool nodelay) { - if (!_pcb) { - return; - } - if (nodelay) { - tcp_nagle_disable(_pcb); - } else { - tcp_nagle_enable(_pcb); - } -} - -bool AsyncClient::getNoDelay() { - if (!_pcb) { - return false; - } - return tcp_nagle_disabled(_pcb); -} - -void AsyncClient::setKeepAlive(uint32_t ms, uint8_t cnt) { - if (ms != 0) { - _pcb->so_options |= SOF_KEEPALIVE; // Turn on TCP Keepalive for the given pcb - // Set the time between keepalive messages in milli-seconds - _pcb->keep_idle = ms; - _pcb->keep_intvl = ms; - _pcb->keep_cnt = cnt; // The number of unanswered probes required to force closure of the socket - } else { - _pcb->so_options &= ~SOF_KEEPALIVE; // Turn off TCP Keepalive for the given pcb - } -} - -uint16_t AsyncClient::getMss() { - if (!_pcb) { - return 0; - } - return tcp_mss(_pcb); -} - -uint32_t AsyncClient::getRemoteAddress() { - if (!_pcb) { - return 0; - } -#if LWIP_IPV4 && LWIP_IPV6 - return _pcb->remote_ip.u_addr.ip4.addr; -#else - return _pcb->remote_ip.addr; -#endif -} - -#if LWIP_IPV6 -ip6_addr_t AsyncClient::getRemoteAddress6() { - if (!_pcb) { - ip6_addr_t nulladdr; - ip6_addr_set_zero(&nulladdr); - return nulladdr; - } - return _pcb->remote_ip.u_addr.ip6; -} - -ip6_addr_t AsyncClient::getLocalAddress6() { - if (!_pcb) { - ip6_addr_t nulladdr; - ip6_addr_set_zero(&nulladdr); - return nulladdr; - } - return _pcb->local_ip.u_addr.ip6; -} - #if ESP_IDF_VERSION_MAJOR < 5 -IPv6Address AsyncClient::remoteIP6() { - return IPv6Address(getRemoteAddress6().addr); -} - -IPv6Address AsyncClient::localIP6() { - return IPv6Address(getLocalAddress6().addr); -} - #else -IPAddress AsyncClient::remoteIP6() { - if (!_pcb) { - return IPAddress(IPType::IPv6); - } - IPAddress ip; - ip.from_ip_addr_t(&(_pcb->remote_ip)); - return ip; -} - -IPAddress AsyncClient::localIP6() { - if (!_pcb) { - return IPAddress(IPType::IPv6); - } - IPAddress ip; - ip.from_ip_addr_t(&(_pcb->local_ip)); - return ip; -} - #endif -#endif - -uint16_t AsyncClient::getRemotePort() { - if (!_pcb) { - return 0; - } - return _pcb->remote_port; -} - -uint32_t AsyncClient::getLocalAddress() { - if (!_pcb) { - return 0; - } -#if LWIP_IPV4 && LWIP_IPV6 - return _pcb->local_ip.u_addr.ip4.addr; -#else - return _pcb->local_ip.addr; -#endif -} - -uint16_t AsyncClient::getLocalPort() { - if (!_pcb) { - return 0; - } - return _pcb->local_port; -} - -IPAddress AsyncClient::remoteIP() { -#if ESP_IDF_VERSION_MAJOR < 5 - return IPAddress(getRemoteAddress()); -#else - if (!_pcb) { - return IPAddress(); - } - IPAddress ip; - ip.from_ip_addr_t(&(_pcb->remote_ip)); - return ip; -#endif -} - -uint16_t AsyncClient::remotePort() { - return getRemotePort(); -} - -IPAddress AsyncClient::localIP() { -#if ESP_IDF_VERSION_MAJOR < 5 - return IPAddress(getLocalAddress()); -#else - if (!_pcb) { - return IPAddress(); - } - IPAddress ip; - ip.from_ip_addr_t(&(_pcb->local_ip)); - return ip; -#endif -} - -uint16_t AsyncClient::localPort() { - return getLocalPort(); -} - -uint8_t AsyncClient::state() { - if (!_pcb) { - return 0; - } - return _pcb->state; -} - -bool AsyncClient::connected() { - if (!_pcb) { - return false; - } - return _pcb->state == ESTABLISHED; -} - -bool AsyncClient::connecting() { - if (!_pcb) { - return false; - } - return _pcb->state > CLOSED && _pcb->state < ESTABLISHED; -} - -bool AsyncClient::disconnecting() { - if (!_pcb) { - return false; - } - return _pcb->state > ESTABLISHED && _pcb->state < TIME_WAIT; -} - -bool AsyncClient::disconnected() { - if (!_pcb) { - return true; - } - return _pcb->state == CLOSED || _pcb->state == TIME_WAIT; -} - -bool AsyncClient::freeable() { - if (!_pcb) { - return true; - } - return _pcb->state == CLOSED || _pcb->state > ESTABLISHED; -} - -bool AsyncClient::canSend() { - return space() > 0; -} - -const char* AsyncClient::errorToString(int8_t error) { - switch (error) { - case ERR_OK: - return "OK"; - case ERR_MEM: - return "Out of memory error"; - case ERR_BUF: - return "Buffer error"; - case ERR_TIMEOUT: - return "Timeout"; - case ERR_RTE: - return "Routing problem"; - case ERR_INPROGRESS: - return "Operation in progress"; - case ERR_VAL: - return "Illegal value"; - case ERR_WOULDBLOCK: - return "Operation would block"; - case ERR_USE: - return "Address in use"; - case ERR_ALREADY: - return "Already connected"; - case ERR_CONN: - return "Not connected"; - case ERR_IF: - return "Low-level netif error"; - case ERR_ABRT: - return "Connection aborted"; - case ERR_RST: - return "Connection reset"; - case ERR_CLSD: - return "Connection closed"; - case ERR_ARG: - return "Illegal argument"; - case -55: - return "DNS failed"; - default: - return "UNKNOWN"; - } -} - -const char* AsyncClient::stateToString() { - switch (state()) { - case 0: - return "Closed"; - case 1: - return "Listen"; - case 2: - return "SYN Sent"; - case 3: - return "SYN Received"; - case 4: - return "Established"; - case 5: - return "FIN Wait 1"; - case 6: - return "FIN Wait 2"; - case 7: - return "Close Wait"; - case 8: - return "Closing"; - case 9: - return "Last ACK"; - case 10: - return "Time Wait"; - default: - return "UNKNOWN"; - } -} - -/* - * Static Callbacks (LwIP C2C++ interconnect) - * */ - -void AsyncClient::_s_dns_found(const char* name, struct ip_addr* ipaddr, void* arg) { - reinterpret_cast(arg)->_dns_found(ipaddr); -} - -int8_t AsyncClient::_s_poll(void* arg, struct tcp_pcb* pcb) { - return reinterpret_cast(arg)->_poll(pcb); -} - -int8_t AsyncClient::_s_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* pb, int8_t err) { - return reinterpret_cast(arg)->_recv(pcb, pb, err); -} - -int8_t AsyncClient::_s_fin(void* arg, struct tcp_pcb* pcb, int8_t err) { - return reinterpret_cast(arg)->_fin(pcb, err); -} - -int8_t AsyncClient::_s_lwip_fin(void* arg, struct tcp_pcb* pcb, int8_t err) { - return reinterpret_cast(arg)->_lwip_fin(pcb, err); -} - -int8_t AsyncClient::_s_sent(void* arg, struct tcp_pcb* pcb, uint16_t len) { - return reinterpret_cast(arg)->_sent(pcb, len); -} - -void AsyncClient::_s_error(void* arg, int8_t err) { - reinterpret_cast(arg)->_error(err); -} - -int8_t AsyncClient::_s_connected(void* arg, struct tcp_pcb* pcb, int8_t err) { - return reinterpret_cast(arg)->_connected(pcb, err); -} - -/* - Async TCP Server - */ - -AsyncServer::AsyncServer(IPAddress addr, uint16_t port) - : _port(port) -#if ESP_IDF_VERSION_MAJOR < 5 - , - _bind4(true), _bind6(false) -#else - , - _bind4(addr.type() != IPType::IPv6), _bind6(addr.type() == IPType::IPv6) -#endif - , - _addr(addr), _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) { -} - -#if ESP_IDF_VERSION_MAJOR < 5 -AsyncServer::AsyncServer(IPv6Address addr, uint16_t port) - : _port(port), _bind4(false), _bind6(true), _addr6(addr), _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) {} -#endif - -AsyncServer::AsyncServer(uint16_t port) - : _port(port), _bind4(true), _bind6(false), _addr((uint32_t)IPADDR_ANY) -#if ESP_IDF_VERSION_MAJOR < 5 - , - _addr6() -#endif - , - _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) { -} - -AsyncServer::~AsyncServer() { - end(); -} - -void AsyncServer::onClient(AcConnectHandler cb, void* arg) { - _connect_cb = cb; - _connect_cb_arg = arg; -} - -void AsyncServer::begin() { - if (_pcb) { - return; - } - - if (!_start_async_task()) { - log_e("failed to start task"); - return; - } - int8_t err; - TCP_MUTEX_LOCK(); - _pcb = tcp_new_ip_type(_bind4 && _bind6 ? IPADDR_TYPE_ANY : (_bind6 ? IPADDR_TYPE_V6 : IPADDR_TYPE_V4)); - TCP_MUTEX_UNLOCK(); - if (!_pcb) { - log_e("_pcb == NULL"); - return; - } - - ip_addr_t local_addr; -#if ESP_IDF_VERSION_MAJOR < 5 - if (_bind6) { // _bind6 && _bind4 both at the same time is not supported on Arduino 2 in this lib API - local_addr.type = IPADDR_TYPE_V6; - memcpy(local_addr.u_addr.ip6.addr, static_cast(_addr6), sizeof(uint32_t) * 4); - } else { - local_addr.type = IPADDR_TYPE_V4; - local_addr.u_addr.ip4.addr = _addr; - } -#else - _addr.to_ip_addr_t(&local_addr); -#endif - err = _tcp_bind(_pcb, &local_addr, _port); - - if (err != ERR_OK) { - _tcp_close(_pcb, -1); - log_e("bind error: %d", err); - return; - } - - static uint8_t backlog = 5; - _pcb = _tcp_listen_with_backlog(_pcb, backlog); - if (!_pcb) { - log_e("listen_pcb == NULL"); - return; - } - TCP_MUTEX_LOCK(); - tcp_arg(_pcb, (void*)this); - tcp_accept(_pcb, &_s_accept); - TCP_MUTEX_UNLOCK(); -} - -void AsyncServer::end() { - if (_pcb) { - TCP_MUTEX_LOCK(); - tcp_arg(_pcb, NULL); - tcp_accept(_pcb, NULL); - if (tcp_close(_pcb) != ERR_OK) { - TCP_MUTEX_UNLOCK(); - _tcp_abort(_pcb, -1); - } else { - TCP_MUTEX_UNLOCK(); - } - _pcb = NULL; - } -} - -// runs on LwIP thread -int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err) { - // ets_printf("+A: 0x%08x\n", pcb); - if (_connect_cb) { - AsyncClient* c = new AsyncClient(pcb); - if (c) { - c->setNoDelay(_noDelay); - return _tcp_accept(this, c); - } - } - if (tcp_close(pcb) != ERR_OK) { - tcp_abort(pcb); - } - log_d("FAIL"); - return ERR_OK; -} - -int8_t AsyncServer::_accepted(AsyncClient* client) { - if (_connect_cb) { - _connect_cb(_connect_cb_arg, client); - } - return ERR_OK; -} - -void AsyncServer::setNoDelay(bool nodelay) { - _noDelay = nodelay; -} - -bool AsyncServer::getNoDelay() { - return _noDelay; -} - -uint8_t AsyncServer::status() { - if (!_pcb) { - return 0; - } - return _pcb->state; -} - -int8_t AsyncServer::_s_accept(void* arg, tcp_pcb* pcb, int8_t err) { - return reinterpret_cast(arg)->_accept(pcb, err); -} - -int8_t AsyncServer::_s_accepted(void* arg, AsyncClient* client) { - return reinterpret_cast(arg)->_accepted(client); -} diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h b/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h deleted file mode 100644 index c909d0518..000000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h +++ /dev/null @@ -1,347 +0,0 @@ -/* - Asynchronous TCP library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef ASYNCTCP_H_ -#define ASYNCTCP_H_ - -#define ASYNCTCP_VERSION "3.3.1" -#define ASYNCTCP_VERSION_MAJOR 3 -#define ASYNCTCP_VERSION_MINOR 3 -#define ASYNCTCP_VERSION_REVISION 1 -#define ASYNCTCP_FORK_mathieucarbou - -#include "../../../devboard/hal/hal.h" -#include "../../../system_settings.h" - -#include "IPAddress.h" -#if ESP_IDF_VERSION_MAJOR < 5 - #include "IPv6Address.h" -#endif -#include "lwip/ip6_addr.h" -#include "lwip/ip_addr.h" -#include - -#ifndef LIBRETINY - #include "sdkconfig.h" -extern "C" { - #include "freertos/semphr.h" - #include "lwip/pbuf.h" -} -#else -extern "C" { - #include - #include -} - #define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE -#endif - -// If core is not defined, then we are running in Arduino or PIO -#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE - #define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE -#endif - -// guard AsyncTCP task with watchdog -#ifndef CONFIG_ASYNC_TCP_USE_WDT - #define CONFIG_ASYNC_TCP_USE_WDT 0 -#endif - -#ifndef CONFIG_ASYNC_TCP_STACK_SIZE - #define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2 -#endif - -#ifndef CONFIG_ASYNC_TCP_PRIORITY - #define CONFIG_ASYNC_TCP_PRIORITY 10 -#endif - -#ifndef CONFIG_ASYNC_TCP_QUEUE_SIZE - #define CONFIG_ASYNC_TCP_QUEUE_SIZE 64 -#endif - -#ifndef CONFIG_ASYNC_TCP_MAX_ACK_TIME - #define CONFIG_ASYNC_TCP_MAX_ACK_TIME 5000 -#endif - -class AsyncClient; - -#define ASYNC_WRITE_FLAG_COPY 0x01 // will allocate new buffer to hold the data while sending (else will hold reference to the data given) -#define ASYNC_WRITE_FLAG_MORE 0x02 // will not send PSH flag, meaning that there should be more data to be sent before the application should react. - -typedef std::function AcConnectHandler; -typedef std::function AcAckHandler; -typedef std::function AcErrorHandler; -typedef std::function AcDataHandler; -typedef std::function AcPacketHandler; -typedef std::function AcTimeoutHandler; - -struct tcp_pcb; -struct ip_addr; - -class AsyncClient { - public: - AsyncClient(tcp_pcb* pcb = 0); - ~AsyncClient(); - - AsyncClient& operator=(const AsyncClient& other); - AsyncClient& operator+=(const AsyncClient& other); - - bool operator==(const AsyncClient& other); - - bool operator!=(const AsyncClient& other) { - return !(*this == other); - } - bool connect(const IPAddress& ip, uint16_t port); -#if ESP_IDF_VERSION_MAJOR < 5 - bool connect(const IPv6Address& ip, uint16_t port); -#endif - bool connect(const char* host, uint16_t port); - /** - * @brief close connection - * - * @param now - ignored - */ - void close(bool now = false); - // same as close() - void stop() { close(false); }; - int8_t abort(); - bool free(); - - // ack is not pending - bool canSend(); - // TCP buffer space available - size_t space(); - - /** - * @brief add data to be send (but do not send yet) - * @note add() would call lwip's tcp_write() - By default apiflags=ASYNC_WRITE_FLAG_COPY - You could try to use apiflags with this flag unset to pass data by reference and avoid copy to socket buffer, - but looks like it does not work for Arduino's lwip in ESP32/IDF at least - it is enforced in https://github.com/espressif/esp-lwip/blob/0606eed9d8b98a797514fdf6eabb4daf1c8c8cd9/src/core/tcp_out.c#L422C5-L422C30 - if LWIP_NETIF_TX_SINGLE_PBUF is set, and it is set indeed in IDF - https://github.com/espressif/esp-idf/blob/a0f798cfc4bbd624aab52b2c194d219e242d80c1/components/lwip/port/include/lwipopts.h#L744 - * - * @param data - * @param size - * @param apiflags - * @return size_t amount of data that has been copied - */ - size_t add(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); - - /** - * @brief send data previously add()'ed - * - * @return true on success - * @return false on error - */ - bool send(); - - /** - * @brief add and enqueue data for sending - * @note it is same as add() + send() - * @note only make sense when canSend() == true - * - * @param data - * @param size - * @param apiflags - * @return size_t - */ - size_t write(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); - - /** - * @brief add and enque data for sending - * @note treats data as null-terminated string - * - * @param data - * @return size_t - */ - size_t write(const char* data) { return data == NULL ? 0 : write(data, strlen(data)); }; - - uint8_t state(); - bool connecting(); - bool connected(); - bool disconnecting(); - bool disconnected(); - - // disconnected or disconnecting - bool freeable(); - - uint16_t getMss(); - - uint32_t getRxTimeout(); - // no RX data timeout for the connection in seconds - void setRxTimeout(uint32_t timeout); - - uint32_t getAckTimeout(); - // no ACK timeout for the last sent packet in milliseconds - void setAckTimeout(uint32_t timeout); - - void setNoDelay(bool nodelay); - bool getNoDelay(); - - void setKeepAlive(uint32_t ms, uint8_t cnt); - - uint32_t getRemoteAddress(); - uint16_t getRemotePort(); - uint32_t getLocalAddress(); - uint16_t getLocalPort(); -#if LWIP_IPV6 - ip6_addr_t getRemoteAddress6(); - ip6_addr_t getLocalAddress6(); - #if ESP_IDF_VERSION_MAJOR < 5 - IPv6Address remoteIP6(); - IPv6Address localIP6(); - #else - IPAddress remoteIP6(); - IPAddress localIP6(); - #endif -#endif - - // compatibility - IPAddress remoteIP(); - uint16_t remotePort(); - IPAddress localIP(); - uint16_t localPort(); - - // set callback - on successful connect - void onConnect(AcConnectHandler cb, void* arg = 0); - // set callback - disconnected - void onDisconnect(AcConnectHandler cb, void* arg = 0); - // set callback - ack received - void onAck(AcAckHandler cb, void* arg = 0); - // set callback - unsuccessful connect or error - void onError(AcErrorHandler cb, void* arg = 0); - // set callback - data received (called if onPacket is not used) - void onData(AcDataHandler cb, void* arg = 0); - // set callback - data received - void onPacket(AcPacketHandler cb, void* arg = 0); - // set callback - ack timeout - void onTimeout(AcTimeoutHandler cb, void* arg = 0); - // set callback - every 125ms when connected - void onPoll(AcConnectHandler cb, void* arg = 0); - - // ack pbuf from onPacket - void ackPacket(struct pbuf* pb); - // ack data that you have not acked using the method below - size_t ack(size_t len); - // will not ack the current packet. Call from onData - void ackLater() { _ack_pcb = false; } - - static const char* errorToString(int8_t error); - const char* stateToString(); - - // internal callbacks - Do NOT call any of the functions below in user code! - static int8_t _s_poll(void* arg, struct tcp_pcb* tpcb); - static int8_t _s_recv(void* arg, struct tcp_pcb* tpcb, struct pbuf* pb, int8_t err); - static int8_t _s_fin(void* arg, struct tcp_pcb* tpcb, int8_t err); - static int8_t _s_lwip_fin(void* arg, struct tcp_pcb* tpcb, int8_t err); - static void _s_error(void* arg, int8_t err); - static int8_t _s_sent(void* arg, struct tcp_pcb* tpcb, uint16_t len); - static int8_t _s_connected(void* arg, struct tcp_pcb* tpcb, int8_t err); - static void _s_dns_found(const char* name, struct ip_addr* ipaddr, void* arg); - - int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); - tcp_pcb* pcb() { return _pcb; } - - protected: - bool _connect(ip_addr_t addr, uint16_t port); - - tcp_pcb* _pcb; - int8_t _closed_slot; - - AcConnectHandler _connect_cb; - void* _connect_cb_arg; - AcConnectHandler _discard_cb; - void* _discard_cb_arg; - AcAckHandler _sent_cb; - void* _sent_cb_arg; - AcErrorHandler _error_cb; - void* _error_cb_arg; - AcDataHandler _recv_cb; - void* _recv_cb_arg; - AcPacketHandler _pb_cb; - void* _pb_cb_arg; - AcTimeoutHandler _timeout_cb; - void* _timeout_cb_arg; - AcConnectHandler _poll_cb; - void* _poll_cb_arg; - - bool _ack_pcb; - uint32_t _tx_last_packet; - uint32_t _rx_ack_len; - uint32_t _rx_last_packet; - uint32_t _rx_timeout; - uint32_t _rx_last_ack; - uint32_t _ack_timeout; - uint16_t _connect_port; - - int8_t _close(); - void _free_closed_slot(); - bool _allocate_closed_slot(); - int8_t _connected(tcp_pcb* pcb, int8_t err); - void _error(int8_t err); - int8_t _poll(tcp_pcb* pcb); - int8_t _sent(tcp_pcb* pcb, uint16_t len); - int8_t _fin(tcp_pcb* pcb, int8_t err); - int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); - void _dns_found(struct ip_addr* ipaddr); - - public: - AsyncClient* prev; - AsyncClient* next; -}; - -class AsyncServer { - public: - AsyncServer(IPAddress addr, uint16_t port); -#if ESP_IDF_VERSION_MAJOR < 5 - AsyncServer(IPv6Address addr, uint16_t port); -#endif - AsyncServer(uint16_t port); - ~AsyncServer(); - void onClient(AcConnectHandler cb, void* arg); - void begin(); - void end(); - void setNoDelay(bool nodelay); - bool getNoDelay(); - uint8_t status(); - - // Do not use any of the functions below! - static int8_t _s_accept(void* arg, tcp_pcb* newpcb, int8_t err); - static int8_t _s_accepted(void* arg, AsyncClient* client); - - protected: - uint16_t _port; - bool _bind4 = false; - bool _bind6 = false; - IPAddress _addr; -#if ESP_IDF_VERSION_MAJOR < 5 - IPv6Address _addr6; -#endif - bool _noDelay; - tcp_pcb* _pcb; - AcConnectHandler _connect_cb; - void* _connect_cb_arg; - - int8_t _accept(tcp_pcb* newpcb, int8_t err); - int8_t _accepted(AsyncClient* client); -}; - -#endif /* ASYNCTCP_H_ */ diff --git a/Software/src/lib/me-no-dev-AsyncTCP/.gitignore b/Software/src/lib/me-no-dev-AsyncTCP/.gitignore new file mode 100644 index 000000000..9bea4330f --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/.gitignore @@ -0,0 +1,2 @@ + +.DS_Store diff --git a/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml b/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml new file mode 100644 index 000000000..dbfc064af --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml @@ -0,0 +1,34 @@ +sudo: false +language: python +os: + - linux + +git: + depth: false + +stages: + - build + +jobs: + include: + + - name: "Arduino Build" + if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) + stage: build + script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh + + - name: "PlatformIO Build" + if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) + stage: build + script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 1 1 + +notifications: + email: + on_success: change + on_failure: change + webhooks: + urls: + - https://webhooks.gitter.im/e/60e65d0c78ea0a920347 + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/CMakeLists.txt b/Software/src/lib/me-no-dev-AsyncTCP/CMakeLists.txt similarity index 100% rename from Software/src/lib/mathieucarbou-AsyncTCP/CMakeLists.txt rename to Software/src/lib/me-no-dev-AsyncTCP/CMakeLists.txt diff --git a/Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild b/Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild new file mode 100644 index 000000000..177492645 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild @@ -0,0 +1,30 @@ +menu "AsyncTCP Configuration" + +choice ASYNC_TCP_RUNNING_CORE + bool "Core on which AsyncTCP's thread is running" + default ASYNC_TCP_RUN_CORE1 + help + Select on which core AsyncTCP is running + + config ASYNC_TCP_RUN_CORE0 + bool "CORE 0" + config ASYNC_TCP_RUN_CORE1 + bool "CORE 1" + config ASYNC_TCP_RUN_NO_AFFINITY + bool "BOTH" + +endchoice + +config ASYNC_TCP_RUNNING_CORE + int + default 0 if ASYNC_TCP_RUN_CORE0 + default 1 if ASYNC_TCP_RUN_CORE1 + default -1 if ASYNC_TCP_RUN_NO_AFFINITY + +config ASYNC_TCP_USE_WDT + bool "Enable WDT for the AsyncTCP task" + default "y" + help + Enable WDT for the AsyncTCP task, so it will trigger if a handler is locking the thread. + +endmenu diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/LICENSE b/Software/src/lib/me-no-dev-AsyncTCP/LICENSE similarity index 100% rename from Software/src/lib/mathieucarbou-AsyncTCP/LICENSE rename to Software/src/lib/me-no-dev-AsyncTCP/LICENSE diff --git a/Software/src/lib/me-no-dev-AsyncTCP/README.md b/Software/src/lib/me-no-dev-AsyncTCP/README.md new file mode 100644 index 000000000..79ffa9ef5 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/README.md @@ -0,0 +1,15 @@ +This is commit ca8ac5f from https://github.com/me-no-dev/AsyncTCP + +# AsyncTCP +[![Build Status](https://travis-ci.org/me-no-dev/AsyncTCP.svg?branch=master)](https://travis-ci.org/me-no-dev/AsyncTCP) ![](https://github.com/me-no-dev/AsyncTCP/workflows/Async%20TCP%20CI/badge.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2f7e4d1df8b446d192cbfec6dc174d2d)](https://www.codacy.com/manual/me-no-dev/AsyncTCP?utm_source=github.com&utm_medium=referral&utm_content=me-no-dev/AsyncTCP&utm_campaign=Badge_Grade) + +### Async TCP Library for ESP32 Arduino + +[![Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer](https://badges.gitter.im/me-no-dev/ESPAsyncWebServer.svg)](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs. + +This library is the base for [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) + +## AsyncClient and AsyncServer +The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/component.mk b/Software/src/lib/me-no-dev-AsyncTCP/component.mk similarity index 100% rename from Software/src/lib/mathieucarbou-AsyncTCP/component.mk rename to Software/src/lib/me-no-dev-AsyncTCP/component.mk diff --git a/Software/src/lib/me-no-dev-AsyncTCP/library.json b/Software/src/lib/me-no-dev-AsyncTCP/library.json new file mode 100644 index 000000000..89f90e4ec --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/library.json @@ -0,0 +1,22 @@ +{ + "name":"AsyncTCP", + "description":"Asynchronous TCP Library for ESP32", + "keywords":"async,tcp", + "authors": + { + "name": "Hristo Gochkov", + "maintainer": true + }, + "repository": + { + "type": "git", + "url": "https://github.com/me-no-dev/AsyncTCP.git" + }, + "version": "1.1.1", + "license": "LGPL-3.0", + "frameworks": "arduino", + "platforms": "espressif32", + "build": { + "libCompatMode": 2 + } +} diff --git a/Software/src/lib/me-no-dev-AsyncTCP/library.properties b/Software/src/lib/me-no-dev-AsyncTCP/library.properties new file mode 100644 index 000000000..eb4e26e90 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/library.properties @@ -0,0 +1,9 @@ +name=AsyncTCP +version=1.1.1 +author=Me-No-Dev +maintainer=Me-No-Dev +sentence=Async TCP Library for ESP32 +paragraph=Async TCP Library for ESP32 +category=Other +url=https://github.com/me-no-dev/AsyncTCP +architectures=* diff --git a/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp new file mode 100644 index 000000000..acd89639c --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp @@ -0,0 +1,1387 @@ +/* + Asynchronous TCP library for Espressif MCUs + + Copyright (c) 2016 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "Arduino.h" + +#include "AsyncTCP.h" +extern "C"{ +#include "lwip/opt.h" +#include "lwip/tcp.h" +#include "lwip/inet.h" +#include "lwip/dns.h" +#include "lwip/err.h" +} +#include "esp_task_wdt.h" + +/* + * TCP/IP Event Task + * */ + +#define TAG "AsyncTCP" + +// https://github.com/espressif/arduino-esp32/issues/10526 +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING +#define TCP_MUTEX_LOCK() \ + if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ + LOCK_TCPIP_CORE(); \ + } + +#define TCP_MUTEX_UNLOCK() \ + if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ + UNLOCK_TCPIP_CORE(); \ + } +#else // CONFIG_LWIP_TCPIP_CORE_LOCKING +#define TCP_MUTEX_LOCK() +#define TCP_MUTEX_UNLOCK() +#endif // CONFIG_LWIP_TCPIP_CORE_LOCKING + +typedef enum { + LWIP_TCP_SENT, LWIP_TCP_RECV, LWIP_TCP_FIN, LWIP_TCP_ERROR, LWIP_TCP_POLL, LWIP_TCP_CLEAR, LWIP_TCP_ACCEPT, LWIP_TCP_CONNECTED, LWIP_TCP_DNS +} lwip_event_t; + +typedef struct { + lwip_event_t event; + void *arg; + union { + struct { + void * pcb; + int8_t err; + } connected; + struct { + int8_t err; + } error; + struct { + tcp_pcb * pcb; + uint16_t len; + } sent; + struct { + tcp_pcb * pcb; + pbuf * pb; + int8_t err; + } recv; + struct { + tcp_pcb * pcb; + int8_t err; + } fin; + struct { + tcp_pcb * pcb; + } poll; + struct { + AsyncClient * client; + } accept; + struct { + const char * name; + ip_addr_t addr; + } dns; + }; +} lwip_event_packet_t; + +static xQueueHandle _async_queue; +static TaskHandle_t _async_service_task_handle = NULL; + + +SemaphoreHandle_t _slots_lock; +const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP; +static uint32_t _closed_slots[_number_of_closed_slots]; +static uint32_t _closed_index = []() { + _slots_lock = xSemaphoreCreateBinary(); + xSemaphoreGive(_slots_lock); + for (int i = 0; i < _number_of_closed_slots; ++ i) { + _closed_slots[i] = 1; + } + return 1; +}(); + + +static inline bool _init_async_event_queue(){ + if(!_async_queue){ + _async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *)); + if(!_async_queue){ + return false; + } + } + return true; +} + +static inline bool _send_async_event(lwip_event_packet_t ** e){ + return _async_queue && xQueueSend(_async_queue, e, portMAX_DELAY) == pdPASS; +} + +static inline bool _prepend_async_event(lwip_event_packet_t ** e){ + return _async_queue && xQueueSendToFront(_async_queue, e, portMAX_DELAY) == pdPASS; +} + +static inline bool _get_async_event(lwip_event_packet_t ** e){ + return _async_queue && xQueueReceive(_async_queue, e, portMAX_DELAY) == pdPASS; +} + +static bool _remove_events_with_arg(void * arg){ + lwip_event_packet_t * first_packet = NULL; + lwip_event_packet_t * packet = NULL; + + if(!_async_queue){ + return false; + } + //figure out which is the first packet so we can keep the order + while(!first_packet){ + if(xQueueReceive(_async_queue, &first_packet, 0) != pdPASS){ + return false; + } + //discard packet if matching + if((int)first_packet->arg == (int)arg){ + free(first_packet); + first_packet = NULL; + //return first packet to the back of the queue + } else if(xQueueSend(_async_queue, &first_packet, portMAX_DELAY) != pdPASS){ + return false; + } + } + + while(xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet){ + if(xQueueReceive(_async_queue, &packet, 0) != pdPASS){ + return false; + } + if((int)packet->arg == (int)arg){ + free(packet); + packet = NULL; + } else if(xQueueSend(_async_queue, &packet, portMAX_DELAY) != pdPASS){ + return false; + } + } + return true; +} + +static void _handle_async_event(lwip_event_packet_t * e){ + if(e->arg == NULL){ + // do nothing when arg is NULL + //ets_printf("event arg == NULL: 0x%08x\n", e->recv.pcb); + } else if(e->event == LWIP_TCP_CLEAR){ + _remove_events_with_arg(e->arg); + } else if(e->event == LWIP_TCP_RECV){ + //ets_printf("-R: 0x%08x\n", e->recv.pcb); + AsyncClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err); + } else if(e->event == LWIP_TCP_FIN){ + //ets_printf("-F: 0x%08x\n", e->fin.pcb); + AsyncClient::_s_fin(e->arg, e->fin.pcb, e->fin.err); + } else if(e->event == LWIP_TCP_SENT){ + //ets_printf("-S: 0x%08x\n", e->sent.pcb); + AsyncClient::_s_sent(e->arg, e->sent.pcb, e->sent.len); + } else if(e->event == LWIP_TCP_POLL){ + //ets_printf("-P: 0x%08x\n", e->poll.pcb); + AsyncClient::_s_poll(e->arg, e->poll.pcb); + } else if(e->event == LWIP_TCP_ERROR){ + //ets_printf("-E: 0x%08x %d\n", e->arg, e->error.err); + AsyncClient::_s_error(e->arg, e->error.err); + } else if(e->event == LWIP_TCP_CONNECTED){ + //ets_printf("C: 0x%08x 0x%08x %d\n", e->arg, e->connected.pcb, e->connected.err); + AsyncClient::_s_connected(e->arg, e->connected.pcb, e->connected.err); + } else if(e->event == LWIP_TCP_ACCEPT){ + //ets_printf("A: 0x%08x 0x%08x\n", e->arg, e->accept.client); + AsyncServer::_s_accepted(e->arg, e->accept.client); + } else if(e->event == LWIP_TCP_DNS){ + //ets_printf("D: 0x%08x %s = %s\n", e->arg, e->dns.name, ipaddr_ntoa(&e->dns.addr)); + AsyncClient::_s_dns_found(e->dns.name, &e->dns.addr, e->arg); + } + free((void*)(e)); +} + +static void _async_service_task(void *pvParameters){ + lwip_event_packet_t * packet = NULL; + for (;;) { + if(_get_async_event(&packet)){ +#if CONFIG_ASYNC_TCP_USE_WDT + if(esp_task_wdt_add(NULL) != ESP_OK){ + log_e("Failed to add async task to WDT"); + } +#endif + _handle_async_event(packet); +#if CONFIG_ASYNC_TCP_USE_WDT + if(esp_task_wdt_delete(NULL) != ESP_OK){ + log_e("Failed to remove loop task from WDT"); + } +#endif + } + } + vTaskDelete(NULL); + _async_service_task_handle = NULL; +} +/* +static void _stop_async_task(){ + if(_async_service_task_handle){ + vTaskDelete(_async_service_task_handle); + _async_service_task_handle = NULL; + } +} +*/ +static bool _start_async_task(){ + if(!_init_async_event_queue()){ + return false; + } + if(!_async_service_task_handle){ + xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, TASK_CONNECTIVITY_PRIO, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); + if(!_async_service_task_handle){ + return false; + } + } + return true; +} + +/* + * LwIP Callbacks + * */ + +static int8_t _tcp_clear_events(void * arg) { + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_CLEAR; + e->arg = arg; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_connected(void * arg, tcp_pcb * pcb, int8_t err) { + //ets_printf("+C: 0x%08x\n", pcb); + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_CONNECTED; + e->arg = arg; + e->connected.pcb = pcb; + e->connected.err = err; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_poll(void * arg, struct tcp_pcb * pcb) { + //ets_printf("+P: 0x%08x\n", pcb); + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_POLL; + e->arg = arg; + e->poll.pcb = pcb; + if (!_send_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) { + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->arg = arg; + if(pb){ + //ets_printf("+R: 0x%08x\n", pcb); + e->event = LWIP_TCP_RECV; + e->recv.pcb = pcb; + e->recv.pb = pb; + e->recv.err = err; + } else { + //ets_printf("+F: 0x%08x\n", pcb); + e->event = LWIP_TCP_FIN; + e->fin.pcb = pcb; + e->fin.err = err; + //close the PCB in LwIP thread + AsyncClient::_s_lwip_fin(e->arg, e->fin.pcb, e->fin.err); + } + if (!_send_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { + //ets_printf("+S: 0x%08x\n", pcb); + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_SENT; + e->arg = arg; + e->sent.pcb = pcb; + e->sent.len = len; + if (!_send_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static void _tcp_error(void * arg, int8_t err) { + //ets_printf("+E: 0x%08x\n", arg); + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_ERROR; + e->arg = arg; + e->error.err = err; + if (!_send_async_event(&e)) { + free((void*)(e)); + } +} + +static void _tcp_dns_found(const char * name, struct ip_addr * ipaddr, void * arg) { + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + //ets_printf("+DNS: name=%s ipaddr=0x%08x arg=%x\n", name, ipaddr, arg); + e->event = LWIP_TCP_DNS; + e->arg = arg; + e->dns.name = name; + if (ipaddr) { + memcpy(&e->dns.addr, ipaddr, sizeof(struct ip_addr)); + } else { + memset(&e->dns.addr, 0, sizeof(e->dns.addr)); + } + if (!_send_async_event(&e)) { + free((void*)(e)); + } +} + +//Used to switch out from LwIP thread +static int8_t _tcp_accept(void * arg, AsyncClient * client) { + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_ACCEPT; + e->arg = arg; + e->accept.client = client; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +/* + * TCP/IP API Calls + * */ + +#include "lwip/priv/tcpip_priv.h" + +typedef struct { + struct tcpip_api_call_data call; + tcp_pcb * pcb; + int8_t closed_slot; + int8_t err; + union { + struct { + const char* data; + size_t size; + uint8_t apiflags; + } write; + size_t received; + struct { + ip_addr_t * addr; + uint16_t port; + tcp_connected_fn cb; + } connect; + struct { + ip_addr_t * addr; + uint16_t port; + } bind; + uint8_t backlog; + }; +} tcp_api_call_t; + +static err_t _tcp_output_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_output(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_output(tcp_pcb * pcb, int8_t closed_slot) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_write_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); + } + return msg->err; +} + +static esp_err_t _tcp_write(tcp_pcb * pcb, int8_t closed_slot, const char* data, size_t size, uint8_t apiflags) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.write.data = data; + msg.write.size = size; + msg.write.apiflags = apiflags; + tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_recved_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + msg->err = 0; + tcp_recved(msg->pcb, msg->received); + } + return msg->err; +} + +static esp_err_t _tcp_recved(tcp_pcb * pcb, int8_t closed_slot, size_t len) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.received = len; + tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_close_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_close(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_close(tcp_pcb * pcb, int8_t closed_slot) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_abort_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + tcp_abort(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_abort(tcp_pcb * pcb, int8_t closed_slot) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_connect_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); + return msg->err; +} + +static esp_err_t _tcp_connect(tcp_pcb * pcb, int8_t closed_slot, ip_addr_t * addr, uint16_t port, tcp_connected_fn cb) { + if(!pcb){ + return ESP_FAIL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.connect.addr = addr; + msg.connect.port = port; + msg.connect.cb = cb; + tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_bind_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); + return msg->err; +} + +static esp_err_t _tcp_bind(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port) { + if(!pcb){ + return ESP_FAIL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = -1; + msg.bind.addr = addr; + msg.bind.port = port; + tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_listen_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = 0; + msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); + return msg->err; +} + +static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { + if(!pcb){ + return NULL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = -1; + msg.backlog = backlog?backlog:0xFF; + tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); + return msg.pcb; +} + + + +/* + Async TCP Client + */ + +AsyncClient::AsyncClient(tcp_pcb* pcb) +: _connect_cb(0) +, _connect_cb_arg(0) +, _discard_cb(0) +, _discard_cb_arg(0) +, _sent_cb(0) +, _sent_cb_arg(0) +, _error_cb(0) +, _error_cb_arg(0) +, _recv_cb(0) +, _recv_cb_arg(0) +, _pb_cb(0) +, _pb_cb_arg(0) +, _timeout_cb(0) +, _timeout_cb_arg(0) +, _pcb_busy(false) +, _pcb_sent_at(0) +, _ack_pcb(true) +, _rx_last_packet(0) +, _rx_since_timeout(0) +, _ack_timeout(ASYNC_MAX_ACK_TIME) +, _connect_port(0) +, prev(NULL) +, next(NULL) +{ + _pcb = pcb; + _closed_slot = -1; + if(_pcb){ + _allocate_closed_slot(); + _rx_last_packet = millis(); + tcp_arg(_pcb, this); + tcp_recv(_pcb, &_tcp_recv); + tcp_sent(_pcb, &_tcp_sent); + tcp_err(_pcb, &_tcp_error); + tcp_poll(_pcb, &_tcp_poll, 1); + } +} + +AsyncClient::~AsyncClient(){ + if(_pcb) { + _close(); + } + _free_closed_slot(); +} + +/* + * Operators + * */ + +AsyncClient& AsyncClient::operator=(const AsyncClient& other){ + if (_pcb) { + _close(); + } + + _pcb = other._pcb; + _closed_slot = other._closed_slot; + if (_pcb) { + _rx_last_packet = millis(); + tcp_arg(_pcb, this); + tcp_recv(_pcb, &_tcp_recv); + tcp_sent(_pcb, &_tcp_sent); + tcp_err(_pcb, &_tcp_error); + tcp_poll(_pcb, &_tcp_poll, 1); + } + return *this; +} + +bool AsyncClient::operator==(const AsyncClient &other) { + return _pcb == other._pcb; +} + +AsyncClient & AsyncClient::operator+=(const AsyncClient &other) { + if(next == NULL){ + next = (AsyncClient*)(&other); + next->prev = this; + } else { + AsyncClient *c = next; + while(c->next != NULL) { + c = c->next; + } + c->next =(AsyncClient*)(&other); + c->next->prev = c; + } + return *this; +} + +/* + * Callback Setters + * */ + +void AsyncClient::onConnect(AcConnectHandler cb, void* arg){ + _connect_cb = cb; + _connect_cb_arg = arg; +} + +void AsyncClient::onDisconnect(AcConnectHandler cb, void* arg){ + _discard_cb = cb; + _discard_cb_arg = arg; +} + +void AsyncClient::onAck(AcAckHandler cb, void* arg){ + _sent_cb = cb; + _sent_cb_arg = arg; +} + +void AsyncClient::onError(AcErrorHandler cb, void* arg){ + _error_cb = cb; + _error_cb_arg = arg; +} + +void AsyncClient::onData(AcDataHandler cb, void* arg){ + _recv_cb = cb; + _recv_cb_arg = arg; +} + +void AsyncClient::onPacket(AcPacketHandler cb, void* arg){ + _pb_cb = cb; + _pb_cb_arg = arg; +} + +void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg){ + _timeout_cb = cb; + _timeout_cb_arg = arg; +} + +void AsyncClient::onPoll(AcConnectHandler cb, void* arg){ + _poll_cb = cb; + _poll_cb_arg = arg; +} + +/* + * Main Public Methods + * */ + +bool AsyncClient::connect(IPAddress ip, uint16_t port){ + if (_pcb){ + log_w("already connected, state %d", _pcb->state); + return false; + } + if(!_start_async_task()){ + log_e("failed to start task"); + return false; + } + + ip_addr_t addr; + addr.type = IPADDR_TYPE_V4; + addr.u_addr.ip4.addr = ip; + + TCP_MUTEX_LOCK(); + tcp_pcb* pcb = tcp_new_ip_type(IPADDR_TYPE_V4); + if (!pcb){ + TCP_MUTEX_UNLOCK(); + log_e("pcb == NULL"); + return false; + } + + tcp_arg(pcb, this); + tcp_err(pcb, &_tcp_error); + tcp_recv(pcb, &_tcp_recv); + tcp_sent(pcb, &_tcp_sent); + tcp_poll(pcb, &_tcp_poll, 1); + TCP_MUTEX_UNLOCK(); + //_tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); + _tcp_connect(pcb, _closed_slot, &addr, port,(tcp_connected_fn)&_tcp_connected); + return true; +} + +bool AsyncClient::connect(const char* host, uint16_t port){ + ip_addr_t addr; + + if(!_start_async_task()){ + log_e("failed to start task"); + return false; + } + TCP_MUTEX_LOCK(); + err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); + TCP_MUTEX_UNLOCK(); + if(err == ERR_OK) { + return connect(IPAddress(addr.u_addr.ip4.addr), port); + } else if(err == ERR_INPROGRESS) { + _connect_port = port; + return true; + } + log_e("error: %d", err); + return false; +} + +void AsyncClient::close(bool now){ + if(_pcb){ + _tcp_recved(_pcb, _closed_slot, _rx_ack_len); + } + _close(); +} + +int8_t AsyncClient::abort(){ + if(_pcb) { + _tcp_abort(_pcb, _closed_slot ); + _pcb = NULL; + } + return ERR_ABRT; +} + +size_t AsyncClient::space(){ + if((_pcb != NULL) && (_pcb->state == 4)){ + return tcp_sndbuf(_pcb); + } + return 0; +} + +size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { + if(!_pcb || size == 0 || data == NULL) { + return 0; + } + size_t room = space(); + if(!room) { + return 0; + } + size_t will_send = (room < size) ? room : size; + int8_t err = ERR_OK; + err = _tcp_write(_pcb, _closed_slot, data, will_send, apiflags); + if(err != ERR_OK) { + return 0; + } + return will_send; +} + +bool AsyncClient::send(){ + int8_t err = ERR_OK; + err = _tcp_output(_pcb, _closed_slot); + if(err == ERR_OK){ + _pcb_busy = true; + _pcb_sent_at = millis(); + return true; + } + return false; +} + +size_t AsyncClient::ack(size_t len){ + if(len > _rx_ack_len) + len = _rx_ack_len; + if(len){ + _tcp_recved(_pcb, _closed_slot, len); + } + _rx_ack_len -= len; + return len; +} + +void AsyncClient::ackPacket(struct pbuf * pb){ + if(!pb){ + return; + } + _tcp_recved(_pcb, _closed_slot, pb->len); + pbuf_free(pb); +} + +/* + * Main Private Methods + * */ + +int8_t AsyncClient::_close(){ + //ets_printf("X: 0x%08x\n", (uint32_t)this); + int8_t err = ERR_OK; + if(_pcb) { + //log_i(""); + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + TCP_MUTEX_UNLOCK(); + _tcp_clear_events(this); + err = _tcp_close(_pcb, _closed_slot); + if(err != ERR_OK) { + err = abort(); + } + _pcb = NULL; + if(_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + } + return err; +} + +void AsyncClient::_allocate_closed_slot(){ + xSemaphoreTake(_slots_lock, portMAX_DELAY); + uint32_t closed_slot_min_index = 0; + for (int i = 0; i < _number_of_closed_slots; ++ i) { + if ((_closed_slot == -1 || _closed_slots[i] <= closed_slot_min_index) && _closed_slots[i] != 0) { + closed_slot_min_index = _closed_slots[i]; + _closed_slot = i; + } + } + if (_closed_slot != -1) { + _closed_slots[_closed_slot] = 0; + } + xSemaphoreGive(_slots_lock); +} + +void AsyncClient::_free_closed_slot(){ + if (_closed_slot != -1) { + _closed_slots[_closed_slot] = _closed_index; + _closed_slot = -1; + ++ _closed_index; + } +} + +/* + * Private Callbacks + * */ + +int8_t AsyncClient::_connected(void* pcb, int8_t err){ + _pcb = reinterpret_cast(pcb); + if(_pcb){ + _rx_last_packet = millis(); + _pcb_busy = false; +// tcp_recv(_pcb, &_tcp_recv); +// tcp_sent(_pcb, &_tcp_sent); +// tcp_poll(_pcb, &_tcp_poll, 1); + } + if(_connect_cb) { + _connect_cb(_connect_cb_arg, this); + } + return ERR_OK; +} + +void AsyncClient::_error(int8_t err) { + if(_pcb){ + tcp_arg(_pcb, NULL); + if(_pcb->state == LISTEN) { + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + } + _pcb = NULL; + } + if(_error_cb) { + _error_cb(_error_cb_arg, this, err); + } + if(_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } +} + +//In LwIP Thread +int8_t AsyncClient::_lwip_fin(tcp_pcb* pcb, int8_t err) { + if(!_pcb || pcb != _pcb){ + log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + return ERR_OK; + } + tcp_arg(_pcb, NULL); + if(_pcb->state == LISTEN) { + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + } + if(tcp_close(_pcb) != ERR_OK) { + tcp_abort(_pcb); + } + _free_closed_slot(); + _pcb = NULL; + return ERR_OK; +} + +//In Async Thread +int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) { + _tcp_clear_events(this); + if(_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + return ERR_OK; +} + +int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { + _rx_last_packet = millis(); + //log_i("%u", len); + _pcb_busy = false; + if(_sent_cb) { + _sent_cb(_sent_cb_arg, this, len, (millis() - _pcb_sent_at)); + } + return ERR_OK; +} + +int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { + while(pb != NULL) { + _rx_last_packet = millis(); + //we should not ack before we assimilate the data + _ack_pcb = true; + pbuf *b = pb; + pb = b->next; + b->next = NULL; + if(_pb_cb){ + _pb_cb(_pb_cb_arg, this, b); + } else { + if(_recv_cb) { + _recv_cb(_recv_cb_arg, this, b->payload, b->len); + } + if(!_ack_pcb) { + _rx_ack_len += b->len; + } else if(_pcb) { + _tcp_recved(_pcb, _closed_slot, b->len); + } + pbuf_free(b); + } + } + return ERR_OK; +} + +int8_t AsyncClient::_poll(tcp_pcb* pcb){ + if(!_pcb){ + log_w("pcb is NULL"); + return ERR_OK; + } + if(pcb != _pcb){ + log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + return ERR_OK; + } + + uint32_t now = millis(); + + // ACK Timeout + if(_pcb_busy && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout){ + _pcb_busy = false; + log_w("ack timeout %d", pcb->state); + if(_timeout_cb) + _timeout_cb(_timeout_cb_arg, this, (now - _pcb_sent_at)); + return ERR_OK; + } + // RX Timeout + if(_rx_since_timeout && (now - _rx_last_packet) >= (_rx_since_timeout * 1000)){ + log_w("rx timeout %d", pcb->state); + _close(); + return ERR_OK; + } + // Everything is fine + if(_poll_cb) { + _poll_cb(_poll_cb_arg, this); + } + return ERR_OK; +} + +void AsyncClient::_dns_found(struct ip_addr *ipaddr){ + if(ipaddr && ipaddr->u_addr.ip4.addr){ + connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port); + } else { + if(_error_cb) { + _error_cb(_error_cb_arg, this, -55); + } + if(_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + } +} + +/* + * Public Helper Methods + * */ + +void AsyncClient::stop() { + close(false); +} + +bool AsyncClient::free(){ + if(!_pcb) { + return true; + } + if(_pcb->state == 0 || _pcb->state > 4) { + return true; + } + return false; +} + +size_t AsyncClient::write(const char* data) { + if(data == NULL) { + return 0; + } + return write(data, strlen(data)); +} + +size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) { + size_t will_send = add(data, size, apiflags); + if(!will_send || !send()) { + return 0; + } + return will_send; +} + +void AsyncClient::setRxTimeout(uint32_t timeout){ + _rx_since_timeout = timeout; +} + +uint32_t AsyncClient::getRxTimeout(){ + return _rx_since_timeout; +} + +uint32_t AsyncClient::getAckTimeout(){ + return _ack_timeout; +} + +void AsyncClient::setAckTimeout(uint32_t timeout){ + _ack_timeout = timeout; +} + +void AsyncClient::setNoDelay(bool nodelay){ + if(!_pcb) { + return; + } + if(nodelay) { + tcp_nagle_disable(_pcb); + } else { + tcp_nagle_enable(_pcb); + } +} + +bool AsyncClient::getNoDelay(){ + if(!_pcb) { + return false; + } + return tcp_nagle_disabled(_pcb); +} + +uint16_t AsyncClient::getMss(){ + if(!_pcb) { + return 0; + } + return tcp_mss(_pcb); +} + +uint32_t AsyncClient::getRemoteAddress() { + if(!_pcb) { + return 0; + } + return _pcb->remote_ip.u_addr.ip4.addr; +} + +uint16_t AsyncClient::getRemotePort() { + if(!_pcb) { + return 0; + } + return _pcb->remote_port; +} + +uint32_t AsyncClient::getLocalAddress() { + if(!_pcb) { + return 0; + } + return _pcb->local_ip.u_addr.ip4.addr; +} + +uint16_t AsyncClient::getLocalPort() { + if(!_pcb) { + return 0; + } + return _pcb->local_port; +} + +IPAddress AsyncClient::remoteIP() { + return IPAddress(getRemoteAddress()); +} + +uint16_t AsyncClient::remotePort() { + return getRemotePort(); +} + +IPAddress AsyncClient::localIP() { + return IPAddress(getLocalAddress()); +} + +uint16_t AsyncClient::localPort() { + return getLocalPort(); +} + +uint8_t AsyncClient::state() { + if(!_pcb) { + return 0; + } + return _pcb->state; +} + +bool AsyncClient::connected(){ + if (!_pcb) { + return false; + } + return _pcb->state == 4; +} + +bool AsyncClient::connecting(){ + if (!_pcb) { + return false; + } + return _pcb->state > 0 && _pcb->state < 4; +} + +bool AsyncClient::disconnecting(){ + if (!_pcb) { + return false; + } + return _pcb->state > 4 && _pcb->state < 10; +} + +bool AsyncClient::disconnected(){ + if (!_pcb) { + return true; + } + return _pcb->state == 0 || _pcb->state == 10; +} + +bool AsyncClient::freeable(){ + if (!_pcb) { + return true; + } + return _pcb->state == 0 || _pcb->state > 4; +} + +bool AsyncClient::canSend(){ + return space() > 0; +} + +const char * AsyncClient::errorToString(int8_t error){ + switch(error){ + case ERR_OK: return "OK"; + case ERR_MEM: return "Out of memory error"; + case ERR_BUF: return "Buffer error"; + case ERR_TIMEOUT: return "Timeout"; + case ERR_RTE: return "Routing problem"; + case ERR_INPROGRESS: return "Operation in progress"; + case ERR_VAL: return "Illegal value"; + case ERR_WOULDBLOCK: return "Operation would block"; + case ERR_USE: return "Address in use"; + case ERR_ALREADY: return "Already connected"; + case ERR_CONN: return "Not connected"; + case ERR_IF: return "Low-level netif error"; + case ERR_ABRT: return "Connection aborted"; + case ERR_RST: return "Connection reset"; + case ERR_CLSD: return "Connection closed"; + case ERR_ARG: return "Illegal argument"; + case -55: return "DNS failed"; + default: return "UNKNOWN"; + } +} + +const char * AsyncClient::stateToString(){ + switch(state()){ + case 0: return "Closed"; + case 1: return "Listen"; + case 2: return "SYN Sent"; + case 3: return "SYN Received"; + case 4: return "Established"; + case 5: return "FIN Wait 1"; + case 6: return "FIN Wait 2"; + case 7: return "Close Wait"; + case 8: return "Closing"; + case 9: return "Last ACK"; + case 10: return "Time Wait"; + default: return "UNKNOWN"; + } +} + +/* + * Static Callbacks (LwIP C2C++ interconnect) + * */ + +void AsyncClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg){ + reinterpret_cast(arg)->_dns_found(ipaddr); +} + +int8_t AsyncClient::_s_poll(void * arg, struct tcp_pcb * pcb) { + return reinterpret_cast(arg)->_poll(pcb); +} + +int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) { + return reinterpret_cast(arg)->_recv(pcb, pb, err); +} + +int8_t AsyncClient::_s_fin(void * arg, struct tcp_pcb * pcb, int8_t err) { + return reinterpret_cast(arg)->_fin(pcb, err); +} + +int8_t AsyncClient::_s_lwip_fin(void * arg, struct tcp_pcb * pcb, int8_t err) { + return reinterpret_cast(arg)->_lwip_fin(pcb, err); +} + +int8_t AsyncClient::_s_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { + return reinterpret_cast(arg)->_sent(pcb, len); +} + +void AsyncClient::_s_error(void * arg, int8_t err) { + reinterpret_cast(arg)->_error(err); +} + +int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){ + return reinterpret_cast(arg)->_connected(pcb, err); +} + +/* + Async TCP Server + */ + +AsyncServer::AsyncServer(IPAddress addr, uint16_t port) +: _port(port) +, _addr(addr) +, _noDelay(false) +, _pcb(0) +, _connect_cb(0) +, _connect_cb_arg(0) +{} + +AsyncServer::AsyncServer(uint16_t port) +: _port(port) +, _addr((uint32_t) IPADDR_ANY) +, _noDelay(false) +, _pcb(0) +, _connect_cb(0) +, _connect_cb_arg(0) +{} + +AsyncServer::~AsyncServer(){ + end(); +} + +void AsyncServer::onClient(AcConnectHandler cb, void* arg){ + _connect_cb = cb; + _connect_cb_arg = arg; +} + +void AsyncServer::begin(){ + if(_pcb) { + return; + } + + if(!_start_async_task()){ + log_e("failed to start task"); + return; + } + int8_t err; + TCP_MUTEX_LOCK(); + _pcb = tcp_new_ip_type(IPADDR_TYPE_V4); + TCP_MUTEX_UNLOCK(); + if (!_pcb){ + log_e("_pcb == NULL"); + return; + } + + ip_addr_t local_addr; + local_addr.type = IPADDR_TYPE_V4; + local_addr.u_addr.ip4.addr = (uint32_t) _addr; + err = _tcp_bind(_pcb, &local_addr, _port); + + if (err != ERR_OK) { + _tcp_close(_pcb, -1); + log_e("bind error: %d", err); + return; + } + + static uint8_t backlog = 5; + _pcb = _tcp_listen_with_backlog(_pcb, backlog); + if (!_pcb) { + log_e("listen_pcb == NULL"); + return; + } + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, (void*) this); + tcp_accept(_pcb, &_s_accept); + TCP_MUTEX_UNLOCK(); +} + +void AsyncServer::end(){ + if(_pcb){ + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, NULL); + tcp_accept(_pcb, NULL); + TCP_MUTEX_UNLOCK(); + if(tcp_close(_pcb) != ERR_OK){ + _tcp_abort(_pcb, -1); + } + _pcb = NULL; + } +} + +//runs on LwIP thread +int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ + //ets_printf("+A: 0x%08x\n", pcb); + if(_connect_cb){ + AsyncClient *c = new AsyncClient(pcb); + if(c){ + c->setNoDelay(_noDelay); + return _tcp_accept(this, c); + } + } + if(tcp_close(pcb) != ERR_OK){ + tcp_abort(pcb); + } + log_e("FAIL"); + return ERR_OK; +} + +int8_t AsyncServer::_accepted(AsyncClient* client){ + if(_connect_cb){ + _connect_cb(_connect_cb_arg, client); + } + return ERR_OK; +} + +void AsyncServer::setNoDelay(bool nodelay){ + _noDelay = nodelay; +} + +bool AsyncServer::getNoDelay(){ + return _noDelay; +} + +uint8_t AsyncServer::status(){ + if (!_pcb) { + return 0; + } + return _pcb->state; +} + +int8_t AsyncServer::_s_accept(void * arg, tcp_pcb * pcb, int8_t err){ + return reinterpret_cast(arg)->_accept(pcb, err); +} + +int8_t AsyncServer::_s_accepted(void *arg, AsyncClient* client){ + return reinterpret_cast(arg)->_accepted(client); +} diff --git a/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h new file mode 100644 index 000000000..b89fb1224 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h @@ -0,0 +1,220 @@ +/* + Asynchronous TCP library for Espressif MCUs + + Copyright (c) 2016 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ASYNCTCP_H_ +#define ASYNCTCP_H_ + +#include "IPAddress.h" +#include "sdkconfig.h" +#include +extern "C" { + #include "freertos/semphr.h" + #include "lwip/pbuf.h" +} + +#include "../../../system_settings.h" +#include "../../../devboard/hal/hal.h" + +//If core is not defined, then we are running in Arduino or PIO +#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE +#define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE //any available core +#define CONFIG_ASYNC_TCP_USE_WDT 0 //if enabled, adds between 33us and 200us per event +#endif + +class AsyncClient; + +#define ASYNC_MAX_ACK_TIME 5000 +#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given) +#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react. + +typedef std::function AcConnectHandler; +typedef std::function AcAckHandler; +typedef std::function AcErrorHandler; +typedef std::function AcDataHandler; +typedef std::function AcPacketHandler; +typedef std::function AcTimeoutHandler; + +struct tcp_pcb; +struct ip_addr; + +class AsyncClient { + public: + AsyncClient(tcp_pcb* pcb = 0); + ~AsyncClient(); + + AsyncClient & operator=(const AsyncClient &other); + AsyncClient & operator+=(const AsyncClient &other); + + bool operator==(const AsyncClient &other); + + bool operator!=(const AsyncClient &other) { + return !(*this == other); + } + bool connect(IPAddress ip, uint16_t port); + bool connect(const char* host, uint16_t port); + void close(bool now = false); + void stop(); + int8_t abort(); + bool free(); + + bool canSend();//ack is not pending + size_t space();//space available in the TCP window + size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending + bool send();//send all data added with the method above + + //write equals add()+send() + size_t write(const char* data); + size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true + + uint8_t state(); + bool connecting(); + bool connected(); + bool disconnecting(); + bool disconnected(); + bool freeable();//disconnected or disconnecting + + uint16_t getMss(); + + uint32_t getRxTimeout(); + void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds + + uint32_t getAckTimeout(); + void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds + + void setNoDelay(bool nodelay); + bool getNoDelay(); + + uint32_t getRemoteAddress(); + uint16_t getRemotePort(); + uint32_t getLocalAddress(); + uint16_t getLocalPort(); + + //compatibility + IPAddress remoteIP(); + uint16_t remotePort(); + IPAddress localIP(); + uint16_t localPort(); + + void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect + void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected + void onAck(AcAckHandler cb, void* arg = 0); //ack received + void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error + void onData(AcDataHandler cb, void* arg = 0); //data received (called if onPacket is not used) + void onPacket(AcPacketHandler cb, void* arg = 0); //data received + void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout + void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected + + void ackPacket(struct pbuf * pb);//ack pbuf from onPacket + size_t ack(size_t len); //ack data that you have not acked using the method below + void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData + + const char * errorToString(int8_t error); + const char * stateToString(); + + //Do not use any of the functions below! + static int8_t _s_poll(void *arg, struct tcp_pcb *tpcb); + static int8_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, int8_t err); + static int8_t _s_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); + static int8_t _s_lwip_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); + static void _s_error(void *arg, int8_t err); + static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); + static int8_t _s_connected(void* arg, void* tpcb, int8_t err); + static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); + + int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); + tcp_pcb * pcb(){ return _pcb; } + + protected: + tcp_pcb* _pcb; + int8_t _closed_slot; + + AcConnectHandler _connect_cb; + void* _connect_cb_arg; + AcConnectHandler _discard_cb; + void* _discard_cb_arg; + AcAckHandler _sent_cb; + void* _sent_cb_arg; + AcErrorHandler _error_cb; + void* _error_cb_arg; + AcDataHandler _recv_cb; + void* _recv_cb_arg; + AcPacketHandler _pb_cb; + void* _pb_cb_arg; + AcTimeoutHandler _timeout_cb; + void* _timeout_cb_arg; + AcConnectHandler _poll_cb; + void* _poll_cb_arg; + + bool _pcb_busy; + uint32_t _pcb_sent_at; + bool _ack_pcb; + uint32_t _rx_ack_len; + uint32_t _rx_last_packet; + uint32_t _rx_since_timeout; + uint32_t _ack_timeout; + uint16_t _connect_port; + + int8_t _close(); + void _free_closed_slot(); + void _allocate_closed_slot(); + int8_t _connected(void* pcb, int8_t err); + void _error(int8_t err); + int8_t _poll(tcp_pcb* pcb); + int8_t _sent(tcp_pcb* pcb, uint16_t len); + int8_t _fin(tcp_pcb* pcb, int8_t err); + int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); + void _dns_found(struct ip_addr *ipaddr); + + public: + AsyncClient* prev; + AsyncClient* next; +}; + +class AsyncServer { + public: + AsyncServer(IPAddress addr, uint16_t port); + AsyncServer(uint16_t port); + ~AsyncServer(); + void onClient(AcConnectHandler cb, void* arg); + void begin(); + void end(); + void setNoDelay(bool nodelay); + bool getNoDelay(); + uint8_t status(); + + //Do not use any of the functions below! + static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); + static int8_t _s_accepted(void *arg, AsyncClient* client); + + protected: + uint16_t _port; + IPAddress _addr; + bool _noDelay; + tcp_pcb* _pcb; + AcConnectHandler _connect_cb; + void* _connect_cb_arg; + + int8_t _accept(tcp_pcb* newpcb, int8_t err); + int8_t _accepted(AsyncClient* client); +}; + + +#endif /* ASYNCTCP_H_ */ diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h index 94a0c51ea..d3d1b1d4f 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h @@ -22,7 +22,7 @@ #include #ifdef ESP32 -#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #define SSE_MAX_QUEUED_MESSAGES 32 #else #include diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h index 2ef8f9ec5..747399b8d 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h @@ -23,7 +23,7 @@ #include #ifdef ESP32 -#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #define WS_MAX_QUEUED_MESSAGES 32 #else #include diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h index 7731a14ca..664c0a5cf 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h @@ -30,10 +30,10 @@ #ifdef ESP32 #include -#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #elif defined(ESP8266) #include -#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #else #error Platform not supported #endif From bd5984de29bf7907189acafafe6b7020a0d98fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 23 Dec 2024 15:39:54 +0200 Subject: [PATCH 108/225] Restore USER_SETTINGS file --- Software/USER_SETTINGS.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 90cb37f7f..2cefdb7aa 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -33,7 +33,7 @@ //#define TESLA_MODEL_3Y_BATTERY //#define TESLA_MODEL_SX_BATTERY //#define VOLVO_SPA_BATTERY -#define TEST_FAKE_BATTERY +//#define TEST_FAKE_BATTERY //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires CAN_ADDON setup) /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ @@ -53,8 +53,8 @@ //#define SOLAX_CAN //Enable this line to emulate a "SolaX Triple Power LFP" over CAN bus /* Select hardware used for Battery-Emulator */ -//#define HW_LILYGO -#define HW_STARK +#define HW_LILYGO +//#define HW_STARK //#define HW_3LB /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ From 5faf6c1a9e3901abfe97d3515b6fdcb0bd814dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 23 Dec 2024 15:53:35 +0200 Subject: [PATCH 109/225] Add TODOs to .cpp file --- Software/src/battery/BOLT-AMPERA-BATTERY.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp index 510b90b72..90d85eb5f 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -5,6 +5,20 @@ #include "../devboard/utils/events.h" #include "BOLT-AMPERA-BATTERY.h" +/* +TODOs left for this implementation +- The battery has 3 CAN ports. One of them is responsible for the 7E4 polls, the other for the 7E7 polls +- Current implementation only seems to get the 7E7 polls working. +- Could on of the CAN channels be GMLAN? + +- The values missing for a working implementation is: +- SOC% missing! This is absolutely mandatory to fix before starting to use this! +- Capacity (kWh) (can be estimated) +- Charge max power (can be estimated) +- Discharge max power (can be estimated) +- SOH% (low prio)) +*/ + /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis20ms = 0; // will store last time a 20ms CAN Message was send static unsigned long previousMillis100ms = 0; // will store last time a 100ms CAN Message was send From 023fbc6e72313136eb1cfcb71bdf38928b372dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 23 Dec 2024 16:09:42 +0200 Subject: [PATCH 110/225] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d3acd4be2..2e897f0e9 100644 --- a/README.md +++ b/README.md @@ -44,17 +44,18 @@ For more examples showing wiring, see each battery types own Wiki page. For inst 3. Click `File` menu -> `Preferences` -> `Additional Development` -> `Additional Board Manager URLs` -> Enter the URL in the input box: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json` and click OK. 4. Click `Tools` menu -> `Board: "...."` -> `Boards Manager...`, install the `esp32` package by `Espressif Systems` (not `Arduino ESP32 Boards`), then press `Close`. -**NOTE: The version depends on which release of Battery-Emulator you are running!** +**NOTE: The ESP32 version depends on which release of Battery-Emulator you are running!** - ⚠️ Make sure to use a 2.x.x version if you are on a release **older** than 6.0.0 (For instance ESP32 v2.0.11 when using Battery-Emulator v5.4.0) -- ⚠️ Make sure to use a 3.x.x version if you are on a release **newer** than 6.0.0 (For instance ESP32 v3.0.0 when using Battery-Emulator v6.0.0) - +- ⚠️ Make sure to use a 3.0.x version if you are on a release **newer** than 6.0.0 (For instance ESP32 v3.0.0 when using Battery-Emulator v6.0.0) +- ⚠️ Make sure to use a 3.1.x version if you are on a release **newer** than 8.0.0 (For instance ESP32 v3.1.0 when using Battery-Emulator v8.0.0) + ![bild](https://github.com/dalathegreat/Battery-Emulator/assets/26695010/6a2414b1-f2ca-4746-8e8d-9afd78bd9252) 5. The Arduino board should be set to `ESP32 Dev Module` (under `Tools` -> `Board` -> `ESP32 Arduino`) with the following settings: ![alt text](https://github.com/Xinyuan-LilyGO/T-CAN485/blob/main/img/arduino_setting.png) 6. Select which battery type you will use, along with other optional settings. This is done in the `USER_SETTINGS.h` file. -7. Copy the `USER_SECRETS.TEMPLATE.h` file to `USER_SECRETS.h` and update relevant secrets. +7. Copy the `USER_SECRETS.TEMPLATE.h` file to `USER_SECRETS.h` and update connectivity settings inside this file. 8. Press `Verify` and `Upload` to send the sketch to the board. NOTE: In some cases, the LilyGo must be powered through the main power connector instead of USB-C when performing the initial firmware upload. From 173091a7f3ce60802f32760841d479f5108def7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 23 Dec 2024 16:10:58 +0200 Subject: [PATCH 111/225] Pre-commit fix --- Software/src/devboard/webserver/advanced_battery_html.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 03fb0540e..a634ef7c5 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -720,7 +720,8 @@ String advanced_battery_processor(const String& var) { #if !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_BATTERY) && !defined(TESLA_BATTERY) && \ !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && !defined(BYD_ATTO_3_BATTERY) && \ - !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && !defined(MEB_BATTERY) // Only the listed types have extra info + !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ + !defined(MEB_BATTERY) // Only the listed types have extra info content += "No extra information available for this battery type"; #endif From ad84b7e0f8230573dc92539c11f4a51456094078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 24 Dec 2024 00:22:33 +0200 Subject: [PATCH 112/225] Make USER_SETTINGS more simplified --- Software/Software.ino | 14 ++++++-------- Software/USER_SECRETS.TEMPLATE.h | 25 ++++++++++++++++--------- Software/USER_SETTINGS.cpp | 28 ++++++++++------------------ Software/USER_SETTINGS.h | 22 +++++++--------------- Software/src/devboard/wifi/wifi.cpp | 8 ++------ 5 files changed, 41 insertions(+), 56 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 60cc30d21..ce84181b1 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -1,16 +1,13 @@ /* 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 "src/include.h" - #include "HardwareSerial.h" +#include "USER_SECRETS.h" #include "USER_SETTINGS.h" #include "esp_system.h" #include "esp_task_wdt.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "src/charger/CHARGERS.h" #include "src/communication/can/comm_can.h" #include "src/communication/contactorcontrol/comm_contactorcontrol.h" #include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h" @@ -22,6 +19,7 @@ #include "src/devboard/utils/led_handler.h" #include "src/devboard/utils/logging.h" #include "src/devboard/utils/value_mapping.h" +#include "src/include.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "src/lib/bblanchon-ArduinoJson/ArduinoJson.h" @@ -30,7 +28,10 @@ #include "src/lib/eModbus-eModbus/scripts/mbServerFCs.h" #include "src/lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "src/lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" - +#ifndef AP_PASSWORD +#error \ + "Initial setup not completed, USER_SECRETS.h is missing. Please rename the file USER_SECRETS.TEMPLATE.h to USER_SECRETS.h and fill in the required credentials. This file is ignored by version control to keep sensitive information private." +#endif #ifdef WIFI #include "src/devboard/wifi/wifi.h" #ifdef WEBSERVER @@ -233,9 +234,6 @@ void core_loop(void* task_time_us) { update_machineryprotection(); // Check safeties (Not on serial link reciever board) #endif // SERIAL_LINK_RECEIVER update_values_inverter(); // Update values heading towards inverter - if (DUMMY_EVENT_ENABLED) { - set_event(EVENT_DUMMY_ERROR, (uint8_t)millis()); - } } END_TIME_MEASUREMENT_MAX(time_values, datalayer.system.status.time_values_us); diff --git a/Software/USER_SECRETS.TEMPLATE.h b/Software/USER_SECRETS.TEMPLATE.h index 1d1b05695..1cd013b9a 100644 --- a/Software/USER_SECRETS.TEMPLATE.h +++ b/Software/USER_SECRETS.TEMPLATE.h @@ -1,13 +1,20 @@ +/* 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 */ + +//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 -#define AP_PASSWORD "123456789" // Minimum of 8 characters; set to blank if you want the access point to be open -#define WEBSERVER_AUTH_REQUIRED \ - false //Set this line to true to activate webserver authentication (this line must not be commented). -#define HTTP_USERNAME "admin" // username to webserver authentication; -#define HTTP_PASSWORD "admin" // password to webserver authentication; +//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 -#define MQTT_SERVER "192.168.xxx.yyy" // mqtt server address -#define MQTT_PORT 1883 // mqtt server port -#define MQTT_USER NULL // mqtt username, leave blank for no authentication -#define MQTT_PASSWORD NULL // mqtt password, leave blank for no authentication +//MQTT credentials +#define MQTT_SERVER "192.168.xxx.yyy" // MQTT server address +#define MQTT_PORT 1883 // MQTT server port +#define MQTT_USER NULL // MQTT username, leave blank for no authentication +#define MQTT_PASSWORD NULL // MQTT password, leave blank for no authentication diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 7c406893c..0ed5c8477 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -20,28 +20,21 @@ volatile CAN_Configuration can_config = { .charger = CAN_NATIVE // (OPTIONAL) Which CAN is your charger connected to? }; -#ifdef WIFI +std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h +std::string password = WIFI_PASSWORD; // Set in USER_SECRETS.h +const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface +const char* passwordAP = AP_PASSWORD; // Set in USER_SECRETS.h +const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection -volatile uint8_t AccessPointEnabled = true; //Set to either true/false to enable direct wifi access point -std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h -std::string password = WIFI_PASSWORD; // Set in USER_SECRETS.h -const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface -const char* passwordAP = AP_PASSWORD; // Set in USER_SECRETS.h -const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection - -#ifdef WIFICONFIG -// Set your Static IP address -IPAddress local_IP(192, 168, 10, 150); -// Set your Gateway IP address -IPAddress gateway(192, 168, 10, 1); -// Set your Subnet IP address -IPAddress subnet(255, 255, 255, 0); -#endif #ifdef WEBSERVER const char* http_username = HTTP_USERNAME; // Set in USER_SECRETS.h const char* http_password = HTTP_PASSWORD; // Set in USER_SECRETS.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); #endif // WEBSERVER + // MQTT #ifdef MQTT const char* mqtt_user = MQTT_USER; // Set in USER_SECRETS.h @@ -55,7 +48,6 @@ const char* mqtt_device_name = "Battery Emulator"; // Custom device name in Home Assistant. Previously, the name was automatically set to "BatteryEmulator_esp32-XXXXXX" #endif // MQTT_MANUAL_TOPIC_OBJECT_NAME #endif // USE_MQTT -#endif // WIFI #ifdef EQUIPMENT_STOP_BUTTON // Equipment stop button behavior. Use NC button for safety reasons. diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index a73799c50..a541950be 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -3,7 +3,7 @@ #include #include -/* This file contains all the battery/inverter protocol settings Battery-Emulator software */ +/* This file contains all sthe 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*/ @@ -77,20 +77,17 @@ //#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 -#ifdef CANFD_ADDON // CANFD_ADDON additional options if enabled #define CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ \ - ACAN2517FDSettings:: \ - OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency? (Default OSC_40MHz) -#endif // CANFD_ADDON + 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 //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) #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 WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future. +#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/battery settings set below) +#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) //#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery @@ -107,12 +104,9 @@ /* 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 -/* Event options*/ -#define DUMMY_EVENT_ENABLED false //Enable this line to have a dummy event that gets logged to test the interface - /* 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 +#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging /* Battery settings */ // Predefined total energy capacity of the battery in Watt-hours @@ -138,8 +132,8 @@ // 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 unless you are sure what you are doing */ -/* Only change battery specific settings in "USER_SETTINGS.h" */ +/* Do not change any code below this line */ +/* Only change battery specific settings above and in "USER_SETTINGS.cpp" */ typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CANFD_ADDON_MCP2518 = 3 } CAN_Interface; typedef struct { CAN_Interface battery; @@ -169,9 +163,7 @@ extern volatile STOP_BUTTON_BEHAVIOR equipment_stop_behavior; #ifdef WIFICONFIG extern IPAddress local_IP; -// Set your Gateway IP address extern IPAddress gateway; -// Set your Subnet IP address extern IPAddress subnet; #endif diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 3dba4b724..7ebcc9c3b 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -29,12 +29,8 @@ static bool connected_once = false; void init_WiFi() { #ifdef WIFIAP - if (AccessPointEnabled) { - WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection - init_WiFi_AP(); - } else { - WiFi.mode(WIFI_STA); // Only Router connection - } + WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection + init_WiFi_AP(); #else WiFi.mode(WIFI_STA); // Only Router connection #endif // WIFIAP From 24baf4199449e533e62da334756bea20eafe9a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 24 Dec 2024 00:31:13 +0200 Subject: [PATCH 113/225] fix order of includes --- Software/Software.ino | 2 +- Software/USER_SETTINGS.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index ce84181b1..2cbecee87 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -1,5 +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 "src/include.h" #include "HardwareSerial.h" #include "USER_SECRETS.h" #include "USER_SETTINGS.h" @@ -19,7 +20,6 @@ #include "src/devboard/utils/led_handler.h" #include "src/devboard/utils/logging.h" #include "src/devboard/utils/value_mapping.h" -#include "src/include.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "src/lib/bblanchon-ArduinoJson/ArduinoJson.h" diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index a541950be..248332fa7 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -3,7 +3,7 @@ #include #include -/* This file contains all sthe battery/inverter protocol settings Battery-Emulator software */ +/* 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*/ @@ -106,7 +106,7 @@ /* 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 +//#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging /* Battery settings */ // Predefined total energy capacity of the battery in Watt-hours From 0199d01287e44d6aa2ba9c42f684cf4cdc8f3ae0 Mon Sep 17 00:00:00 2001 From: lenvm Date: Tue, 24 Dec 2024 22:07:10 +0100 Subject: [PATCH 114/225] make MCP2515 and MCP2518FD unique, such that they can be used simultaneously --- Software/src/communication/can/comm_can.cpp | 56 +++++++++++---------- Software/src/devboard/utils/events.cpp | 8 +-- Software/src/devboard/utils/events.h | 4 +- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index 8fa2ab3d9..b9aa22597 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -9,11 +9,13 @@ volatile bool send_ok = 0; #ifdef CAN_ADDON static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h -ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT); +SPIClass SPI2515; +ACAN2515 can(MCP2515_CS, SPI2515, MCP2515_INT); static ACAN2515_Buffer16 gBuffer; #endif //CAN_ADDON #ifdef CANFD_ADDON -ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); +SPIClass SPI2517; +ACAN2517FD canfd(MCP2517_CS, SPI2517, MCP2517_INT); #endif //CANFD_ADDON // Initialization functions @@ -39,20 +41,20 @@ void init_CAN() { logging.println("Dual CAN Bus (ESP32+MCP2515) selected"); #endif // DEBUG_LOG gBuffer.initWithSize(25); - SPI.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); - ACAN2515Settings settings(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s - settings.mRequestedMode = ACAN2515Settings::NormalMode; - const uint16_t errorCodeMCP = can.begin(settings, [] { can.isr(); }); - if (errorCodeMCP == 0) { + SPI2515.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); + ACAN2515Settings settings2515(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s + settings2515.mRequestedMode = ACAN2515Settings::NormalMode; + const uint16_t errorCode2515 = can.begin(settings2515, [] { can.isr(); }); + if (errorCode2515 == 0) { #ifdef DEBUG_LOG logging.println("Can ok"); #endif // DEBUG_LOG } else { #ifdef DEBUG_LOG logging.print("Error Can: 0x"); - logging.println(errorCodeMCP, HEX); + logging.println(errorCode2515, HEX); #endif // DEBUG_LOG - set_event(EVENT_CANMCP_INIT_FAILURE, (uint8_t)errorCodeMCP); + set_event(EVENT_CANMCP2515_INIT_FAILURE, (uint8_t)errorCode2515); } #endif // CAN_ADDON @@ -60,41 +62,41 @@ void init_CAN() { #ifdef DEBUG_LOG logging.println("CAN FD add-on (ESP32+MCP2517) selected"); #endif // DEBUG_LOG - SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); - ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, - DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s + SPI2517.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); + ACAN2517FDSettings settings2517(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, + DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN - settings.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD -#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN - settings.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD -#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN - const uint32_t errorCode = canfd.begin(settings, [] { canfd.isr(); }); + settings2517.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD +#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN + settings2517.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD +#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN + const uint32_t errorCode2517 = canfd.begin(settings2517, [] { canfd.isr(); }); canfd.poll(); - if (errorCode == 0) { + if (errorCode2517 == 0) { #ifdef DEBUG_LOG logging.print("Bit Rate prescaler: "); - logging.println(settings.mBitRatePrescaler); + logging.println(settings2517.mBitRatePrescaler); logging.print("Arbitration Phase segment 1: "); - logging.print(settings.mArbitrationPhaseSegment1); + logging.print(settings2517.mArbitrationPhaseSegment1); logging.print(" segment 2: "); - logging.print(settings.mArbitrationPhaseSegment2); + logging.print(settings2517.mArbitrationPhaseSegment2); logging.print(" SJW: "); - logging.println(settings.mArbitrationSJW); + logging.println(settings2517.mArbitrationSJW); logging.print("Actual Arbitration Bit Rate: "); - logging.print(settings.actualArbitrationBitRate()); + logging.print(settings2517.actualArbitrationBitRate()); logging.print(" bit/s"); logging.print(" (Exact:"); - logging.println(settings.exactArbitrationBitRate() ? "yes)" : "no)"); + logging.println(settings2517.exactArbitrationBitRate() ? "yes)" : "no)"); logging.print("Arbitration Sample point: "); - logging.print(settings.arbitrationSamplePointFromBitStart()); + logging.print(settings2517.arbitrationSamplePointFromBitStart()); logging.println("%"); #endif // DEBUG_LOG } else { #ifdef DEBUG_LOG logging.print("CAN-FD Configuration error 0x"); - logging.println(errorCode, HEX); + logging.println(errorCode2517, HEX); #endif // DEBUG_LOG - set_event(EVENT_CANFD_INIT_FAILURE, (uint8_t)errorCode); + set_event(EVENT_CANMCP2517FD_INIT_FAILURE, (uint8_t)errorCode2517); } #endif // CANFD_ADDON } diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 021b1660a..88546af3f 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -140,8 +140,8 @@ void init_events(void) { events.entries[i].MQTTpublished = false; // Not published by default } - events.entries[EVENT_CANFD_INIT_FAILURE].level = EVENT_LEVEL_WARNING; - events.entries[EVENT_CANMCP_INIT_FAILURE].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_CANMCP2517FD_INIT_FAILURE].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_CANMCP2515_INIT_FAILURE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANFD_BUFFER_FULL].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CAN_OVERRUN].level = EVENT_LEVEL_INFO; events.entries[EVENT_CANFD_RX_OVERRUN].level = EVENT_LEVEL_WARNING; @@ -264,9 +264,9 @@ void set_event_MQTTpublished(EVENTS_ENUM_TYPE event) { const char* get_event_message_string(EVENTS_ENUM_TYPE event) { switch (event) { - case EVENT_CANFD_INIT_FAILURE: + case EVENT_CANMCP2517FD_INIT_FAILURE: return "CAN-FD initialization failed. Check hardware or bitrate settings"; - case EVENT_CANMCP_INIT_FAILURE: + case EVENT_CANMCP2515_INIT_FAILURE: return "CAN-MCP addon initialization failed. Check hardware"; case EVENT_CANFD_BUFFER_FULL: return "CAN-FD buffer overflowed. Some CAN messages were not sent. Contact developers."; diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index d410d66f5..972842fd6 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -26,8 +26,8 @@ */ #define EVENTS_ENUM_TYPE(XX) \ - XX(EVENT_CANFD_INIT_FAILURE) \ - XX(EVENT_CANMCP_INIT_FAILURE) \ + XX(EVENT_CANMCP2517FD_INIT_FAILURE) \ + XX(EVENT_CANMCP2515_INIT_FAILURE) \ XX(EVENT_CANFD_BUFFER_FULL) \ XX(EVENT_CAN_OVERRUN) \ XX(EVENT_CANFD_RX_OVERRUN) \ From 126ab438a7e1fcdd9835a26b0b1eb1d6423c30a9 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 25 Dec 2024 20:14:05 +1300 Subject: [PATCH 115/225] Update TESLA-BATTERY.cpp Change values that hold either a true/false could instead of being defined as: static uint8_t battery_packCtrsOpenNowRequested = 0; Instead be defined as: static bool battery_packCtrsOpenNowRequested = false; --- Software/src/battery/TESLA-BATTERY.cpp | 419 ++++++++++++------------- 1 file changed, 206 insertions(+), 213 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 5ecd958e8..7d372393a 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -37,8 +37,8 @@ static uint16_t battery_energy_to_charge_complete = 0; // kWh static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh static uint16_t battery_expected_energy_remaining = 0; // kWh static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh -static uint8_t battery_full_charge_complete = 0; // kWh -static uint8_t battery_fully_charged = 0; // kWh +static bool battery_full_charge_complete = false; // Changed to bool +static bool battery_fully_charged = false; // Changed to bool static uint16_t battery_ideal_energy_remaining = 0; // kWh static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh static uint16_t battery_nominal_energy_remaining = 0; // kWh @@ -98,46 +98,46 @@ static uint8_t battery_hvil_status = 0; static uint8_t battery_packContNegativeState = 0; static uint8_t battery_packContPositiveState = 0; static uint8_t battery_packContactorSetState = 0; -static uint8_t battery_packCtrsClosingAllowed = 0; -static uint8_t battery_pyroTestInProgress = 0; -static uint8_t battery_packCtrsOpenNowRequested = 0; -static uint8_t battery_packCtrsOpenRequested = 0; +static bool battery_packCtrsClosingAllowed = false; // Change to bool +static bool battery_pyroTestInProgress = false; // Change to bool +static bool battery_packCtrsOpenNowRequested = false; // Change to bool +static bool battery_packCtrsOpenRequested = false; // Change to bool static uint8_t battery_packCtrsRequestStatus = 0; -static uint8_t battery_packCtrsResetRequestRequired = 0; -static uint8_t battery_dcLinkAllowedToEnergize = 0; -static uint8_t battery_fcContNegativeAuxOpen = 0; +static bool battery_packCtrsResetRequestRequired = false; // Change to bool +static bool battery_dcLinkAllowedToEnergize = false; // Change to bool +static bool battery_fcContNegativeAuxOpen = false; // Change to bool static uint8_t battery_fcContNegativeState = 0; -static uint8_t battery_fcContPositiveAuxOpen = 0; +static bool battery_fcContPositiveAuxOpen = false; // Change to bool static uint8_t battery_fcContPositiveState = 0; static uint8_t battery_fcContactorSetState = 0; -static uint8_t battery_fcCtrsClosingAllowed = 0; -static uint8_t battery_fcCtrsOpenNowRequested = 0; -static uint8_t battery_fcCtrsOpenRequested = 0; +static bool battery_fcCtrsClosingAllowed = false; // Change to bool +static bool battery_fcCtrsOpenNowRequested = false; // Change to bool +static bool battery_fcCtrsOpenRequested = false; // Change to bool static uint8_t battery_fcCtrsRequestStatus = 0; -static uint8_t battery_fcCtrsResetRequestRequired = 0; -static uint8_t battery_fcLinkAllowedToEnergize = 0; +static bool battery_fcCtrsResetRequestRequired = false; // Change to bool +static bool battery_fcLinkAllowedToEnergize = false; // Change to bool //0x212: 530 BMS_status -static uint8_t battery_BMS_hvacPowerRequest = 0; -static uint8_t battery_BMS_notEnoughPowerForDrive = 0; -static uint8_t battery_BMS_notEnoughPowerForSupport = 0; -static uint8_t battery_BMS_preconditionAllowed = 0; -static uint8_t battery_BMS_updateAllowed = 0; -static uint8_t battery_BMS_activeHeatingWorthwhile = 0; -static uint8_t battery_BMS_cpMiaOnHvs = 0; +static bool battery_BMS_hvacPowerRequest = false; //Change to bool +static bool battery_BMS_notEnoughPowerForDrive = false; //Change to bool +static bool battery_BMS_notEnoughPowerForSupport = false; //Change to bool +static bool battery_BMS_preconditionAllowed = false; //Change to bool +static bool battery_BMS_updateAllowed = false; //Change to bool +static bool battery_BMS_activeHeatingWorthwhile = false; //Change to bool +static bool battery_BMS_cpMiaOnHvs = false; //Change to bool static uint8_t battery_BMS_contactorState = 0; static uint8_t battery_BMS_state = 0; static uint8_t battery_BMS_hvState = 0; static uint16_t battery_BMS_isolationResistance = 0; -static uint8_t battery_BMS_chargeRequest = 0; -static uint8_t battery_BMS_keepWarmRequest = 0; +static bool battery_BMS_chargeRequest = false; //Change to bool +static bool battery_BMS_keepWarmRequest = false; //Change to bool static uint8_t battery_BMS_uiChargeStatus = 0; -static uint8_t battery_BMS_diLimpRequest = 0; -static uint8_t battery_BMS_okToShipByAir = 0; -static uint8_t battery_BMS_okToShipByLand = 0; +static bool battery_BMS_diLimpRequest = false; //Change to bool +static bool battery_BMS_okToShipByAir = false; //Change to bool +static bool battery_BMS_okToShipByLand = false; //Change to bool static uint32_t battery_BMS_chgPowerAvailable = 0; static uint8_t battery_BMS_chargeRetryCount = 0; -static uint8_t battery_BMS_pcsPwmEnabled = 0; -static uint8_t battery_BMS_ecuLogUploadRequest = 0; +static bool battery_BMS_pcsPwmEnabled = false; //Change to bool +static bool battery_BMS_ecuLogUploadRequest = false; //Change to bool static uint8_t battery_BMS_minPackTemperature = 0; // 0x224:548 PCS_dcdcStatus static uint8_t battery_PCS_dcdcPrechargeStatus = 0; @@ -145,8 +145,8 @@ static uint8_t battery_PCS_dcdc12VSupportStatus = 0; static uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0; static uint16_t battery_PCS_dcdcMainState = 0; static uint8_t battery_PCS_dcdcSubState = 0; -static uint8_t battery_PCS_dcdcFaulted = 0; -static uint8_t battery_PCS_dcdcOutputIsLimited = 0; +static bool battery_PCS_dcdcFaulted = false; //Change to bool +static bool battery_PCS_dcdcOutputIsLimited = false; //Change to bool static uint32_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0; static uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0; static uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0; @@ -196,38 +196,38 @@ static uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0; static uint32_t PCS_dcdc12vSupportLifetimekWh = 0; //0x7AA: //1962 HVP_debugMessage: static uint8_t HVP_debugMessageMultiplexer = 0; -static uint8_t HVP_gpioPassivePyroDepl = 0; -static uint8_t HVP_gpioPyroIsoEn = 0; -static uint8_t HVP_gpioCpFaultIn = 0; -static uint8_t HVP_gpioPackContPowerEn = 0; -static uint8_t HVP_gpioHvCablesOk = 0; -static uint8_t HVP_gpioHvpSelfEnable = 0; -static uint8_t HVP_gpioLed = 0; -static uint8_t HVP_gpioCrashSignal = 0; -static uint8_t HVP_gpioShuntDataReady = 0; -static uint8_t HVP_gpioFcContPosAux = 0; -static uint8_t HVP_gpioFcContNegAux = 0; -static uint8_t HVP_gpioBmsEout = 0; -static uint8_t HVP_gpioCpFaultOut = 0; -static uint8_t HVP_gpioPyroPor = 0; -static uint8_t HVP_gpioShuntEn = 0; -static uint8_t HVP_gpioHvpVerEn = 0; -static uint8_t HVP_gpioPackCoontPosFlywheel = 0; -static uint8_t HVP_gpioCpLatchEnable = 0; -static uint8_t HVP_gpioPcsEnable = 0; -static uint8_t HVP_gpioPcsDcdcPwmEnable = 0; -static uint8_t HVP_gpioPcsChargePwmEnable = 0; -static uint8_t HVP_gpioFcContPowerEnable = 0; -static uint8_t HVP_gpioHvilEnable = 0; -static uint8_t HVP_gpioSecDrdy = 0; +static bool HVP_gpioPassivePyroDepl = false; //Change to bool +static bool HVP_gpioPyroIsoEn = false; //Change to bool +static bool HVP_gpioCpFaultIn = false; //Change to bool +static bool HVP_gpioPackContPowerEn = false; //Change to bool +static bool HVP_gpioHvCablesOk = false; //Change to bool +static bool HVP_gpioHvpSelfEnable = false; //Change to bool +static bool HVP_gpioLed = false; //Change to bool +static bool HVP_gpioCrashSignal = false; //Change to bool +static bool HVP_gpioShuntDataReady = false; //Change to bool +static bool HVP_gpioFcContPosAux = false; //Change to bool +static bool HVP_gpioFcContNegAux = false; //Change to bool +static bool HVP_gpioBmsEout = false; //Change to bool +static bool HVP_gpioCpFaultOut = false; //Change to bool +static bool HVP_gpioPyroPor = false; //Change to bool +static bool HVP_gpioShuntEn = false; //Change to bool +static bool HVP_gpioHvpVerEn = false; //Change to bool +static bool HVP_gpioPackCoontPosFlywheel = false; //Change to bool +static bool HVP_gpioCpLatchEnable = false; //Change to bool +static bool HVP_gpioPcsEnable = false; //Change to bool +static bool HVP_gpioPcsDcdcPwmEnable = false; //Change to bool +static bool HVP_gpioPcsChargePwmEnable = false; //Change to bool +static bool HVP_gpioFcContPowerEnable = false; //Change to bool +static bool HVP_gpioHvilEnable = false; //Change to bool +static bool HVP_gpioSecDrdy = false; //Change to bool static uint16_t HVP_hvp1v5Ref = 0; static int16_t HVP_shuntCurrentDebug = 0; -static uint8_t HVP_packCurrentMia = 0; -static uint8_t HVP_auxCurrentMia = 0; -static uint8_t HVP_currentSenseMia = 0; -static uint8_t HVP_shuntRefVoltageMismatch = 0; -static uint8_t HVP_shuntThermistorMia = 0; -static uint8_t HVP_shuntHwMia = 0; +static bool HVP_packCurrentMia = false; //Change to bool +static bool HVP_auxCurrentMia = false; //Change to bool +static bool HVP_currentSenseMia =false; //Change to bool +static bool HVP_shuntRefVoltageMismatch = false; //Change to bool +static bool HVP_shuntThermistorMia = false; //Change to bool +static bool HVP_shuntHwMia = false; //Change to bool static int16_t HVP_dcLinkVoltage = 0; static int16_t HVP_packVoltage = 0; static int16_t HVP_fcLinkVoltage = 0; @@ -252,159 +252,152 @@ static int16_t HVP_shuntAsicTempDbg = 0; static uint8_t HVP_shuntAuxCurrentStatus = 0; static uint8_t HVP_shuntBarTempStatus = 0; static uint8_t HVP_shuntAsicTempStatus = 0; -//0x3aa: HVP_alertMatrix1 Fault codes -static uint8_t battery_WatchdogReset = 0; //Warns if the processor has experienced a reset due to watchdog reset. -static uint8_t battery_PowerLossReset = 0; //Warns if the processor has experienced a reset due to power loss. -static uint8_t battery_SwAssertion = 0; //An internal software assertion has failed. -static uint8_t battery_CrashEvent = 0; //Warns if the crash signal is detected by HVP -static uint8_t battery_OverDchgCurrentFault = 0; //Warns if the pack discharge is above max discharge current limit -static uint8_t battery_OverChargeCurrentFault = - 0; //Warns if the pack discharge current is above max charge current limit -static uint8_t battery_OverCurrentFault = - 0; //Warns if the pack current (discharge or charge) is above max current limit. -static uint8_t battery_OverTemperatureFault = 0; //A pack module temperature is above maximum temperature limit -static uint8_t battery_OverVoltageFault = 0; //A brick voltage is above maximum voltage limit -static uint8_t battery_UnderVoltageFault = 0; //A brick voltage is below minimum voltage limit -static uint8_t battery_PrimaryBmbMiaFault = - 0; //Warns if the voltage and temperature readings from primary BMB chain are mia -static uint8_t battery_SecondaryBmbMiaFault = - 0; //Warns if the voltage and temperature readings from secondary BMB chain are mia -static uint8_t battery_BmbMismatchFault = - 0; //Warns if the primary and secondary BMB chain readings don't match with each other -static uint8_t battery_BmsHviMiaFault = 0; //Warns if the BMS node is mia on HVS or HVI CAN -static uint8_t battery_CpMiaFault = 0; //Warns if the CP node is mia on HVS CAN -static uint8_t battery_PcsMiaFault = 0; //The PCS node is mia on HVS CAN -static uint8_t battery_BmsFault = 0; //Warns if the BMS ECU has faulted -static uint8_t battery_PcsFault = 0; //Warns if the PCS ECU has faulted -static uint8_t battery_CpFault = 0; //Warns if the CP ECU has faulted -static uint8_t battery_ShuntHwMiaFault = 0; //Warns if the shunt current reading is not available -static uint8_t battery_PyroMiaFault = 0; //Warns if the pyro squib is not connected -static uint8_t battery_hvsMiaFault = 0; //Warns if the pack contactor hw fault -static uint8_t battery_hviMiaFault = 0; //Warns if the FC contactor hw fault -static uint8_t battery_Supply12vFault = 0; //Warns if the low voltage (12V) battery is below minimum voltage threshold -static uint8_t battery_VerSupplyFault = - 0; //Warns if the Energy reserve voltage supply is below minimum voltage threshold -static uint8_t battery_HvilFault = 0; //Warn if a High Voltage Inter Lock fault is detected -static uint8_t battery_BmsHvsMiaFault = 0; //Warns if the BMS node is mia on HVS or HVI CAN -static uint8_t battery_PackVoltMismatchFault = - 0; //Warns if the pack voltage doesn't match approximately with sum of brick voltages -static uint8_t battery_EnsMiaFault = 0; //Warns if the ENS line is not connected to HVC -static uint8_t battery_PackPosCtrArcFault = 0; //Warns if the HVP detectes series arc at pack contactor -static uint8_t battery_packNegCtrArcFault = 0; //Warns if the HVP detectes series arc at FC contactor -static uint8_t battery_ShuntHwAndBmsMiaFault = 0; -static uint8_t battery_fcContHwFault = 0; -static uint8_t battery_robinOverVoltageFault = 0; -static uint8_t battery_packContHwFault = 0; -static uint8_t battery_pyroFuseBlown = 0; -static uint8_t battery_pyroFuseFailedToBlow = 0; -static uint8_t battery_CpilFault = 0; -static uint8_t battery_PackContactorFellOpen = 0; -static uint8_t battery_FcContactorFellOpen = 0; -static uint8_t battery_packCtrCloseBlocked = 0; -static uint8_t battery_fcCtrCloseBlocked = 0; -static uint8_t battery_packContactorForceOpen = 0; -static uint8_t battery_fcContactorForceOpen = 0; -static uint8_t battery_dcLinkOverVoltage = 0; -static uint8_t battery_shuntOverTemperature = 0; -static uint8_t battery_passivePyroDeploy = 0; -static uint8_t battery_logUploadRequest = 0; -static uint8_t battery_packCtrCloseFailed = 0; -static uint8_t battery_fcCtrCloseFailed = 0; -static uint8_t battery_shuntThermistorMia = 0; +//0x3aa: HVP_alertMatrix1 Fault codes // Change to bool +static bool battery_WatchdogReset = false; //Warns if the processor has experienced a reset due to watchdog reset. +static bool battery_PowerLossReset = false; //Warns if the processor has experienced a reset due to power loss. +static bool battery_SwAssertion = false; //An internal software assertion has failed. +static bool battery_CrashEvent = false; //Warns if the crash signal is detected by HVP +static bool battery_OverDchgCurrentFault = false; //Warns if the pack discharge is above max discharge current limit +static bool battery_OverChargeCurrentFault = false; //Warns if the pack discharge current is above max charge current limit +static bool battery_OverCurrentFault = false; //Warns if the pack current (discharge or charge) is above max current limit. +static bool battery_OverTemperatureFault = false; //A pack module temperature is above maximum temperature limit +static bool battery_OverVoltageFault = false; //A brick voltage is above maximum voltage limit +static bool battery_UnderVoltageFault = false; //A brick voltage is below minimum voltage limit +static bool battery_PrimaryBmbMiaFault = false; //Warns if the voltage and temperature readings from primary BMB chain are mia +static bool battery_SecondaryBmbMiaFault = false; //Warns if the voltage and temperature readings from secondary BMB chain are mia +static bool battery_BmbMismatchFault = false; //Warns if the primary and secondary BMB chain readings don't match with each other +static bool battery_BmsHviMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN +static bool battery_CpMiaFault = false; //Warns if the CP node is mia on HVS CAN +static bool battery_PcsMiaFault = false; //The PCS node is mia on HVS CAN +static bool battery_BmsFault = false; //Warns if the BMS ECU has faulted +static bool battery_PcsFault = false; //Warns if the PCS ECU has faulted +static bool battery_CpFault = false; //Warns if the CP ECU has faulted +static bool battery_ShuntHwMiaFault = false; //Warns if the shunt current reading is not available +static bool battery_PyroMiaFault = false; //Warns if the pyro squib is not connected +static bool battery_hvsMiaFault = false; //Warns if the pack contactor hw fault +static bool battery_hviMiaFault = false; //Warns if the FC contactor hw fault +static bool battery_Supply12vFault = false; //Warns if the low voltage (12V) battery is below minimum voltage threshold +static bool battery_VerSupplyFault = false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold +static bool battery_HvilFault = false; //Warn if a High Voltage Inter Lock fault is detected +static bool battery_BmsHvsMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN +static bool battery_PackVoltMismatchFault = false; //Warns if the pack voltage doesn't match approximately with sum of brick voltages +static bool battery_EnsMiaFault = false; //Warns if the ENS line is not connected to HVC +static bool battery_PackPosCtrArcFault = false; //Warns if the HVP detectes series arc at pack contactor +static bool battery_packNegCtrArcFault = false; //Warns if the HVP detectes series arc at FC contactor +static bool battery_ShuntHwAndBmsMiaFault = false; +static bool battery_fcContHwFault = false; +static bool battery_robinOverVoltageFault = false; +static bool battery_packContHwFault = false; +static bool battery_pyroFuseBlown = false; +static bool battery_pyroFuseFailedToBlow = false; +static bool battery_CpilFault = false; +static bool battery_PackContactorFellOpen = false; +static bool battery_FcContactorFellOpen = false; +static bool battery_packCtrCloseBlocked = false; +static bool battery_fcCtrCloseBlocked = false; +static bool battery_packContactorForceOpen = false; +static bool battery_fcContactorForceOpen = false; +static bool battery_dcLinkOverVoltage = false; +static bool battery_shuntOverTemperature = false; +static bool battery_passivePyroDeploy = false; +static bool battery_logUploadRequest = false; +static bool battery_packCtrCloseFailed = false; +static bool battery_fcCtrCloseFailed = false; +static bool battery_shuntThermistorMia = false; //0x320: 800 BMS_alertMatrix -static uint8_t battery_BMS_matrixIndex = 4; -static uint8_t battery_BMS_a061_robinBrickOverVoltage = 1; -static uint8_t battery_BMS_a062_SW_BrickV_Imbalance = 1; -static uint8_t battery_BMS_a063_SW_ChargePort_Fault = 1; -static uint8_t battery_BMS_a064_SW_SOC_Imbalance = 1; -static uint8_t battery_BMS_a127_SW_shunt_SNA = 1; -static uint8_t battery_BMS_a128_SW_shunt_MIA = 1; -static uint8_t battery_BMS_a069_SW_Low_Power = 1; -static uint8_t battery_BMS_a130_IO_CAN_Error = 1; -static uint8_t battery_BMS_a071_SW_SM_TransCon_Not_Met = 1; -static uint8_t battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = 1; -static uint8_t battery_BMS_a134_SW_Delayed_Ctr_Off = 1; -static uint8_t battery_BMS_a075_SW_Chg_Disable_Failure = 1; -static uint8_t battery_BMS_a076_SW_Dch_While_Charging = 1; -static uint8_t battery_BMS_a017_SW_Brick_OV = 1; -static uint8_t battery_BMS_a018_SW_Brick_UV = 1; -static uint8_t battery_BMS_a019_SW_Module_OT = 1; -static uint8_t battery_BMS_a021_SW_Dr_Limits_Regulation = 1; -static uint8_t battery_BMS_a022_SW_Over_Current = 1; -static uint8_t battery_BMS_a023_SW_Stack_OV = 1; -static uint8_t battery_BMS_a024_SW_Islanded_Brick = 1; -static uint8_t battery_BMS_a025_SW_PwrBalance_Anomaly = 1; -static uint8_t battery_BMS_a026_SW_HFCurrent_Anomaly = 1; -static uint8_t battery_BMS_a087_SW_Feim_Test_Blocked = 1; -static uint8_t battery_BMS_a088_SW_VcFront_MIA_InDrive = 1; -static uint8_t battery_BMS_a089_SW_VcFront_MIA = 1; -static uint8_t battery_BMS_a090_SW_Gateway_MIA = 1; -static uint8_t battery_BMS_a091_SW_ChargePort_MIA = 1; -static uint8_t battery_BMS_a092_SW_ChargePort_Mia_On_Hv = 1; -static uint8_t battery_BMS_a034_SW_Passive_Isolation = 1; -static uint8_t battery_BMS_a035_SW_Isolation = 1; -static uint8_t battery_BMS_a036_SW_HvpHvilFault = 1; -static uint8_t battery_BMS_a037_SW_Flood_Port_Open = 1; -static uint8_t battery_BMS_a158_SW_HVP_HVI_Comms = 1; -static uint8_t battery_BMS_a039_SW_DC_Link_Over_Voltage = 1; -static uint8_t battery_BMS_a041_SW_Power_On_Reset = 1; -static uint8_t battery_BMS_a042_SW_MPU_Error = 1; -static uint8_t battery_BMS_a043_SW_Watch_Dog_Reset = 1; -static uint8_t battery_BMS_a044_SW_Assertion = 1; -static uint8_t battery_BMS_a045_SW_Exception = 1; -static uint8_t battery_BMS_a046_SW_Task_Stack_Usage = 1; -static uint8_t battery_BMS_a047_SW_Task_Stack_Overflow = 1; -static uint8_t battery_BMS_a048_SW_Log_Upload_Request = 1; -static uint8_t battery_BMS_a169_SW_FC_Pack_Weld = 1; -static uint8_t battery_BMS_a050_SW_Brick_Voltage_MIA = 1; -static uint8_t battery_BMS_a051_SW_HVC_Vref_Bad = 1; -static uint8_t battery_BMS_a052_SW_PCS_MIA = 1; -static uint8_t battery_BMS_a053_SW_ThermalModel_Sanity = 1; -static uint8_t battery_BMS_a054_SW_Ver_Supply_Fault = 1; -static uint8_t battery_BMS_a176_SW_GracefulPowerOff = 1; -static uint8_t battery_BMS_a059_SW_Pack_Voltage_Sensing = 1; -static uint8_t battery_BMS_a060_SW_Leakage_Test_Failure = 1; -static uint8_t battery_BMS_a077_SW_Charger_Regulation = 1; -static uint8_t battery_BMS_a081_SW_Ctr_Close_Blocked = 1; -static uint8_t battery_BMS_a082_SW_Ctr_Force_Open = 1; -static uint8_t battery_BMS_a083_SW_Ctr_Close_Failure = 1; -static uint8_t battery_BMS_a084_SW_Sleep_Wake_Aborted = 1; -static uint8_t battery_BMS_a094_SW_Drive_Inverter_MIA = 1; -static uint8_t battery_BMS_a099_SW_BMB_Communication = 1; -static uint8_t battery_BMS_a105_SW_One_Module_Tsense = 1; -static uint8_t battery_BMS_a106_SW_All_Module_Tsense = 1; -static uint8_t battery_BMS_a107_SW_Stack_Voltage_MIA = 1; -static uint8_t battery_BMS_a121_SW_NVRAM_Config_Error = 1; -static uint8_t battery_BMS_a122_SW_BMS_Therm_Irrational = 1; -static uint8_t battery_BMS_a123_SW_Internal_Isolation = 1; -static uint8_t battery_BMS_a129_SW_VSH_Failure = 1; -static uint8_t battery_BMS_a131_Bleed_FET_Failure = 1; -static uint8_t battery_BMS_a136_SW_Module_OT_Warning = 1; -static uint8_t battery_BMS_a137_SW_Brick_UV_Warning = 1; -static uint8_t battery_BMS_a138_SW_Brick_OV_Warning = 1; -static uint8_t battery_BMS_a139_SW_DC_Link_V_Irrational = 1; -static uint8_t battery_BMS_a141_SW_BMB_Status_Warning = 1; -static uint8_t battery_BMS_a144_Hvp_Config_Mismatch = 1; -static uint8_t battery_BMS_a145_SW_SOC_Change = 1; -static uint8_t battery_BMS_a146_SW_Brick_Overdischarged = 1; -static uint8_t battery_BMS_a149_SW_Missing_Config_Block = 1; -static uint8_t battery_BMS_a151_SW_external_isolation = 1; -static uint8_t battery_BMS_a156_SW_BMB_Vref_bad = 1; -static uint8_t battery_BMS_a157_SW_HVP_HVS_Comms = 1; -static uint8_t battery_BMS_a159_SW_HVP_ECU_Error = 1; -static uint8_t battery_BMS_a161_SW_DI_Open_Request = 1; -static uint8_t battery_BMS_a162_SW_No_Power_For_Support = 1; -static uint8_t battery_BMS_a163_SW_Contactor_Mismatch = 1; -static uint8_t battery_BMS_a164_SW_Uncontrolled_Regen = 1; -static uint8_t battery_BMS_a165_SW_Pack_Partial_Weld = 1; -static uint8_t battery_BMS_a166_SW_Pack_Full_Weld = 1; -static uint8_t battery_BMS_a167_SW_FC_Partial_Weld = 1; -static uint8_t battery_BMS_a168_SW_FC_Full_Weld = 1; -static uint8_t battery_BMS_a170_SW_Limp_Mode = 1; -static uint8_t battery_BMS_a171_SW_Stack_Voltage_Sense = 1; -static uint8_t battery_BMS_a174_SW_Charge_Failure = 1; -static uint8_t battery_BMS_a179_SW_Hvp_12V_Fault = 1; -static uint8_t battery_BMS_a180_SW_ECU_reset_blocked = 1; +static uint8_t battery_BMS_matrixIndex = 0; // Changed to bool +static bool battery_BMS_a061_robinBrickOverVoltage = false; +static bool battery_BMS_a062_SW_BrickV_Imbalance = false; +static bool battery_BMS_a063_SW_ChargePort_Fault = false; +static bool battery_BMS_a064_SW_SOC_Imbalance = false; +static bool battery_BMS_a027_SW_shunt_SNA = false; +static bool battery_BMS_a128_SW_shunt_MIA = false; +static bool battery_BMS_a069_SW_Low_Power = false; +static bool battery_BMS_a130_IO_CAN_Error = false; +static bool battery_BMS_a071_SW_SM_TransCon_Not_Met = false; +static bool battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = false; +static bool battery_BMS_a134_SW_Delayed_Ctr_Off = false; +static bool battery_BMS_a075_SW_Chg_Disable_Failure = false; +static bool battery_BMS_a076_SW_Dch_While_Charging = false; +static bool battery_BMS_a017_SW_Brick_OV = false; +static bool battery_BMS_a018_SW_Brick_UV = false; +static bool battery_BMS_a019_SW_Module_OT = false; +static bool battery_BMS_a021_SW_Dr_Limits_Regulation = false; +static bool battery_BMS_a022_SW_Over_Current = false; +static bool battery_BMS_a023_SW_Stack_OV = false; +static bool battery_BMS_a024_SW_Islanded_Brick = false; +static bool battery_BMS_a025_SW_PwrBalance_Anomaly = false; +static bool battery_BMS_a026_SW_HFCurrent_Anomaly = false; +static bool battery_BMS_a087_SW_Feim_Test_Blocked = false; +static bool battery_BMS_a088_SW_VcFront_MIA_InDrive = false; +static bool battery_BMS_a089_SW_VcFront_MIA = false; +static bool battery_BMS_a090_SW_Gateway_MIA = false; +static bool battery_BMS_a091_SW_ChargePort_MIA = false; +static bool battery_BMS_a092_SW_ChargePort_Mia_On_Hv = false; +static bool battery_BMS_a034_SW_Passive_Isolation = false; +static bool battery_BMS_a035_SW_Isolation = false; +static bool battery_BMS_a036_SW_HvpHvilFault = false; +static bool battery_BMS_a037_SW_Flood_Port_Open = false; +static bool battery_BMS_a158_SW_HVP_HVI_Comms = false; +static bool battery_BMS_a039_SW_DC_Link_Over_Voltage = false; +static bool battery_BMS_a041_SW_Power_On_Reset = false; +static bool battery_BMS_a042_SW_MPU_Error = false; +static bool battery_BMS_a043_SW_Watch_Dog_Reset = false; +static bool battery_BMS_a044_SW_Assertion = false; +static bool battery_BMS_a045_SW_Exception = false; +static bool battery_BMS_a046_SW_Task_Stack_Usage = false; +static bool battery_BMS_a047_SW_Task_Stack_Overflow = false; +static bool battery_BMS_a048_SW_Log_Upload_Request = false; +static bool battery_BMS_a169_SW_FC_Pack_Weld = false; +static bool battery_BMS_a050_SW_Brick_Voltage_MIA = false; +static bool battery_BMS_a051_SW_HVC_Vref_Bad = false; +static bool battery_BMS_a052_SW_PCS_MIA = false; +static bool battery_BMS_a053_SW_ThermalModel_Sanity = false; +static bool battery_BMS_a054_SW_Ver_Supply_Fault = false; +static bool battery_BMS_a176_SW_GracefulPowerOff = false; +static bool battery_BMS_a059_SW_Pack_Voltage_Sensing = false; +static bool battery_BMS_a060_SW_Leakage_Test_Failure = false; +static bool battery_BMS_a077_SW_Charger_Regulation = false; +static bool battery_BMS_a081_SW_Ctr_Close_Blocked = false; +static bool battery_BMS_a082_SW_Ctr_Force_Open = false; +static bool battery_BMS_a083_SW_Ctr_Close_Failure = false; +static bool battery_BMS_a084_SW_Sleep_Wake_Aborted = false; +static bool battery_BMS_a094_SW_Drive_Inverter_MIA = false; +static bool battery_BMS_a099_SW_BMB_Communication = false; +static bool battery_BMS_a105_SW_One_Module_Tsense = false; +static bool battery_BMS_a106_SW_All_Module_Tsense = false; +static bool battery_BMS_a107_SW_Stack_Voltage_MIA = false; +static bool battery_BMS_a121_SW_NVRAM_Config_Error = false; +static bool battery_BMS_a122_SW_BMS_Therm_Irrational = false; +static bool battery_BMS_a123_SW_Internal_Isolation = false; +static bool battery_BMS_a129_SW_VSH_Failure = false; +static bool battery_BMS_a131_Bleed_FET_Failure = false; +static bool battery_BMS_a136_SW_Module_OT_Warning = false; +static bool battery_BMS_a137_SW_Brick_UV_Warning = false; +static bool battery_BMS_a138_SW_Brick_OV_Warning = false; +static bool battery_BMS_a139_SW_DC_Link_V_Irrational = false; +static bool battery_BMS_a141_SW_BMB_Status_Warning = false; +static bool battery_BMS_a144_Hvp_Config_Mismatch = false; +static bool battery_BMS_a145_SW_SOC_Change = false; +static bool battery_BMS_a146_SW_Brick_Overdischarged = false; +static bool battery_BMS_a149_SW_Missing_Config_Block = false; +static bool battery_BMS_a151_SW_external_isolation = false; +static bool battery_BMS_a156_SW_BMB_Vref_bad = false; +static bool battery_BMS_a157_SW_HVP_HVS_Comms = false; +static bool battery_BMS_a159_SW_HVP_ECU_Error = false; +static bool battery_BMS_a161_SW_DI_Open_Request = false; +static bool battery_BMS_a162_SW_No_Power_For_Support = false; +static bool battery_BMS_a163_SW_Contactor_Mismatch = false; +static bool battery_BMS_a164_SW_Uncontrolled_Regen = false; +static bool battery_BMS_a165_SW_Pack_Partial_Weld = false; +static bool battery_BMS_a166_SW_Pack_Full_Weld = false; +static bool battery_BMS_a167_SW_FC_Partial_Weld = false; +static bool battery_BMS_a168_SW_FC_Full_Weld = false; +static bool battery_BMS_a170_SW_Limp_Mode = false; +static bool battery_BMS_a171_SW_Stack_Voltage_Sense = false; +static bool battery_BMS_a174_SW_Charge_Failure = false; +static bool battery_BMS_a179_SW_Hvp_12V_Fault = false; +static bool battery_BMS_a180_SW_ECU_reset_blocked = false; #ifdef DOUBLE_BATTERY //need to update for battery2 From 931f99fb3564805e7093f205e300a4f6be5a99b8 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 25 Dec 2024 20:54:16 +1300 Subject: [PATCH 116/225] Update TESLA-BATTERY.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 145 +++++++++++++------------ 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 8c1fe984d..b15b2639b 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -37,8 +37,8 @@ static uint16_t battery_energy_to_charge_complete = 0; // kWh static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh static uint16_t battery_expected_energy_remaining = 0; // kWh static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh -static bool battery_full_charge_complete = false; // Changed to bool -static bool battery_fully_charged = false; // Changed to bool +static bool battery_full_charge_complete = false; // Changed to bool +static bool battery_fully_charged = false; // Changed to bool static uint16_t battery_ideal_energy_remaining = 0; // kWh static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh static uint16_t battery_nominal_energy_remaining = 0; // kWh @@ -98,46 +98,46 @@ static uint8_t battery_hvil_status = 0; static uint8_t battery_packContNegativeState = 0; static uint8_t battery_packContPositiveState = 0; static uint8_t battery_packContactorSetState = 0; -static bool battery_packCtrsClosingAllowed = false; // Change to bool -static bool battery_pyroTestInProgress = false; // Change to bool -static bool battery_packCtrsOpenNowRequested = false; // Change to bool -static bool battery_packCtrsOpenRequested = false; // Change to bool +static bool battery_packCtrsClosingAllowed = false; // Change to bool +static bool battery_pyroTestInProgress = false; // Change to bool +static bool battery_packCtrsOpenNowRequested = false; // Change to bool +static bool battery_packCtrsOpenRequested = false; // Change to bool static uint8_t battery_packCtrsRequestStatus = 0; -static bool battery_packCtrsResetRequestRequired = false; // Change to bool -static bool battery_dcLinkAllowedToEnergize = false; // Change to bool -static bool battery_fcContNegativeAuxOpen = false; // Change to bool +static bool battery_packCtrsResetRequestRequired = false; // Change to bool +static bool battery_dcLinkAllowedToEnergize = false; // Change to bool +static bool battery_fcContNegativeAuxOpen = false; // Change to bool static uint8_t battery_fcContNegativeState = 0; -static bool battery_fcContPositiveAuxOpen = false; // Change to bool +static bool battery_fcContPositiveAuxOpen = false; // Change to bool static uint8_t battery_fcContPositiveState = 0; static uint8_t battery_fcContactorSetState = 0; -static bool battery_fcCtrsClosingAllowed = false; // Change to bool -static bool battery_fcCtrsOpenNowRequested = false; // Change to bool -static bool battery_fcCtrsOpenRequested = false; // Change to bool +static bool battery_fcCtrsClosingAllowed = false; // Change to bool +static bool battery_fcCtrsOpenNowRequested = false; // Change to bool +static bool battery_fcCtrsOpenRequested = false; // Change to bool static uint8_t battery_fcCtrsRequestStatus = 0; -static bool battery_fcCtrsResetRequestRequired = false; // Change to bool -static bool battery_fcLinkAllowedToEnergize = false; // Change to bool +static bool battery_fcCtrsResetRequestRequired = false; // Change to bool +static bool battery_fcLinkAllowedToEnergize = false; // Change to bool //0x212: 530 BMS_status -static bool battery_BMS_hvacPowerRequest = false; //Change to bool -static bool battery_BMS_notEnoughPowerForDrive = false; //Change to bool -static bool battery_BMS_notEnoughPowerForSupport = false; //Change to bool -static bool battery_BMS_preconditionAllowed = false; //Change to bool -static bool battery_BMS_updateAllowed = false; //Change to bool -static bool battery_BMS_activeHeatingWorthwhile = false; //Change to bool -static bool battery_BMS_cpMiaOnHvs = false; //Change to bool +static bool battery_BMS_hvacPowerRequest = false; //Change to bool +static bool battery_BMS_notEnoughPowerForDrive = false; //Change to bool +static bool battery_BMS_notEnoughPowerForSupport = false; //Change to bool +static bool battery_BMS_preconditionAllowed = false; //Change to bool +static bool battery_BMS_updateAllowed = false; //Change to bool +static bool battery_BMS_activeHeatingWorthwhile = false; //Change to bool +static bool battery_BMS_cpMiaOnHvs = false; //Change to bool static uint8_t battery_BMS_contactorState = 0; static uint8_t battery_BMS_state = 0; static uint8_t battery_BMS_hvState = 0; static uint16_t battery_BMS_isolationResistance = 0; -static bool battery_BMS_chargeRequest = false; //Change to bool -static bool battery_BMS_keepWarmRequest = false; //Change to bool +static bool battery_BMS_chargeRequest = false; //Change to bool +static bool battery_BMS_keepWarmRequest = false; //Change to bool static uint8_t battery_BMS_uiChargeStatus = 0; -static bool battery_BMS_diLimpRequest = false; //Change to bool -static bool battery_BMS_okToShipByAir = false; //Change to bool -static bool battery_BMS_okToShipByLand = false; //Change to bool +static bool battery_BMS_diLimpRequest = false; //Change to bool +static bool battery_BMS_okToShipByAir = false; //Change to bool +static bool battery_BMS_okToShipByLand = false; //Change to bool static uint32_t battery_BMS_chgPowerAvailable = 0; static uint8_t battery_BMS_chargeRetryCount = 0; -static bool battery_BMS_pcsPwmEnabled = false; //Change to bool -static bool battery_BMS_ecuLogUploadRequest = false; //Change to bool +static bool battery_BMS_pcsPwmEnabled = false; //Change to bool +static bool battery_BMS_ecuLogUploadRequest = false; //Change to bool static uint8_t battery_BMS_minPackTemperature = 0; // 0x224:548 PCS_dcdcStatus static uint8_t battery_PCS_dcdcPrechargeStatus = 0; @@ -145,7 +145,7 @@ static uint8_t battery_PCS_dcdc12VSupportStatus = 0; static uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0; static uint16_t battery_PCS_dcdcMainState = 0; static uint8_t battery_PCS_dcdcSubState = 0; -static bool battery_PCS_dcdcFaulted = false; //Change to bool +static bool battery_PCS_dcdcFaulted = false; //Change to bool static bool battery_PCS_dcdcOutputIsLimited = false; //Change to bool static uint32_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0; static uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0; @@ -196,38 +196,38 @@ static uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0; static uint32_t PCS_dcdc12vSupportLifetimekWh = 0; //0x7AA: //1962 HVP_debugMessage: static uint8_t HVP_debugMessageMultiplexer = 0; -static bool HVP_gpioPassivePyroDepl = false; //Change to bool -static bool HVP_gpioPyroIsoEn = false; //Change to bool -static bool HVP_gpioCpFaultIn = false; //Change to bool -static bool HVP_gpioPackContPowerEn = false; //Change to bool -static bool HVP_gpioHvCablesOk = false; //Change to bool -static bool HVP_gpioHvpSelfEnable = false; //Change to bool -static bool HVP_gpioLed = false; //Change to bool -static bool HVP_gpioCrashSignal = false; //Change to bool -static bool HVP_gpioShuntDataReady = false; //Change to bool -static bool HVP_gpioFcContPosAux = false; //Change to bool -static bool HVP_gpioFcContNegAux = false; //Change to bool -static bool HVP_gpioBmsEout = false; //Change to bool -static bool HVP_gpioCpFaultOut = false; //Change to bool -static bool HVP_gpioPyroPor = false; //Change to bool -static bool HVP_gpioShuntEn = false; //Change to bool -static bool HVP_gpioHvpVerEn = false; //Change to bool -static bool HVP_gpioPackCoontPosFlywheel = false; //Change to bool -static bool HVP_gpioCpLatchEnable = false; //Change to bool -static bool HVP_gpioPcsEnable = false; //Change to bool -static bool HVP_gpioPcsDcdcPwmEnable = false; //Change to bool -static bool HVP_gpioPcsChargePwmEnable = false; //Change to bool -static bool HVP_gpioFcContPowerEnable = false; //Change to bool -static bool HVP_gpioHvilEnable = false; //Change to bool -static bool HVP_gpioSecDrdy = false; //Change to bool +static bool HVP_gpioPassivePyroDepl = false; //Change to bool +static bool HVP_gpioPyroIsoEn = false; //Change to bool +static bool HVP_gpioCpFaultIn = false; //Change to bool +static bool HVP_gpioPackContPowerEn = false; //Change to bool +static bool HVP_gpioHvCablesOk = false; //Change to bool +static bool HVP_gpioHvpSelfEnable = false; //Change to bool +static bool HVP_gpioLed = false; //Change to bool +static bool HVP_gpioCrashSignal = false; //Change to bool +static bool HVP_gpioShuntDataReady = false; //Change to bool +static bool HVP_gpioFcContPosAux = false; //Change to bool +static bool HVP_gpioFcContNegAux = false; //Change to bool +static bool HVP_gpioBmsEout = false; //Change to bool +static bool HVP_gpioCpFaultOut = false; //Change to bool +static bool HVP_gpioPyroPor = false; //Change to bool +static bool HVP_gpioShuntEn = false; //Change to bool +static bool HVP_gpioHvpVerEn = false; //Change to bool +static bool HVP_gpioPackCoontPosFlywheel = false; //Change to bool +static bool HVP_gpioCpLatchEnable = false; //Change to bool +static bool HVP_gpioPcsEnable = false; //Change to bool +static bool HVP_gpioPcsDcdcPwmEnable = false; //Change to bool +static bool HVP_gpioPcsChargePwmEnable = false; //Change to bool +static bool HVP_gpioFcContPowerEnable = false; //Change to bool +static bool HVP_gpioHvilEnable = false; //Change to bool +static bool HVP_gpioSecDrdy = false; //Change to bool static uint16_t HVP_hvp1v5Ref = 0; static int16_t HVP_shuntCurrentDebug = 0; -static bool HVP_packCurrentMia = false; //Change to bool -static bool HVP_auxCurrentMia = false; //Change to bool -static bool HVP_currentSenseMia =false; //Change to bool -static bool HVP_shuntRefVoltageMismatch = false; //Change to bool -static bool HVP_shuntThermistorMia = false; //Change to bool -static bool HVP_shuntHwMia = false; //Change to bool +static bool HVP_packCurrentMia = false; //Change to bool +static bool HVP_auxCurrentMia = false; //Change to bool +static bool HVP_currentSenseMia = false; //Change to bool +static bool HVP_shuntRefVoltageMismatch = false; //Change to bool +static bool HVP_shuntThermistorMia = false; //Change to bool +static bool HVP_shuntHwMia = false; //Change to bool static int16_t HVP_dcLinkVoltage = 0; static int16_t HVP_packVoltage = 0; static int16_t HVP_fcLinkVoltage = 0; @@ -258,14 +258,19 @@ static bool battery_PowerLossReset = false; //Warns if the processor has experi static bool battery_SwAssertion = false; //An internal software assertion has failed. static bool battery_CrashEvent = false; //Warns if the crash signal is detected by HVP static bool battery_OverDchgCurrentFault = false; //Warns if the pack discharge is above max discharge current limit -static bool battery_OverChargeCurrentFault = false; //Warns if the pack discharge current is above max charge current limit -static bool battery_OverCurrentFault = false; //Warns if the pack current (discharge or charge) is above max current limit. +static bool battery_OverChargeCurrentFault = + false; //Warns if the pack discharge current is above max charge current limit +static bool battery_OverCurrentFault = + false; //Warns if the pack current (discharge or charge) is above max current limit. static bool battery_OverTemperatureFault = false; //A pack module temperature is above maximum temperature limit static bool battery_OverVoltageFault = false; //A brick voltage is above maximum voltage limit static bool battery_UnderVoltageFault = false; //A brick voltage is below minimum voltage limit -static bool battery_PrimaryBmbMiaFault = false; //Warns if the voltage and temperature readings from primary BMB chain are mia -static bool battery_SecondaryBmbMiaFault = false; //Warns if the voltage and temperature readings from secondary BMB chain are mia -static bool battery_BmbMismatchFault = false; //Warns if the primary and secondary BMB chain readings don't match with each other +static bool battery_PrimaryBmbMiaFault = + false; //Warns if the voltage and temperature readings from primary BMB chain are mia +static bool battery_SecondaryBmbMiaFault = + false; //Warns if the voltage and temperature readings from secondary BMB chain are mia +static bool battery_BmbMismatchFault = + false; //Warns if the primary and secondary BMB chain readings don't match with each other static bool battery_BmsHviMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN static bool battery_CpMiaFault = false; //Warns if the CP node is mia on HVS CAN static bool battery_PcsMiaFault = false; //The PCS node is mia on HVS CAN @@ -276,11 +281,13 @@ static bool battery_ShuntHwMiaFault = false; //Warns if the shunt current readi static bool battery_PyroMiaFault = false; //Warns if the pyro squib is not connected static bool battery_hvsMiaFault = false; //Warns if the pack contactor hw fault static bool battery_hviMiaFault = false; //Warns if the FC contactor hw fault -static bool battery_Supply12vFault = false; //Warns if the low voltage (12V) battery is below minimum voltage threshold -static bool battery_VerSupplyFault = false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold +static bool battery_Supply12vFault = false; //Warns if the low voltage (12V) battery is below minimum voltage threshold +static bool battery_VerSupplyFault = + false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold static bool battery_HvilFault = false; //Warn if a High Voltage Inter Lock fault is detected static bool battery_BmsHvsMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN -static bool battery_PackVoltMismatchFault = false; //Warns if the pack voltage doesn't match approximately with sum of brick voltages +static bool battery_PackVoltMismatchFault = + false; //Warns if the pack voltage doesn't match approximately with sum of brick voltages static bool battery_EnsMiaFault = false; //Warns if the ENS line is not connected to HVC static bool battery_PackPosCtrArcFault = false; //Warns if the HVP detectes series arc at pack contactor static bool battery_packNegCtrArcFault = false; //Warns if the HVP detectes series arc at FC contactor @@ -305,7 +312,7 @@ static bool battery_packCtrCloseFailed = false; static bool battery_fcCtrCloseFailed = false; static bool battery_shuntThermistorMia = false; //0x320: 800 BMS_alertMatrix -static uint8_t battery_BMS_matrixIndex = 0; // Changed to bool +static uint8_t battery_BMS_matrixIndex = 0; // Changed to bool static bool battery_BMS_a061_robinBrickOverVoltage = false; static bool battery_BMS_a062_SW_BrickV_Imbalance = false; static bool battery_BMS_a063_SW_ChargePort_Fault = false; From 76efc1528f88330cd3465c2b4cbfd9c50625be0c Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 25 Dec 2024 21:36:45 +1300 Subject: [PATCH 117/225] Update bool and battery2 --- Software/src/battery/TESLA-BATTERY.cpp | 446 +++++++++++++------------ 1 file changed, 224 insertions(+), 222 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index b15b2639b..0fbe0b6d1 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -66,8 +66,7 @@ static uint16_t battery_bms_min_voltage = 0; //0x2b4: 692 PCS_dcdcRailStatus static uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt static uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt -static uint16_t battery_dcdcLvOutputCurrent = - 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent +static uint16_t battery_dcdcLvOutputCurrent = 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent //0x292: 658 BMS_socStatus static uint16_t battery_beginning_of_life = 600; // kWh static uint16_t battery_soc_min = 0; @@ -164,8 +163,8 @@ static uint16_t BMS_inletPassiveTargetT = 0; static uint16_t BMS_inletActiveHeatTargetT = 0; static uint16_t BMS_packTMin = 0; static uint16_t BMS_packTMax = 0; -static uint16_t BMS_pcsNoFlowRequest = 0; -static uint16_t BMS_noFlowRequest = 0; +static bool BMS_pcsNoFlowRequest = false; +static bool BMS_noFlowRequest = false; //0x2A4; 676 PCS_thermalStatus static int16_t PCS_chgPhATemp = 0; static int16_t PCS_chgPhBTemp = 0; @@ -317,7 +316,7 @@ static bool battery_BMS_a061_robinBrickOverVoltage = false; static bool battery_BMS_a062_SW_BrickV_Imbalance = false; static bool battery_BMS_a063_SW_ChargePort_Fault = false; static bool battery_BMS_a064_SW_SOC_Imbalance = false; -static bool battery_BMS_a027_SW_shunt_SNA = false; +static bool battery_BMS_a127_SW_shunt_SNA = false; static bool battery_BMS_a128_SW_shunt_MIA = false; static bool battery_BMS_a069_SW_Low_Power = false; static bool battery_BMS_a130_IO_CAN_Error = false; @@ -421,8 +420,8 @@ static uint16_t battery2_energy_to_charge_complete = 0; static uint16_t battery2_energy_to_charge_complete_m1 = 0; // kWh static uint16_t battery2_expected_energy_remaining = 0; static uint16_t battery2_expected_energy_remaining_m1 = 0; // kWh -static uint8_t battery2_full_charge_complete = 0; -static uint8_t battery2_fully_charged = 0; +static bool battery2_full_charge_complete = false; +static bool battery2_fully_charged = false; static uint16_t battery2_ideal_energy_remaining = 0; static uint16_t battery2_ideal_energy_remaining_m0 = 0; // kWh static uint16_t battery2_nominal_energy_remaining = 0; @@ -435,10 +434,13 @@ static int16_t battery2_amps = 0; // A static int16_t battery2_raw_amps = 0; // A static uint16_t battery2_charge_time_remaining = 0; // Minutes //0x252 594 BMS_powerAvailable -static uint16_t BMS2_regenerative_limit = 0; -static uint16_t BMS2_discharge_limit = 0; -static uint16_t BMS2_max_heat_park = 0; -static uint16_t BMS2_hvac_max_power = 0; +static uint16_t BMS2_maxRegenPower = 0; //rename from battery_regenerative_limit +static uint16_t BMS2_maxDischargePower = 0; // rename from battery_discharge_limit +static uint16_t BMS2_maxStationaryHeatPower = 0; //rename from battery_max_heat_park +static uint16_t BMS2_hvacPowerBudget = 0; //rename from battery_hvac_max_power +static uint8_t BMS2_notEnoughPowerForHeatPump = 0; +static uint8_t BMS2_powerLimitState = 0; +static uint8_t BMS2_inverterTQF = 0; //0x2d2: 722 BMSVAlimits static uint16_t battery2_max_discharge_current = 0; static uint16_t battery2_max_charge_current = 0; @@ -478,46 +480,46 @@ static uint8_t battery2_hvil_status = 0; static uint8_t battery2_packContNegativeState = 0; static uint8_t battery2_packContPositiveState = 0; static uint8_t battery2_packContactorSetState = 0; -static uint8_t battery2_packCtrsClosingAllowed = 0; -static uint8_t battery2_pyroTestInProgress = 0; -static uint8_t battery2_packCtrsOpenNowRequested = 0; -static uint8_t battery2_packCtrsOpenRequested = 0; +static bool battery2_packCtrsClosingAllowed = false; +static bool battery2_pyroTestInProgress = false; +static bool battery2_packCtrsOpenNowRequested = false; +static bool battery2_packCtrsOpenRequested = false; static uint8_t battery2_packCtrsRequestStatus = 0; -static uint8_t battery2_packCtrsResetRequestRequired = 0; -static uint8_t battery2_dcLinkAllowedToEnergize = 0; -static uint8_t battery2_fcContNegativeAuxOpen = 0; +static bool battery2_packCtrsResetRequestRequired = false; +static bool battery2_dcLinkAllowedToEnergize = false; +static bool battery2_fcContNegativeAuxOpen = false; static uint8_t battery2_fcContNegativeState = 0; -static uint8_t battery2_fcContPositiveAuxOpen = 0; +static bool battery2_fcContPositiveAuxOpen = false; static uint8_t battery2_fcContPositiveState = 0; static uint8_t battery2_fcContactorSetState = 0; -static uint8_t battery2_fcCtrsClosingAllowed = 0; -static uint8_t battery2_fcCtrsOpenNowRequested = 0; -static uint8_t battery2_fcCtrsOpenRequested = 0; +static bool battery2_fcCtrsClosingAllowed = false; +static bool battery2_fcCtrsOpenNowRequested = false; +static bool battery2_fcCtrsOpenRequested = false; static uint8_t battery2_fcCtrsRequestStatus = 0; -static uint8_t battery2_fcCtrsResetRequestRequired = 0; -static uint8_t battery2_fcLinkAllowedToEnergize = 0; +static bool battery2_fcCtrsResetRequestRequired = false; +static bool battery2_fcLinkAllowedToEnergize = false; //0x212: 530 BMS_status -static uint8_t battery2_BMS_hvacPowerRequest = 0; -static uint8_t battery2_BMS_notEnoughPowerForDrive = 0; -static uint8_t battery2_BMS_notEnoughPowerForSupport = 0; -static uint8_t battery2_BMS_preconditionAllowed = 0; -static uint8_t battery2_BMS_updateAllowed = 0; -static uint8_t battery2_BMS_activeHeatingWorthwhile = 0; -static uint8_t battery2_BMS_cpMiaOnHvs = 0; +static bool battery2_BMS_hvacPowerRequest = false; +static bool battery2_BMS_notEnoughPowerForDrive = false; +static bool battery2_BMS_notEnoughPowerForSupport = false; +static bool battery2_BMS_preconditionAllowed = false; +static bool battery2_BMS_updateAllowed = false; +static bool battery2_BMS_activeHeatingWorthwhile = false; +static bool battery2_BMS_cpMiaOnHvs = false; static uint8_t battery2_BMS_contactorState = 0; static uint8_t battery2_BMS_state = 0; static uint8_t battery2_BMS_hvState = 0; static uint16_t battery2_BMS_isolationResistance = 0; -static uint8_t battery2_BMS_chargeRequest = 0; -static uint8_t battery2_BMS_keepWarmRequest = 0; +static bool battery2_BMS_chargeRequest = false; +static bool battery2_BMS_keepWarmRequest = false; static uint8_t battery2_BMS_uiChargeStatus = 0; -static uint8_t battery2_BMS_diLimpRequest = 0; -static uint8_t battery2_BMS_okToShipByAir = 0; -static uint8_t battery2_BMS_okToShipByLand = 0; +static bool battery2_BMS_diLimpRequest = false; +static bool battery2_BMS_okToShipByAir = false; +static bool battery2_BMS_okToShipByLand = false; static uint32_t battery2_BMS_chgPowerAvailable = 0; static uint8_t battery2_BMS_chargeRetryCount = 0; -static uint8_t battery2_BMS_pcsPwmEnabled = 0; -static uint8_t battery2_BMS_ecuLogUploadRequest = 0; +static bool battery2_BMS_pcsPwmEnabled = false; +static bool battery2_BMS_ecuLogUploadRequest = false; static uint8_t battery2_BMS_minPackTemperature = 0; // 0x224:548 PCS_dcdcStatus static uint8_t battery2_PCS_dcdcPrechargeStatus = 0; @@ -525,8 +527,8 @@ static uint8_t battery2_PCS_dcdc12VSupportStatus = 0; static uint8_t battery2_PCS_dcdcHvBusDischargeStatus = 0; static uint16_t battery2_PCS_dcdcMainState = 0; static uint8_t battery2_PCS_dcdcSubState = 0; -static uint8_t battery2_PCS_dcdcFaulted = 0; -static uint8_t battery2_PCS_dcdcOutputIsLimited = 0; +static bool battery2_PCS_dcdcFaulted = false; +static bool battery2_PCS_dcdcOutputIsLimited = false; static uint32_t battery2_PCS_dcdcMaxOutputCurrentAllowed = 0; static uint8_t battery2_PCS_dcdcPrechargeRtyCnt = 0; static uint8_t battery2_PCS_dcdc12VSupportRtyCnt = 0; @@ -544,8 +546,8 @@ static uint16_t BMS2_inletPassiveTargetT = 0; static uint16_t BMS2_inletActiveHeatTargetT = 0; static uint16_t BMS2_packTMin = 0; static uint16_t BMS2_packTMax = 0; -static uint16_t BMS2_pcsNoFlowRequest = 0; -static uint16_t BMS2_noFlowRequest = 0; +static bool BMS2_pcsNoFlowRequest = false; +static bool BMS2_noFlowRequest = false; //0x2A4; 676 PCS_thermalStatus static int16_t PCS2_chgPhATemp = 0; static int16_t PCS2_chgPhBTemp = 0; @@ -576,38 +578,38 @@ static uint16_t PCS2_dcdcIntervalMinLvOutputCurr = 0; static uint32_t PCS2_dcdc12vSupportLifetimekWh = 0; //0x7AA: //1962 HVP_debugMessage: static uint8_t HVP2_debugMessageMultiplexer = 0; -static uint8_t HVP2_gpioPassivePyroDepl = 0; -static uint8_t HVP2_gpioPyroIsoEn = 0; -static uint8_t HVP2_gpioCpFaultIn = 0; -static uint8_t HVP2_gpioPackContPowerEn = 0; -static uint8_t HVP2_gpioHvCablesOk = 0; -static uint8_t HVP2_gpioHVPSelfEnable = 0; -static uint8_t HVP2_gpioLed = 0; -static uint8_t HVP2_gpioCrashSignal = 0; -static uint8_t HVP2_gpioShuntDataReady = 0; -static uint8_t HVP2_gpioFcContPosAux = 0; -static uint8_t HVP2_gpioFcContNegAux = 0; -static uint8_t HVP2_gpioBmsEout = 0; -static uint8_t HVP2_gpioCpFaultOut = 0; -static uint8_t HVP2_gpioPyroPor = 0; -static uint8_t HVP2_gpioShuntEn = 0; -static uint8_t HVP2_gpioHVPVerEn = 0; -static uint8_t HVP2_gpioPackCoontPosFlywheel = 0; -static uint8_t HVP2_gpioCpLatchEnable = 0; -static uint8_t HVP2_gpioPcsEnable = 0; -static uint8_t HVP2_gpioPcsDcdcPwmEnable = 0; -static uint8_t HVP2_gpioPcsChargePwmEnable = 0; -static uint8_t HVP2_gpioFcContPowerEnable = 0; -static uint8_t HVP2_gpioHvilEnable = 0; -static uint8_t HVP2_gpioSecDrdy = 0; +static bool HVP2_gpioPassivePyroDepl = false; +static bool HVP2_gpioPyroIsoEn = false; +static bool HVP2_gpioCpFaultIn = false; +static bool HVP2_gpioPackContPowerEn = false; +static bool HVP2_gpioHvCablesOk = false; +static bool HVP2_gpioHVPSelfEnable = false; +static bool HVP2_gpioLed = false; +static bool HVP2_gpioCrashSignal = false; +static bool HVP2_gpioShuntDataReady = false; +static bool HVP2_gpioFcContPosAux = false; +static bool HVP2_gpioFcContNegAux = false; +static bool HVP2_gpioBmsEout = false; +static bool HVP2_gpioCpFaultOut = false; +static bool HVP2_gpioPyroPor = false; +static bool HVP2_gpioShuntEn = false; +static bool HVP2_gpioHVPVerEn = false; +static bool HVP2_gpioPackCoontPosFlywheel = false; +static bool HVP2_gpioCpLatchEnable = false; +static bool HVP2_gpioPcsEnable = false; +static bool HVP2_gpioPcsDcdcPwmEnable = false; +static bool HVP2_gpioPcsChargePwmEnable = false; +static bool HVP2_gpioFcContPowerEnable = false; +static bool HVP2_gpioHvilEnable = false; +static bool HVP2_gpioSecDrdy = false; static uint16_t HVP2_hvp1v5Ref = 0; static int16_t HVP2_shuntCurrentDebug = 0; -static uint8_t HVP2_packCurrentMia = 0; -static uint8_t HVP2_auxCurrentMia = 0; -static uint8_t HVP2_currentSenseMia = 0; -static uint8_t HVP2_shuntRefVoltageMismatch = 0; -static uint8_t HVP2_shuntThermistorMia = 0; -static uint8_t HVP2_shuntHwMia = 0; +static bool HVP2_packCurrentMia = false; +static bool HVP2_auxCurrentMia = false; +static bool HVP2_currentSenseMia = false; +static bool HVP2_shuntRefVoltageMismatch = false; +static bool HVP2_shuntThermistorMia = false; +static bool HVP2_shuntHwMia = false; static int16_t HVP2_dcLinkVoltage = 0; static int16_t HVP2_packVoltage = 0; static int16_t HVP2_fcLinkVoltage = 0; @@ -633,158 +635,158 @@ static uint8_t HVP2_shuntAuxCurrentStatus = 0; static uint8_t HVP2_shuntBarTempStatus = 0; static uint8_t HVP2_shuntAsicTempStatus = 0; //0x3aa: HVP_alertMatrix1 Fault codes -static uint8_t battery2_WatchdogReset = 0; //Warns if the processor has experienced a reset due to watchdog reset. -static uint8_t battery2_PowerLossReset = 0; //Warns if the processor has experienced a reset due to power loss. -static uint8_t battery2_SwAssertion = 0; //An internal software assertion has failed. -static uint8_t battery2_CrashEvent = 0; //Warns if the crash signal is detected by HVP -static uint8_t battery2_OverDchgCurrentFault = 0; //Warns if the pack discharge is above max discharge current limit -static uint8_t battery2_OverChargeCurrentFault = - 0; //Warns if the pack discharge current is above max charge current limit -static uint8_t battery2_OverCurrentFault = - 0; //Warns if the pack current (discharge or charge) is above max current limit. -static uint8_t battery2_OverTemperatureFault = 0; //A pack module temperature is above maximum temperature limit -static uint8_t battery2_OverVoltageFault = 0; //A brick voltage is above maximum voltage limit -static uint8_t battery2_UnderVoltageFault = 0; //A brick voltage is below minimum voltage limit -static uint8_t battery2_PrimaryBmbMiaFault = - 0; //Warns if the voltage and temperature readings from primary BMB chain are mia -static uint8_t battery2_SecondaryBmbMiaFault = - 0; //Warns if the voltage and temperature readings from secondary BMB chain are mia -static uint8_t battery2_BmbMismatchFault = - 0; //Warns if the primary and secondary BMB chain readings don't match with each other -static uint8_t battery2_BmsHviMiaFault = 0; //Warns if the BMS node is mia on HVS or HVI CAN -static uint8_t battery2_CpMiaFault = 0; //Warns if the CP node is mia on HVS CAN -static uint8_t battery2_PcsMiaFault = 0; //The PCS node is mia on HVS CAN -static uint8_t battery2_BmsFault = 0; //Warns if the BMS ECU has faulted -static uint8_t battery2_PcsFault = 0; //Warns if the PCS ECU has faulted -static uint8_t battery2_CpFault = 0; //Warns if the CP ECU has faulted -static uint8_t battery2_ShuntHwMiaFault = 0; //Warns if the shunt current reading is not available -static uint8_t battery2_PyroMiaFault = 0; //Warns if the pyro squib is not connected -static uint8_t battery2_hvsMiaFault = 0; //Warns if the pack contactor hw fault -static uint8_t battery2_hviMiaFault = 0; //Warns if the FC contactor hw fault -static uint8_t battery2_Supply12vFault = 0; //Warns if the low voltage (12V) battery is below minimum voltage threshold -static uint8_t battery2_VerSupplyFault = - 0; //Warns if the Energy reserve voltage supply is below minimum voltage threshold -static uint8_t battery2_HvilFault = 0; //Warn if a High Voltage Inter Lock fault is detected -static uint8_t battery2_BmsHvsMiaFault = 0; //Warns if the BMS node is mia on HVS or HVI CAN -static uint8_t battery2_PackVoltMismatchFault = - 0; //Warns if the pack voltage doesn't match approximately with sum of brick voltages -static uint8_t battery2_EnsMiaFault = 0; //Warns if the ENS line is not connected to HVC -static uint8_t battery2_PackPosCtrArcFault = 0; //Warns if the HVP detectes series arc at pack contactor -static uint8_t battery2_packNegCtrArcFault = 0; //Warns if the HVP detectes series arc at FC contactor -static uint8_t battery2_ShuntHwAndBmsMiaFault = 0; -static uint8_t battery2_fcContHwFault = 0; -static uint8_t battery2_robinOverVoltageFault = 0; -static uint8_t battery2_packContHwFault = 0; -static uint8_t battery2_pyroFuseBlown = 0; -static uint8_t battery2_pyroFuseFailedToBlow = 0; -static uint8_t battery2_CpilFault = 0; -static uint8_t battery2_PackContactorFellOpen = 0; -static uint8_t battery2_FcContactorFellOpen = 0; -static uint8_t battery2_packCtrCloseBlocked = 0; -static uint8_t battery2_fcCtrCloseBlocked = 0; -static uint8_t battery2_packContactorForceOpen = 0; -static uint8_t battery2_fcContactorForceOpen = 0; -static uint8_t battery2_dcLinkOverVoltage = 0; -static uint8_t battery2_shuntOverTemperature = 0; -static uint8_t battery2_passivePyroDeploy = 0; -static uint8_t battery2_logUploadRequest = 0; -static uint8_t battery2_packCtrCloseFailed = 0; -static uint8_t battery2_fcCtrCloseFailed = 0; -static uint8_t battery2_shuntThermistorMia = 0; +static bool battery2_WatchdogReset = false; //Warns if the processor has experienced a reset due to watchdog reset. +static bool battery2_PowerLossReset = false; //Warns if the processor has experienced a reset due to power loss. +static bool battery2_SwAssertion = false; //An internal software assertion has failed. +static bool battery2_CrashEvent = false; //Warns if the crash signal is detected by HVP +static bool battery2_OverDchgCurrentFault = false; //Warns if the pack discharge is above max discharge current limit +static bool battery2_OverChargeCurrentFault = + false; //Warns if the pack discharge current is above max charge current limit +static bool battery2_OverCurrentFault = + false; //Warns if the pack current (discharge or charge) is above max current limit. +static bool battery2_OverTemperatureFault = false; //A pack module temperature is above maximum temperature limit +static bool battery2_OverVoltageFault = false; //A brick voltage is above maximum voltage limit +static bool battery2_UnderVoltageFault = false; //A brick voltage is below minimum voltage limit +static bool battery2_PrimaryBmbMiaFault = + false; //Warns if the voltage and temperature readings from primary BMB chain are mia +static bool battery2_SecondaryBmbMiaFault = + false; //Warns if the voltage and temperature readings from secondary BMB chain are mia +static bool battery2_BmbMismatchFault = + false; //Warns if the primary and secondary BMB chain readings don't match with each other +static bool battery2_BmsHviMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN +static bool battery2_CpMiaFault = false; //Warns if the CP node is mia on HVS CAN +static bool battery2_PcsMiaFault = false; //The PCS node is mia on HVS CAN +static bool battery2_BmsFault = false; //Warns if the BMS ECU has faulted +static bool battery2_PcsFault = false; //Warns if the PCS ECU has faulted +static bool battery2_CpFault = false; //Warns if the CP ECU has faulted +static bool battery2_ShuntHwMiaFault = false; //Warns if the shunt current reading is not available +static bool battery2_PyroMiaFault = false; //Warns if the pyro squib is not connected +static bool battery2_hvsMiaFault = false; //Warns if the pack contactor hw fault +static bool battery2_hviMiaFault = false; //Warns if the FC contactor hw fault +static bool battery2_Supply12vFault = false; //Warns if the low voltage (12V) battery is below minimum voltage threshold +static bool battery2_VerSupplyFault = + false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold +static bool battery2_HvilFault = false; //Warn if a High Voltage Inter Lock fault is detected +static bool battery2_BmsHvsMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN +static bool battery2_PackVoltMismatchFault = + false; //Warns if the pack voltage doesn't match approximately with sum of brick voltages +static bool battery2_EnsMiaFault = false; //Warns if the ENS line is not connected to HVC +static bool battery2_PackPosCtrArcFault = false; //Warns if the HVP detectes series arc at pack contactor +static bool battery2_packNegCtrArcFault = false; //Warns if the HVP detectes series arc at FC contactor +static bool battery2_ShuntHwAndBmsMiaFault = false; +static bool battery2_fcContHwFault = false; +static bool battery2_robinOverVoltageFault = false; +static bool battery2_packContHwFault = false; +static bool battery2_pyroFuseBlown = false; +static bool battery2_pyroFuseFailedToBlow = false; +static bool battery2_CpilFault = false; +static bool battery2_PackContactorFellOpen = false; +static bool battery2_FcContactorFellOpen = false; +static bool battery2_packCtrCloseBlocked = false; +static bool battery2_fcCtrCloseBlocked = false; +static bool battery2_packContactorForceOpen = false; +static bool battery2_fcContactorForceOpen = false; +static bool battery2_dcLinkOverVoltage = false; +static bool battery2_shuntOverTemperature = false; +static bool battery2_passivePyroDeploy = false; +static bool battery2_logUploadRequest = false; +static bool battery2_packCtrCloseFailed = false; +static bool battery2_fcCtrCloseFailed = false; +static bool battery2_shuntThermistorMia = false; //0x320: 800 BMS_alertMatrix static uint8_t battery2_BMS_matrixIndex = 4; -static uint8_t battery2_BMS_a061_robinBrickOverVoltage = 1; -static uint8_t battery2_BMS_a062_SW_BrickV_Imbalance = 1; -static uint8_t battery2_BMS_a063_SW_ChargePort_Fault = 1; -static uint8_t battery2_BMS_a064_SW_SOC_Imbalance = 1; -static uint8_t battery2_BMS_a127_SW_shunt_SNA = 1; -static uint8_t battery2_BMS_a128_SW_shunt_MIA = 1; -static uint8_t battery2_BMS_a069_SW_Low_Power = 1; -static uint8_t battery2_BMS_a130_IO_CAN_Error = 1; -static uint8_t battery2_BMS_a071_SW_SM_TransCon_Not_Met = 1; -static uint8_t battery2_BMS_a132_HW_BMB_OTP_Uncorrctbl = 1; -static uint8_t battery2_BMS_a134_SW_Delayed_Ctr_Off = 1; -static uint8_t battery2_BMS_a075_SW_Chg_Disable_Failure = 1; -static uint8_t battery2_BMS_a076_SW_Dch_While_Charging = 1; -static uint8_t battery2_BMS_a017_SW_Brick_OV = 1; -static uint8_t battery2_BMS_a018_SW_Brick_UV = 1; -static uint8_t battery2_BMS_a019_SW_Module_OT = 1; -static uint8_t battery2_BMS_a021_SW_Dr_Limits_Regulation = 1; -static uint8_t battery2_BMS_a022_SW_Over_Current = 1; -static uint8_t battery2_BMS_a023_SW_Stack_OV = 1; -static uint8_t battery2_BMS_a024_SW_Islanded_Brick = 1; -static uint8_t battery2_BMS_a025_SW_PwrBalance_Anomaly = 1; -static uint8_t battery2_BMS_a026_SW_HFCurrent_Anomaly = 1; -static uint8_t battery2_BMS_a087_SW_Feim_Test_Blocked = 1; -static uint8_t battery2_BMS_a088_SW_VcFront_MIA_InDrive = 1; -static uint8_t battery2_BMS_a089_SW_VcFront_MIA = 1; -static uint8_t battery2_BMS_a090_SW_Gateway_MIA = 1; -static uint8_t battery2_BMS_a091_SW_ChargePort_MIA = 1; -static uint8_t battery2_BMS_a092_SW_ChargePort_Mia_On_Hv = 1; -static uint8_t battery2_BMS_a034_SW_Passive_Isolation = 1; -static uint8_t battery2_BMS_a035_SW_Isolation = 1; -static uint8_t battery2_BMS_a036_SW_HvpHvilFault = 1; -static uint8_t battery2_BMS_a037_SW_Flood_Port_Open = 1; -static uint8_t battery2_BMS_a158_SW_HVP_HVI_Comms = 1; -static uint8_t battery2_BMS_a039_SW_DC_Link_Over_Voltage = 1; -static uint8_t battery2_BMS_a041_SW_Power_On_Reset = 1; -static uint8_t battery2_BMS_a042_SW_MPU_Error = 1; -static uint8_t battery2_BMS_a043_SW_Watch_Dog_Reset = 1; -static uint8_t battery2_BMS_a044_SW_Assertion = 1; -static uint8_t battery2_BMS_a045_SW_Exception = 1; -static uint8_t battery2_BMS_a046_SW_Task_Stack_Usage = 1; -static uint8_t battery2_BMS_a047_SW_Task_Stack_Overflow = 1; -static uint8_t battery2_BMS_a048_SW_Log_Upload_Request = 1; -static uint8_t battery2_BMS_a169_SW_FC_Pack_Weld = 1; -static uint8_t battery2_BMS_a050_SW_Brick_Voltage_MIA = 1; -static uint8_t battery2_BMS_a051_SW_HVC_Vref_Bad = 1; -static uint8_t battery2_BMS_a052_SW_PCS_MIA = 1; -static uint8_t battery2_BMS_a053_SW_ThermalModel_Sanity = 1; -static uint8_t battery2_BMS_a054_SW_Ver_Supply_Fault = 1; -static uint8_t battery2_BMS_a176_SW_GracefulPowerOff = 1; -static uint8_t battery2_BMS_a059_SW_Pack_Voltage_Sensing = 1; -static uint8_t battery2_BMS_a060_SW_Leakage_Test_Failure = 1; -static uint8_t battery2_BMS_a077_SW_Charger_Regulation = 1; -static uint8_t battery2_BMS_a081_SW_Ctr_Close_Blocked = 1; -static uint8_t battery2_BMS_a082_SW_Ctr_Force_Open = 1; -static uint8_t battery2_BMS_a083_SW_Ctr_Close_Failure = 1; -static uint8_t battery2_BMS_a084_SW_Sleep_Wake_Aborted = 1; -static uint8_t battery2_BMS_a094_SW_Drive_Inverter_MIA = 1; -static uint8_t battery2_BMS_a099_SW_BMB_Communication = 1; -static uint8_t battery2_BMS_a105_SW_One_Module_Tsense = 1; -static uint8_t battery2_BMS_a106_SW_All_Module_Tsense = 1; -static uint8_t battery2_BMS_a107_SW_Stack_Voltage_MIA = 1; -static uint8_t battery2_BMS_a121_SW_NVRAM_Config_Error = 1; -static uint8_t battery2_BMS_a122_SW_BMS_Therm_Irrational = 1; -static uint8_t battery2_BMS_a123_SW_Internal_Isolation = 1; -static uint8_t battery2_BMS_a129_SW_VSH_Failure = 1; -static uint8_t battery2_BMS_a131_Bleed_FET_Failure = 1; -static uint8_t battery2_BMS_a136_SW_Module_OT_Warning = 1; -static uint8_t battery2_BMS_a137_SW_Brick_UV_Warning = 1; -static uint8_t battery2_BMS_a138_SW_Brick_OV_Warning = 1; -static uint8_t battery2_BMS_a139_SW_DC_Link_V_Irrational = 1; -static uint8_t battery2_BMS_a141_SW_BMB_Status_Warning = 1; -static uint8_t battery2_BMS_a144_Hvp_Config_Mismatch = 1; -static uint8_t battery2_BMS_a145_SW_SOC_Change = 1; -static uint8_t battery2_BMS_a146_SW_Brick_Overdischarged = 1; -static uint8_t battery2_BMS_a149_SW_Missing_Config_Block = 1; -static uint8_t battery2_BMS_a151_SW_external_isolation = 1; -static uint8_t battery2_BMS_a156_SW_BMB_Vref_bad = 1; -static uint8_t battery2_BMS_a157_SW_HVP_HVS_Comms = 1; -static uint8_t battery2_BMS_a159_SW_HVP_ECU_Error = 1; -static uint8_t battery2_BMS_a161_SW_DI_Open_Request = 1; -static uint8_t battery2_BMS_a162_SW_No_Power_For_Support = 1; -static uint8_t battery2_BMS_a163_SW_Contactor_Mismatch = 1; -static uint8_t battery2_BMS_a164_SW_Uncontrolled_Regen = 1; -static uint8_t battery2_BMS_a165_SW_Pack_Partial_Weld = 1; -static uint8_t battery2_BMS_a166_SW_Pack_Full_Weld = 1; -static uint8_t battery2_BMS_a167_SW_FC_Partial_Weld = 1; -static uint8_t battery2_BMS_a168_SW_FC_Full_Weld = 1; -static uint8_t battery2_BMS_a170_SW_Limp_Mode = 1; -static uint8_t battery2_BMS_a171_SW_Stack_Voltage_Sense = 1; -static uint8_t battery2_BMS_a174_SW_Charge_Failure = 1; -static uint8_t battery2_BMS_a179_SW_Hvp_12V_Fault = 1; -static uint8_t battery2_BMS_a180_SW_ECU_reset_blocked = 1; +static bool battery2_BMS_a061_robinBrickOverVoltage = false; +static bool battery2_BMS_a062_SW_BrickV_Imbalance = false; +static bool battery2_BMS_a063_SW_ChargePort_Fault = false; +static bool battery2_BMS_a064_SW_SOC_Imbalance = false; +static bool battery2_BMS_a127_SW_shunt_SNA = false; +static bool battery2_BMS_a128_SW_shunt_MIA = false; +static bool battery2_BMS_a069_SW_Low_Power = false; +static bool battery2_BMS_a130_IO_CAN_Error = false; +static bool battery2_BMS_a071_SW_SM_TransCon_Not_Met = false; +static bool battery2_BMS_a132_HW_BMB_OTP_Uncorrctbl = false; +static bool battery2_BMS_a134_SW_Delayed_Ctr_Off = false; +static bool battery2_BMS_a075_SW_Chg_Disable_Failure = false; +static bool battery2_BMS_a076_SW_Dch_While_Charging = false; +static bool battery2_BMS_a017_SW_Brick_OV = false; +static bool battery2_BMS_a018_SW_Brick_UV = false; +static bool battery2_BMS_a019_SW_Module_OT = false; +static bool battery2_BMS_a021_SW_Dr_Limits_Regulation = false; +static bool battery2_BMS_a022_SW_Over_Current = false; +static bool battery2_BMS_a023_SW_Stack_OV = false; +static bool battery2_BMS_a024_SW_Islanded_Brick = false; +static bool battery2_BMS_a025_SW_PwrBalance_Anomaly = false; +static bool battery2_BMS_a026_SW_HFCurrent_Anomaly = false; +static bool battery2_BMS_a087_SW_Feim_Test_Blocked = false; +static bool battery2_BMS_a088_SW_VcFront_MIA_InDrive = false; +static bool battery2_BMS_a089_SW_VcFront_MIA = false; +static bool battery2_BMS_a090_SW_Gateway_MIA = false; +static bool battery2_BMS_a091_SW_ChargePort_MIA = false; +static bool battery2_BMS_a092_SW_ChargePort_Mia_On_Hv = false; +static bool battery2_BMS_a034_SW_Passive_Isolation = false; +static bool battery2_BMS_a035_SW_Isolation = false; +static bool battery2_BMS_a036_SW_HvpHvilFault = false; +static bool battery2_BMS_a037_SW_Flood_Port_Open = false; +static bool battery2_BMS_a158_SW_HVP_HVI_Comms = false; +static bool battery2_BMS_a039_SW_DC_Link_Over_Voltage = 1; +static bool battery2_BMS_a041_SW_Power_On_Reset = false; +static bool battery2_BMS_a042_SW_MPU_Error = false; +static bool battery2_BMS_a043_SW_Watch_Dog_Reset = false; +static bool battery2_BMS_a044_SW_Assertion = false; +static bool battery2_BMS_a045_SW_Exception = false; +static bool battery2_BMS_a046_SW_Task_Stack_Usage = false; +static bool battery2_BMS_a047_SW_Task_Stack_Overflow = false; +static bool battery2_BMS_a048_SW_Log_Upload_Request = false; +static bool battery2_BMS_a169_SW_FC_Pack_Weld = false; +static bool battery2_BMS_a050_SW_Brick_Voltage_MIA = false; +static bool battery2_BMS_a051_SW_HVC_Vref_Bad = false; +static bool battery2_BMS_a052_SW_PCS_MIA = false; +static bool battery2_BMS_a053_SW_ThermalModel_Sanity = false; +static bool battery2_BMS_a054_SW_Ver_Supply_Fault = false; +static bool battery2_BMS_a176_SW_GracefulPowerOff = false; +static bool battery2_BMS_a059_SW_Pack_Voltage_Sensing = false; +static bool battery2_BMS_a060_SW_Leakage_Test_Failure = false; +static bool battery2_BMS_a077_SW_Charger_Regulation = false; +static bool battery2_BMS_a081_SW_Ctr_Close_Blocked = false; +static bool battery2_BMS_a082_SW_Ctr_Force_Open = false; +static bool battery2_BMS_a083_SW_Ctr_Close_Failure = false; +static bool battery2_BMS_a084_SW_Sleep_Wake_Aborted = false; +static bool battery2_BMS_a094_SW_Drive_Inverter_MIA = false; +static bool battery2_BMS_a099_SW_BMB_Communication = false; +static bool battery2_BMS_a105_SW_One_Module_Tsense = false; +static bool battery2_BMS_a106_SW_All_Module_Tsense = false; +static bool battery2_BMS_a107_SW_Stack_Voltage_MIA = false; +static bool battery2_BMS_a121_SW_NVRAM_Config_Error = false; +static bool battery2_BMS_a122_SW_BMS_Therm_Irrational = false; +static bool battery2_BMS_a123_SW_Internal_Isolation = false; +static bool battery2_BMS_a129_SW_VSH_Failure = false; +static bool battery2_BMS_a131_Bleed_FET_Failure = false; +static bool battery2_BMS_a136_SW_Module_OT_Warning = false; +static bool battery2_BMS_a137_SW_Brick_UV_Warning = false; +static bool battery2_BMS_a138_SW_Brick_OV_Warning = false; +static bool battery2_BMS_a139_SW_DC_Link_V_Irrational = false; +static bool battery2_BMS_a141_SW_BMB_Status_Warning = false; +static bool battery2_BMS_a144_Hvp_Config_Mismatch = false; +static bool battery2_BMS_a145_SW_SOC_Change = false; +static bool battery2_BMS_a146_SW_Brick_Overdischarged = false; +static bool battery2_BMS_a149_SW_Missing_Config_Block = false; +static bool battery2_BMS_a151_SW_external_isolation = false; +static bool battery2_BMS_a156_SW_BMB_Vref_bad = false; +static bool battery2_BMS_a157_SW_HVP_HVS_Comms = false; +static bool battery2_BMS_a159_SW_HVP_ECU_Error = false; +static bool battery2_BMS_a16false_SW_DI_Open_Request = false; +static bool battery2_BMS_a162_SW_No_Power_For_Support = false; +static bool battery2_BMS_a163_SW_Contactor_Mismatch = false; +static bool battery2_BMS_a164_SW_Uncontrolled_Regen = false; +static bool battery2_BMS_a165_SW_Pack_Partial_Weld = false; +static bool battery2_BMS_a166_SW_Pack_Full_Weld = false; +static bool battery2_BMS_a167_SW_FC_Partial_Weld = false; +static bool battery2_BMS_a168_SW_FC_Full_Weld = false; +static bool battery2_BMS_a170_SW_Limp_Mode = false; +static bool battery2_BMS_a171_SW_Stack_Voltage_Sense = false; +static bool battery2_BMS_a174_SW_Charge_Failure = false; +static bool battery2_BMS_a179_SW_Hvp_12V_Fault = false; +static bool battery2_BMS_a180_SW_ECU_reset_blocked = false; #endif //DOUBLE_BATTERY From 7edba4efc62f5d7f8c43286b0ffe2cf9f7a3aa0b Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 25 Dec 2024 21:38:58 +1300 Subject: [PATCH 118/225] Update TESLA-BATTERY.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 0fbe0b6d1..c4de734ec 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -66,7 +66,8 @@ static uint16_t battery_bms_min_voltage = 0; //0x2b4: 692 PCS_dcdcRailStatus static uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt static uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt -static uint16_t battery_dcdcLvOutputCurrent = 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent +static uint16_t battery_dcdcLvOutputCurrent = + 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent //0x292: 658 BMS_socStatus static uint16_t battery_beginning_of_life = 600; // kWh static uint16_t battery_soc_min = 0; @@ -663,9 +664,10 @@ static bool battery2_ShuntHwMiaFault = false; //Warns if the shunt current read static bool battery2_PyroMiaFault = false; //Warns if the pyro squib is not connected static bool battery2_hvsMiaFault = false; //Warns if the pack contactor hw fault static bool battery2_hviMiaFault = false; //Warns if the FC contactor hw fault -static bool battery2_Supply12vFault = false; //Warns if the low voltage (12V) battery is below minimum voltage threshold +static bool battery2_Supply12vFault = + false; //Warns if the low voltage (12V) battery is below minimum voltage threshold static bool battery2_VerSupplyFault = - false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold + false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold static bool battery2_HvilFault = false; //Warn if a High Voltage Inter Lock fault is detected static bool battery2_BmsHvsMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN static bool battery2_PackVoltMismatchFault = From a113cd309324832181d1cf80b4385fc1c3e80697 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Wed, 25 Dec 2024 22:06:17 +1300 Subject: [PATCH 119/225] Return to send 30ms message --- Software/src/battery/TESLA-BATTERY.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index c4de734ec..3630f8ddf 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -8,7 +8,7 @@ /* Do not change code below unless you are sure what you are doing */ /* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */ -static unsigned long previousMillis50 = 0; // will store last time a 30ms CAN Message was send +static unsigned long previousMillis30 = 0; // will store last time a 30ms CAN Message was send CAN_frame TESLA_221_1 = { .FD = false, @@ -2658,14 +2658,14 @@ the first, for a few cycles, then stop all messages which causes the contactor #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) //Send 30ms message - if (currentMillis - previousMillis50 >= INTERVAL_50_MS) { + if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { // Check if sending of CAN messages has been delayed too much. - if ((currentMillis - previousMillis50 >= INTERVAL_50_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { - set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis50)); + if ((currentMillis - previousMillis30 >= INTERVAL_30_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis30)); } else { clear_event(EVENT_CAN_OVERRUN); } - previousMillis50 = currentMillis; + previousMillis30 = currentMillis; if ((datalayer.system.status.inverter_allows_contactor_closing == true) && (datalayer.battery.status.bms_status != FAULT)) { From 4f07290d172a1bfa7641edb4a1341f82851f2b80 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Thu, 26 Dec 2024 10:35:48 +1300 Subject: [PATCH 120/225] Update bool values in datalayer and advanced battery --- Software/src/datalayer/datalayer_extended.h | 84 ++++++------ .../webserver/advanced_battery_html.cpp | 122 +++++++++--------- 2 files changed, 103 insertions(+), 103 deletions(-) diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index d5a4ece65..190640357 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -215,12 +215,12 @@ typedef struct { uint8_t packCtrsClosingAllowed = 0; /** uint8_t */ /** Pyro test in progress */ - uint8_t pyroTestInProgress = 0; - uint8_t battery_packCtrsOpenNowRequested = 0; - uint8_t battery_packCtrsOpenRequested = 0; + bool pyroTestInProgress = false; + bool battery_packCtrsOpenNowRequested = false; + bool battery_packCtrsOpenRequested = false; uint8_t battery_packCtrsRequestStatus = 0; - uint8_t battery_packCtrsResetRequestRequired = 0; - uint8_t battery_dcLinkAllowedToEnergize = 0; + bool battery_packCtrsResetRequestRequired = false; + bool battery_dcLinkAllowedToEnergize = false; uint8_t battery_beginning_of_life = 0; uint8_t battery_battTempPct = 0; uint16_t battery_dcdcLvBusVolt = 0; @@ -238,8 +238,8 @@ typedef struct { uint16_t battery_energy_buffer_m1 = 0; uint16_t battery_expected_energy_remaining = 0; uint16_t battery_expected_energy_remaining_m1 = 0; - uint16_t battery_full_charge_complete = 0; - uint8_t battery_fully_charged = 0; + bool battery_full_charge_complete = false; + bool battery_fully_charged = false; uint16_t battery_total_discharge = 0; uint16_t battery_total_charge = 0; uint16_t battery_BrickVoltageMax = 0; @@ -268,16 +268,16 @@ typedef struct { uint8_t battery_BMS_hvState = 0; uint16_t battery_BMS_isolationResistance = 0; uint8_t battery_BMS_uiChargeStatus = 0; - uint8_t battery_BMS_diLimpRequest = 0; + bool battery_BMS_diLimpRequest = false; uint16_t battery_BMS_chgPowerAvailable = 0; - uint8_t battery_BMS_pcsPwmEnabled = 0; + bool battery_BMS_pcsPwmEnabled = false; uint8_t battery_PCS_dcdcPrechargeStatus = 0; uint8_t battery_PCS_dcdc12VSupportStatus = 0; uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0; uint8_t battery_PCS_dcdcMainState = 0; uint8_t battery_PCS_dcdcSubState = 0; - uint8_t battery_PCS_dcdcFaulted = 0; - uint8_t battery_PCS_dcdcOutputIsLimited = 0; + bool battery_PCS_dcdcFaulted = false; + bool battery_PCS_dcdcOutputIsLimited = false; uint16_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0; uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0; uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0; @@ -300,8 +300,8 @@ typedef struct { uint16_t BMS_inletActiveHeatTargetT = 0; uint16_t BMS_packTMin = 0; uint16_t BMS_packTMax = 0; - uint8_t BMS_pcsNoFlowRequest = 0; - uint8_t BMS_noFlowRequest = 0; + bool BMS_pcsNoFlowRequest = false; + bool BMS_noFlowRequest = false; uint16_t PCS_dcdcTemp = 0; uint16_t PCS_ambientTemp = 0; uint16_t PCS_dcdcMaxLvOutputCurrent = 0; @@ -324,37 +324,37 @@ typedef struct { uint16_t PCS_dcdcIntervalMinLvBusVolt = 0; uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0; uint32_t PCS_dcdc12vSupportLifetimekWh = 0; - uint8_t HVP_gpioPassivePyroDepl = 0; - uint8_t HVP_gpioPyroIsoEn = 0; - uint8_t HVP_gpioCpFaultIn = 0; - uint8_t HVP_gpioPackContPowerEn = 0; - uint8_t HVP_gpioHvCablesOk = 0; - uint8_t HVP_gpioHvpSelfEnable = 0; - uint8_t HVP_gpioLed = 0; - uint8_t HVP_gpioCrashSignal = 0; - uint8_t HVP_gpioShuntDataReady = 0; - uint8_t HVP_gpioFcContPosAux = 0; - uint8_t HVP_gpioFcContNegAux = 0; - uint8_t HVP_gpioBmsEout = 0; - uint8_t HVP_gpioCpFaultOut = 0; - uint8_t HVP_gpioPyroPor = 0; - uint8_t HVP_gpioShuntEn = 0; - uint8_t HVP_gpioHvpVerEn = 0; - uint8_t HVP_gpioPackCoontPosFlywheel = 0; - uint8_t HVP_gpioCpLatchEnable = 0; - uint8_t HVP_gpioPcsEnable = 0; - uint8_t HVP_gpioPcsDcdcPwmEnable = 0; - uint8_t HVP_gpioPcsChargePwmEnable = 0; - uint8_t HVP_gpioFcContPowerEnable = 0; - uint8_t HVP_gpioHvilEnable = 0; - uint8_t HVP_gpioSecDrdy = 0; + bool HVP_gpioPassivePyroDepl = false; + bool HVP_gpioPyroIsoEn = false; + bool HVP_gpioCpFaultIn = false; + bool HVP_gpioPackContPowerEn = false; + bool HVP_gpioHvCablesOk = false; + bool HVP_gpioHvpSelfEnable = false; + bool HVP_gpioLed = false; + bool HVP_gpioCrashSignal = false; + bool HVP_gpioShuntDataReady = false; + bool HVP_gpioFcContPosAux = false; + bool HVP_gpioFcContNegAux = false; + bool HVP_gpioBmsEout = false; + bool HVP_gpioCpFaultOut = false; + bool HVP_gpioPyroPor = false; + bool HVP_gpioShuntEn = false; + bool HVP_gpioHvpVerEn = false; + bool HVP_gpioPackCoontPosFlywheel = false; + bool HVP_gpioCpLatchEnable = false; + bool HVP_gpioPcsEnable = false; + bool HVP_gpioPcsDcdcPwmEnable = false; + bool HVP_gpioPcsChargePwmEnable = false; + bool HVP_gpioFcContPowerEnable = false; + bool HVP_gpioHvilEnable = false; + bool HVP_gpioSecDrdy = false; uint16_t HVP_hvp1v5Ref = 0; uint16_t HVP_shuntCurrentDebug = 0; - uint8_t HVP_packCurrentMia = 0; - uint8_t HVP_auxCurrentMia = 0; - uint8_t HVP_currentSenseMia = 0; - uint8_t HVP_shuntRefVoltageMismatch = 0; - uint8_t HVP_shuntThermistorMia = 0; + bool HVP_packCurrentMia = false; + bool HVP_auxCurrentMia = false; + bool HVP_currentSenseMia = false; + bool HVP_shuntRefVoltageMismatch = false; + bool HVP_shuntThermistorMia = false; uint8_t HVP_shuntHwMia = 0; uint16_t HVP_dcLinkVoltage = 0; uint16_t HVP_packVoltage = 0; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index f2e055bbe..5f1016e17 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -502,20 +502,20 @@ String advanced_battery_processor(const String& var) { "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; content += "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; - content += "

Closing allowed?: " + String(falseTrue[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; - content += "

Pyrotest in Progress: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "

"; + content += "

Closing allowed?: " + String(datalayer_extended.tesla.packCtrsClosingAllowed) + "

"; //bool + content += "

Pyrotest in Progress: " + String(datalayer_extended.tesla.pyroTestInProgress) + "

"; //bool content += "

Contactors Open Now Requested: " + - String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; + String(datalayer_extended.tesla.battery_packCtrsOpenNowRequested) + ""; //bool content += - "

Contactors Open Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + - "

"; + "

Contactors Open Requested: " + String(datalayer_extended.tesla.battery_packCtrsOpenRequested) + + "

"; //bool content += "

Contactors Request Status: " + String(HVP_contactor[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; content += "

Contactors Reset Request Required: " + - String(noYes[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; + String(datalayer_extended.tesla.battery_packCtrsResetRequestRequired) + ""; //bool content += - "

DC Link Allowed to Energize:" + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + - "

"; + "

DC Link Allowed to Energize:" + String(datalayer_extended.tesla.battery_dcLinkAllowedToEnergize) + + "

"; //bool // Comment what data you would like to dislay, order can be changed. //0x292 658 BMS_socStates content += "

Battery Beginning of Life: " + String(beginning_of_life) + " KWh

"; @@ -544,25 +544,25 @@ String advanced_battery_processor(const String& var) { "

Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "

"; content += "

Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "

"; - content += "

PCS Faulted: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcFaulted]) + "

"; + content += "

PCS Faulted: " + String(datalayer_extended.tesla.battery_PCS_dcdcFaulted) + "

"; //bool content += - "

Output Is Limited: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + "

"; + "

Output Is Limited: " + String(datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited) + "

"; //bool content += "

Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A

"; - content += "

Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) + - "

"; + content += "

Precharge Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt) + + "

"; //bool content += - "

12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) + - "

"; - content += "

Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) + - "

"; + "

12V Support Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt) + + "

"; // bool + content += "

Discharge Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt) + + "

"; //bool content += - "

PWM Enable Line: " + String(noYes[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + "

"; + "

PWM Enable Line: " + String(datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine) + "

"; //bool content += "

Supporting Fixed LV Target: " + - String(noYes[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "

"; + String(datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget) + ""; //bool content += "

Precharge Restart Cnt: " + - String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "

"; + String(datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt) + ""; //bool content += "

Initial Precharge Substate: " + - String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "

"; + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + ""; //0x2C4 708 PCS_logging content += "

PCS_dcdcMaxLvOutputCurrent: " + String(PCS_dcdcMaxLvOutputCurrent) + " A

"; content += "

PCS_dcdcCurrentLimit: " + String(PCS_dcdcCurrentLimit) + " A

"; @@ -597,7 +597,7 @@ String advanced_battery_processor(const String& var) { content += "

BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; content += - "

BMS PCS PWM Enabled: " + String(noYes[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; + "

BMS PCS PWM Enabled: " + String(datalayer_extended.tesla.battery_BMS_pcsPwmEnabled) + "

"; //bool //0x352 850 BMS_energyStatus content += "

Early BMS 0x352:

"; //if using older BMS <2021 and comment 0x352 without MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy * 100 / beginning_of_life) + "

"; @@ -607,7 +607,7 @@ String advanced_battery_processor(const String& var) { content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer) + " KWh

"; content += - "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; + "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "

"; //bool //0x352 850 BMS_energyStatus content += "

Late BMS 0x352 with Mux:

"; //if using newer BMS >2021 and comment 0x352 with MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "

"; @@ -617,7 +617,7 @@ String advanced_battery_processor(const String& var) { content += "

Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer_m1) + " KWh

"; content += "

Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " KWh

"; - content += "

Fully Charged: " + String(noYes[datalayer_extended.tesla.battery_fully_charged]) + "

"; + content += "

Fully Charged: " + String(datalayer_extended.tesla.battery_fully_charged) + "

"; //bool //0x392 BMS_packConfig content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; @@ -642,8 +642,8 @@ String advanced_battery_processor(const String& var) { content += "

Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh

"; content += "

HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW

"; content += - "

Not Enough Power For Heat Pump: " + String(noYes[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + - "

"; + "

Not Enough Power For Heat Pump: " + String(datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump) + + "

"; //bool content += "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; content += "

Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "

"; @@ -655,57 +655,57 @@ String advanced_battery_processor(const String& var) { content += "

Inlet Active Heat Target Temp: " + String(BMS_inletActiveHeatTargetT) + " DegC

"; content += "

Pack Temp Min: " + String(BMS_packTMin) + " DegC

"; content += "

Pack Temp Max: " + String(BMS_packTMax) + " DegC

"; - content += "

PCS No Flow Request: " + String(falseTrue[datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "

"; - content += "

BMS No Flow Request: " + String(falseTrue[datalayer_extended.tesla.BMS_noFlowRequest]) + "

"; + content += "

PCS No Flow Request: " + String(datalayer_extended.tesla.BMS_pcsNoFlowRequest) + "

"; //bool + content += "

BMS No Flow Request: " + String(datalayer_extended.tesla.BMS_noFlowRequest) + "

"; //bool //0x7AA 1962 HVP_debugMessage content += - "

HVP_gpioPassivePyroDepl: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) + "

"; - content += "

HVP_gpioPyroIsoEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPyroIsoEn]) + "

"; - content += "

HVP_gpioCpFaultIn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpFaultIn]) + "

"; + "

HVP_gpioPassivePyroDepl: " + String(datalayer_extended.tesla.HVP_gpioPassivePyroDepl) + "

"; //bool + content += "

HVP_gpioPyroIsoEn: " + String(datalayer_extended.tesla.HVP_gpioPyroIsoEn) + "

"; //bool + content += "

HVP_gpioCpFaultIn: " + String(datalayer_extended.tesla.HVP_gpioCpFaultIn) + "

"; //bool content += - "

HVP_gpioPackContPowerEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) + "

"; - content += "

HVP_gpioHvCablesOk: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvCablesOk]) + "

"; + "

HVP_gpioPackContPowerEn: " + String(datalayer_extended.tesla.HVP_gpioPackContPowerEn) + "

"; //bool + content += "

HVP_gpioHvCablesOk: " + String(datalayer_extended.tesla.HVP_gpioHvCablesOk) + "

"; //bool content += - "

HVP_gpioHvpSelfEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "

"; - content += "

HVP_gpioLed: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioLed]) + "

"; - content += "

HVP_gpioCrashSignal: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCrashSignal]) + "

"; + "

HVP_gpioHvpSelfEnable: " + String(datalayer_extended.tesla.HVP_gpioHvpSelfEnable) + "

"; //bool + content += "

HVP_gpioLed: " + String(datalayer_extended.tesla.HVP_gpioLed) + "

"; //bool + content += "

HVP_gpioCrashSignal: " + String(datalayer_extended.tesla.HVP_gpioCrashSignal) + "

"; //bool content += - "

HVP_gpioShuntDataReady: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioShuntDataReady]) + "

"; + "

HVP_gpioShuntDataReady: " + String(datalayer_extended.tesla.HVP_gpioShuntDataReady) + "

"; //bool content += - "

HVP_gpioFcContPosAux: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "

"; + "

HVP_gpioFcContPosAux: " + String(datalayer_extended.tesla.HVP_gpioFcContPosAux) + "

"; //bool content += - "

HVP_gpioFcContNegAux: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "

"; - content += "

HVP_gpioBmsEout: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioBmsEout]) + "

"; - content += "

HVP_gpioCpFaultOut: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpFaultOut]) + "

"; - content += "

HVP_gpioPyroPor: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPyroPor]) + "

"; - content += "

HVP_gpioShuntEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioShuntEn]) + "

"; - content += "

HVP_gpioHvpVerEn: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvpVerEn]) + "

"; + "

HVP_gpioFcContNegAux: " + String(datalayer_extended.tesla.HVP_gpioFcContNegAux) + "

"; //bool + content += "

HVP_gpioBmsEout: " + String(datalayer_extended.tesla.HVP_gpioBmsEout) + "

"; //bool + content += "

HVP_gpioCpFaultOut: " + String(datalayer_extended.tesla.HVP_gpioCpFaultOut) + "

"; //bool + content += "

HVP_gpioPyroPor: " + String(datalayer_extended.tesla.HVP_gpioPyroPor) + "

"; //bool + content += "

HVP_gpioShuntEn: " + String(datalayer_extended.tesla.HVP_gpioShuntEn) + "

"; //bool + content += "

HVP_gpioHvpVerEn: " + String(datalayer_extended.tesla.HVP_gpioHvpVerEn) + "

"; //bool content += "

HVP_gpioPackCoontPosFlywheel: " + - String(falseTrue[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) + "

"; + String(datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel) + ""; //bool content += - "

HVP_gpioCpLatchEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "

"; - content += "

HVP_gpioPcsEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsEnable]) + "

"; - content += "

HVP_gpioPcsDcdcPwmEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) + - "

"; + "

HVP_gpioCpLatchEnable: " + String(datalayer_extended.tesla.HVP_gpioCpLatchEnable) + "

"; //bool + content += "

HVP_gpioPcsEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsEnable) + "

"; //bool + content += "

HVP_gpioPcsDcdcPwmEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable) + + "

"; //bool content += - "

HVP_gpioPcsChargePwmEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable]) + - "

"; + "

HVP_gpioPcsChargePwmEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable) + + "

"; //bool content += - "

HVP_gpioFcContPowerEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioFcContPowerEnable]) + - "

"; - content += "

HVP_gpioHvilEnable: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioHvilEnable]) + "

"; - content += "

HVP_gpioSecDrdy: " + String(falseTrue[datalayer_extended.tesla.HVP_gpioSecDrdy]) + "

"; + "

HVP_gpioFcContPowerEnable: " + String(datalayer_extended.tesla.HVP_gpioFcContPowerEnable) + + "

"; //bool + content += "

HVP_gpioHvilEnable: " + String(datalayer_extended.tesla.HVP_gpioHvilEnable) + "

"; //bool + content += "

HVP_gpioSecDrdy: " + String(datalayer_extended.tesla.HVP_gpioSecDrdy) + "

"; //bool content += "

HVP_hvp1v5Ref: " + String(HVP_hvp1v5Ref) + " V

"; content += "

HVP_shuntCurrentDebug: " + String(HVP_shuntCurrentDebug) + " A

"; - content += "

HVP_packCurrentMia: " + String(falseTrue[datalayer_extended.tesla.HVP_packCurrentMia]) + "

"; - content += "

HVP_auxCurrentMia: " + String(falseTrue[datalayer_extended.tesla.HVP_auxCurrentMia]) + "

"; - content += "

HVP_currentSenseMia: " + String(falseTrue[datalayer_extended.tesla.HVP_currentSenseMia]) + "

"; + content += "

HVP_packCurrentMia: " + String(datalayer_extended.tesla.HVP_packCurrentMia) + "

"; //bool + content += "

HVP_auxCurrentMia: " + String(datalayer_extended.tesla.HVP_auxCurrentMia) + "

"; //bool + content += "

HVP_currentSenseMia: " + String(datalayer_extended.tesla.HVP_currentSenseMia) + "

"; //bool content += - "

HVP_shuntRefVoltageMismatch: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) + - "

"; + "

HVP_shuntRefVoltageMismatch: " + String(datalayer_extended.tesla.HVP_shuntRefVoltageMismatch) + + "

"; //bool content += - "

HVP_shuntThermistorMia: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntThermistorMia]) + "

"; - content += "

HVP_shuntHwMia: " + String(falseTrue[datalayer_extended.tesla.HVP_shuntHwMia]) + "

"; + "

HVP_shuntThermistorMia: " + String(datalayer_extended.tesla.HVP_shuntThermistorMia) + "

"; //bool + content += "

HVP_shuntHwMia: " + String(datalayer_extended.tesla.HVP_shuntHwMia) + "

"; //bool content += "

HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V

"; content += "

HVP_packVoltage: " + String(HVP_packVoltage) + " V

"; content += "

HVP_fcLinkVoltage: " + String(HVP_fcLinkVoltage) + " V

"; From b8e10c3b289dd37e9e9448428d6fb7243673ebb1 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Thu, 26 Dec 2024 10:36:33 +1300 Subject: [PATCH 121/225] Update bool values --- .../webserver/advanced_battery_html.cpp | 145 ++++++++---------- 1 file changed, 68 insertions(+), 77 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 5f1016e17..3e68190e0 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -502,20 +502,19 @@ String advanced_battery_processor(const String& var) { "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; content += "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; - content += "

Closing allowed?: " + String(datalayer_extended.tesla.packCtrsClosingAllowed) + "

"; //bool - content += "

Pyrotest in Progress: " + String(datalayer_extended.tesla.pyroTestInProgress) + "

"; //bool - content += "

Contactors Open Now Requested: " + - String(datalayer_extended.tesla.battery_packCtrsOpenNowRequested) + "

"; //bool + content += "

Closing allowed?: " + String(datalayer_extended.tesla.packCtrsClosingAllowed) + "

"; //bool + content += "

Pyrotest in Progress: " + String(datalayer_extended.tesla.pyroTestInProgress) + "

"; //bool content += - "

Contactors Open Requested: " + String(datalayer_extended.tesla.battery_packCtrsOpenRequested) + - "

"; //bool + "

Contactors Open Now Requested: " + String(datalayer_extended.tesla.battery_packCtrsOpenNowRequested) + + "

"; //bool + content += "

Contactors Open Requested: " + String(datalayer_extended.tesla.battery_packCtrsOpenRequested) + + "

"; //bool content += "

Contactors Request Status: " + String(HVP_contactor[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; content += "

Contactors Reset Request Required: " + - String(datalayer_extended.tesla.battery_packCtrsResetRequestRequired) + "

"; //bool - content += - "

DC Link Allowed to Energize:" + String(datalayer_extended.tesla.battery_dcLinkAllowedToEnergize) + - "

"; //bool + String(datalayer_extended.tesla.battery_packCtrsResetRequestRequired) + ""; //bool + content += "

DC Link Allowed to Energize:" + String(datalayer_extended.tesla.battery_dcLinkAllowedToEnergize) + + "

"; //bool // Comment what data you would like to dislay, order can be changed. //0x292 658 BMS_socStates content += "

Battery Beginning of Life: " + String(beginning_of_life) + " KWh

"; @@ -544,23 +543,23 @@ String advanced_battery_processor(const String& var) { "

Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "

"; content += "

Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "

"; - content += "

PCS Faulted: " + String(datalayer_extended.tesla.battery_PCS_dcdcFaulted) + "

"; //bool + content += "

PCS Faulted: " + String(datalayer_extended.tesla.battery_PCS_dcdcFaulted) + "

"; //bool content += "

Output Is Limited: " + String(datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited) + "

"; //bool content += "

Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A

"; - content += "

Precharge Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt) + - "

"; //bool - content += - "

12V Support Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt) + - "

"; // bool - content += "

Discharge Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt) + - "

"; //bool - content += - "

PWM Enable Line: " + String(datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine) + "

"; //bool - content += "

Supporting Fixed LV Target: " + - String(datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget) + "

"; //bool - content += "

Precharge Restart Cnt: " + - String(datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt) + "

"; //bool + content += + "

Precharge Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt) + "

"; //bool + content += "

12V Support Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt) + + "

"; // bool + content += + "

Discharge Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt) + "

"; //bool + content += + "

PWM Enable Line: " + String(datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine) + "

"; //bool + content += + "

Supporting Fixed LV Target: " + String(datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget) + + "

"; //bool + content += "

Precharge Restart Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt) + + "

"; //bool content += "

Initial Precharge Substate: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "

"; //0x2C4 708 PCS_logging @@ -597,7 +596,7 @@ String advanced_battery_processor(const String& var) { content += "

BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; content += - "

BMS PCS PWM Enabled: " + String(datalayer_extended.tesla.battery_BMS_pcsPwmEnabled) + "

"; //bool + "

BMS PCS PWM Enabled: " + String(datalayer_extended.tesla.battery_BMS_pcsPwmEnabled) + "

"; //bool //0x352 850 BMS_energyStatus content += "

Early BMS 0x352:

"; //if using older BMS <2021 and comment 0x352 without MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy * 100 / beginning_of_life) + "

"; @@ -607,7 +606,7 @@ String advanced_battery_processor(const String& var) { content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer) + " KWh

"; content += - "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "

"; //bool + "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "

"; //bool //0x352 850 BMS_energyStatus content += "

Late BMS 0x352 with Mux:

"; //if using newer BMS >2021 and comment 0x352 with MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "

"; @@ -617,7 +616,7 @@ String advanced_battery_processor(const String& var) { content += "

Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer_m1) + " KWh

"; content += "

Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " KWh

"; - content += "

Fully Charged: " + String(datalayer_extended.tesla.battery_fully_charged) + "

"; //bool + content += "

Fully Charged: " + String(datalayer_extended.tesla.battery_fully_charged) + "

"; //bool //0x392 BMS_packConfig content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; @@ -641,9 +640,8 @@ String advanced_battery_processor(const String& var) { content += "

Max Discharge Power: " + String(BMS_maxDischargePower) + " KW

"; content += "

Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh

"; content += "

HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW

"; - content += - "

Not Enough Power For Heat Pump: " + String(datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump) + - "

"; //bool + content += "

Not Enough Power For Heat Pump: " + String(datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump) + + "

"; //bool content += "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; content += "

Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "

"; @@ -655,57 +653,50 @@ String advanced_battery_processor(const String& var) { content += "

Inlet Active Heat Target Temp: " + String(BMS_inletActiveHeatTargetT) + " DegC

"; content += "

Pack Temp Min: " + String(BMS_packTMin) + " DegC

"; content += "

Pack Temp Max: " + String(BMS_packTMax) + " DegC

"; - content += "

PCS No Flow Request: " + String(datalayer_extended.tesla.BMS_pcsNoFlowRequest) + "

"; //bool - content += "

BMS No Flow Request: " + String(datalayer_extended.tesla.BMS_noFlowRequest) + "

"; //bool + content += "

PCS No Flow Request: " + String(datalayer_extended.tesla.BMS_pcsNoFlowRequest) + "

"; //bool + content += "

BMS No Flow Request: " + String(datalayer_extended.tesla.BMS_noFlowRequest) + "

"; //bool //0x7AA 1962 HVP_debugMessage content += - "

HVP_gpioPassivePyroDepl: " + String(datalayer_extended.tesla.HVP_gpioPassivePyroDepl) + "

"; //bool - content += "

HVP_gpioPyroIsoEn: " + String(datalayer_extended.tesla.HVP_gpioPyroIsoEn) + "

"; //bool - content += "

HVP_gpioCpFaultIn: " + String(datalayer_extended.tesla.HVP_gpioCpFaultIn) + "

"; //bool - content += - "

HVP_gpioPackContPowerEn: " + String(datalayer_extended.tesla.HVP_gpioPackContPowerEn) + "

"; //bool - content += "

HVP_gpioHvCablesOk: " + String(datalayer_extended.tesla.HVP_gpioHvCablesOk) + "

"; //bool - content += - "

HVP_gpioHvpSelfEnable: " + String(datalayer_extended.tesla.HVP_gpioHvpSelfEnable) + "

"; //bool - content += "

HVP_gpioLed: " + String(datalayer_extended.tesla.HVP_gpioLed) + "

"; //bool - content += "

HVP_gpioCrashSignal: " + String(datalayer_extended.tesla.HVP_gpioCrashSignal) + "

"; //bool - content += - "

HVP_gpioShuntDataReady: " + String(datalayer_extended.tesla.HVP_gpioShuntDataReady) + "

"; //bool - content += - "

HVP_gpioFcContPosAux: " + String(datalayer_extended.tesla.HVP_gpioFcContPosAux) + "

"; //bool - content += - "

HVP_gpioFcContNegAux: " + String(datalayer_extended.tesla.HVP_gpioFcContNegAux) + "

"; //bool - content += "

HVP_gpioBmsEout: " + String(datalayer_extended.tesla.HVP_gpioBmsEout) + "

"; //bool - content += "

HVP_gpioCpFaultOut: " + String(datalayer_extended.tesla.HVP_gpioCpFaultOut) + "

"; //bool - content += "

HVP_gpioPyroPor: " + String(datalayer_extended.tesla.HVP_gpioPyroPor) + "

"; //bool - content += "

HVP_gpioShuntEn: " + String(datalayer_extended.tesla.HVP_gpioShuntEn) + "

"; //bool - content += "

HVP_gpioHvpVerEn: " + String(datalayer_extended.tesla.HVP_gpioHvpVerEn) + "

"; //bool - content += "

HVP_gpioPackCoontPosFlywheel: " + - String(datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel) + "

"; //bool - content += - "

HVP_gpioCpLatchEnable: " + String(datalayer_extended.tesla.HVP_gpioCpLatchEnable) + "

"; //bool - content += "

HVP_gpioPcsEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsEnable) + "

"; //bool - content += "

HVP_gpioPcsDcdcPwmEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable) + - "

"; //bool - content += - "

HVP_gpioPcsChargePwmEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable) + - "

"; //bool - content += - "

HVP_gpioFcContPowerEnable: " + String(datalayer_extended.tesla.HVP_gpioFcContPowerEnable) + - "

"; //bool - content += "

HVP_gpioHvilEnable: " + String(datalayer_extended.tesla.HVP_gpioHvilEnable) + "

"; //bool - content += "

HVP_gpioSecDrdy: " + String(datalayer_extended.tesla.HVP_gpioSecDrdy) + "

"; //bool + "

HVP_gpioPassivePyroDepl: " + String(datalayer_extended.tesla.HVP_gpioPassivePyroDepl) + "

"; //bool + content += "

HVP_gpioPyroIsoEn: " + String(datalayer_extended.tesla.HVP_gpioPyroIsoEn) + "

"; //bool + content += "

HVP_gpioCpFaultIn: " + String(datalayer_extended.tesla.HVP_gpioCpFaultIn) + "

"; //bool + content += + "

HVP_gpioPackContPowerEn: " + String(datalayer_extended.tesla.HVP_gpioPackContPowerEn) + "

"; //bool + content += "

HVP_gpioHvCablesOk: " + String(datalayer_extended.tesla.HVP_gpioHvCablesOk) + "

"; //bool + content += "

HVP_gpioHvpSelfEnable: " + String(datalayer_extended.tesla.HVP_gpioHvpSelfEnable) + "

"; //bool + content += "

HVP_gpioLed: " + String(datalayer_extended.tesla.HVP_gpioLed) + "

"; //bool + content += "

HVP_gpioCrashSignal: " + String(datalayer_extended.tesla.HVP_gpioCrashSignal) + "

"; //bool + content += + "

HVP_gpioShuntDataReady: " + String(datalayer_extended.tesla.HVP_gpioShuntDataReady) + "

"; //bool + content += "

HVP_gpioFcContPosAux: " + String(datalayer_extended.tesla.HVP_gpioFcContPosAux) + "

"; //bool + content += "

HVP_gpioFcContNegAux: " + String(datalayer_extended.tesla.HVP_gpioFcContNegAux) + "

"; //bool + content += "

HVP_gpioBmsEout: " + String(datalayer_extended.tesla.HVP_gpioBmsEout) + "

"; //bool + content += "

HVP_gpioCpFaultOut: " + String(datalayer_extended.tesla.HVP_gpioCpFaultOut) + "

"; //bool + content += "

HVP_gpioPyroPor: " + String(datalayer_extended.tesla.HVP_gpioPyroPor) + "

"; //bool + content += "

HVP_gpioShuntEn: " + String(datalayer_extended.tesla.HVP_gpioShuntEn) + "

"; //bool + content += "

HVP_gpioHvpVerEn: " + String(datalayer_extended.tesla.HVP_gpioHvpVerEn) + "

"; //bool + content += "

HVP_gpioPackCoontPosFlywheel: " + String(datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel) + + "

"; //bool + content += "

HVP_gpioCpLatchEnable: " + String(datalayer_extended.tesla.HVP_gpioCpLatchEnable) + "

"; //bool + content += "

HVP_gpioPcsEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsEnable) + "

"; //bool + content += + "

HVP_gpioPcsDcdcPwmEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable) + "

"; //bool + content += "

HVP_gpioPcsChargePwmEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable) + + "

"; //bool + content += "

HVP_gpioFcContPowerEnable: " + String(datalayer_extended.tesla.HVP_gpioFcContPowerEnable) + + "

"; //bool + content += "

HVP_gpioHvilEnable: " + String(datalayer_extended.tesla.HVP_gpioHvilEnable) + "

"; //bool + content += "

HVP_gpioSecDrdy: " + String(datalayer_extended.tesla.HVP_gpioSecDrdy) + "

"; //bool content += "

HVP_hvp1v5Ref: " + String(HVP_hvp1v5Ref) + " V

"; content += "

HVP_shuntCurrentDebug: " + String(HVP_shuntCurrentDebug) + " A

"; - content += "

HVP_packCurrentMia: " + String(datalayer_extended.tesla.HVP_packCurrentMia) + "

"; //bool - content += "

HVP_auxCurrentMia: " + String(datalayer_extended.tesla.HVP_auxCurrentMia) + "

"; //bool - content += "

HVP_currentSenseMia: " + String(datalayer_extended.tesla.HVP_currentSenseMia) + "

"; //bool - content += - "

HVP_shuntRefVoltageMismatch: " + String(datalayer_extended.tesla.HVP_shuntRefVoltageMismatch) + - "

"; //bool - content += - "

HVP_shuntThermistorMia: " + String(datalayer_extended.tesla.HVP_shuntThermistorMia) + "

"; //bool - content += "

HVP_shuntHwMia: " + String(datalayer_extended.tesla.HVP_shuntHwMia) + "

"; //bool + content += "

HVP_packCurrentMia: " + String(datalayer_extended.tesla.HVP_packCurrentMia) + "

"; //bool + content += "

HVP_auxCurrentMia: " + String(datalayer_extended.tesla.HVP_auxCurrentMia) + "

"; //bool + content += "

HVP_currentSenseMia: " + String(datalayer_extended.tesla.HVP_currentSenseMia) + "

"; //bool + content += "

HVP_shuntRefVoltageMismatch: " + String(datalayer_extended.tesla.HVP_shuntRefVoltageMismatch) + + "

"; //bool + content += + "

HVP_shuntThermistorMia: " + String(datalayer_extended.tesla.HVP_shuntThermistorMia) + "

"; //bool + content += "

HVP_shuntHwMia: " + String(datalayer_extended.tesla.HVP_shuntHwMia) + "

"; //bool content += "

HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V

"; content += "

HVP_packVoltage: " + String(HVP_packVoltage) + " V

"; content += "

HVP_fcLinkVoltage: " + String(HVP_fcLinkVoltage) + " V

"; From aadd9df47083f93d017d67b971ac26865c888080 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Thu, 26 Dec 2024 12:33:41 +1300 Subject: [PATCH 122/225] Add delay adding 3s delay to allow cell voltage min/max to be read before transmit_can to stop false under/over cell voltage events. --- Software/src/battery/TESLA-BATTERY.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index cd6afd08d..0c83fab62 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1226,6 +1226,8 @@ the first, for a few cycles, then stop all messages which causes the contactor } #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) + delay(3000) // adding 3s delay to allow cell voltage min/max to be read before transmit_can to stop false under/over cell voltage events. + //Send 30ms message if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { // Check if sending of CAN messages has been delayed too much. From 3ef5bec6e2530a7ee11e202ff03c7bf4d9bb18d8 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Thu, 26 Dec 2024 12:35:28 +1300 Subject: [PATCH 123/225] Add delay adding 3s delay to allow cell voltage min/max to be read before transmit_can to stop false under/over cell voltage events. --- Software/src/battery/TESLA-BATTERY.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 0c83fab62..8decbee2b 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1226,10 +1226,11 @@ the first, for a few cycles, then stop all messages which causes the contactor } #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) - delay(3000) // adding 3s delay to allow cell voltage min/max to be read before transmit_can to stop false under/over cell voltage events. + delay( + 3000) // adding 3s delay to allow cell voltage min/max to be read before transmit_can to stop false under/over cell voltage events. - //Send 30ms message - if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { + //Send 30ms message + if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { // Check if sending of CAN messages has been delayed too much. if ((currentMillis - previousMillis30 >= INTERVAL_30_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis30)); From fc90d3eca92857b19be0e84e61bf5bde628ae368 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:02:35 +1300 Subject: [PATCH 124/225] Update TESLA-BATTERY.cpp Change location of delay --- Software/src/battery/TESLA-BATTERY.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 8decbee2b..65257afe5 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1198,6 +1198,9 @@ the first, for a few cycles, then stop all messages which causes the contactor unsigned long currentMillis = millis(); + delay( + 3000); // adding 3s delay to allow cell voltage min/max to be read before transmit_can to stop false under/over cell voltage events. + #if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { if (currentMillis - lastSend1CF >= 10) { @@ -1226,9 +1229,6 @@ the first, for a few cycles, then stop all messages which causes the contactor } #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) - delay( - 3000) // adding 3s delay to allow cell voltage min/max to be read before transmit_can to stop false under/over cell voltage events. - //Send 30ms message if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { // Check if sending of CAN messages has been delayed too much. From 22c8d7dbe3b3a014594942560ec9dadf9a43d1c6 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:03:03 +1300 Subject: [PATCH 125/225] Update TESLA-BATTERY.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 65257afe5..e41f581cd 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -1229,8 +1229,8 @@ the first, for a few cycles, then stop all messages which causes the contactor } #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) - //Send 30ms message - if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { + //Send 30ms message + if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { // Check if sending of CAN messages has been delayed too much. if ((currentMillis - previousMillis30 >= INTERVAL_30_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis30)); From 7d9f8cf72d7f27ca7f1601b78f4dcff6fcc31320 Mon Sep 17 00:00:00 2001 From: lenvm Date: Thu, 26 Dec 2024 16:15:50 +0100 Subject: [PATCH 126/225] add LED pin, that turns on when SMA allows contactor closing --- Software/src/inverter/BYD-SMA.cpp | 19 ++++++++++++++++--- Software/src/inverter/SMA-CAN.cpp | 18 +++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Software/src/inverter/BYD-SMA.cpp b/Software/src/inverter/BYD-SMA.cpp index 34e33063a..4892eacf0 100644 --- a/Software/src/inverter/BYD-SMA.cpp +++ b/Software/src/inverter/BYD-SMA.cpp @@ -130,10 +130,18 @@ void update_values_can_inverter() { //This function maps all the values fetched } //Error bits - if (!datalayer.system.status.inverter_allows_contactor_closing) { - SMA_158.data.u8[2] = 0x6A; - } else { + if (datalayer.system.status.inverter_allows_contactor_closing) { SMA_158.data.u8[2] = 0xAA; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, + HIGH); // Turn on LED to indicate that SMA inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN + } else { + SMA_158.data.u8[2] = 0x6A; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, + LOW); // Turn off LED to indicate that SMA inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } /* @@ -251,10 +259,15 @@ void send_can_inverter() { } } } + void setup_inverter(void) { // Performs one time setup at startup over CAN bus strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box HVS over SMA CAN", 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + pinMode(INVERTER_CONTACTOR_ENABLE_LED_PIN, OUTPUT); + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, LOW); // Turn LED off, until inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } #endif diff --git a/Software/src/inverter/SMA-CAN.cpp b/Software/src/inverter/SMA-CAN.cpp index 5831406d2..43ccad0d5 100644 --- a/Software/src/inverter/SMA-CAN.cpp +++ b/Software/src/inverter/SMA-CAN.cpp @@ -127,10 +127,18 @@ void update_values_can_inverter() { //This function maps all the values fetched } //Error bits - if (!datalayer.system.status.inverter_allows_contactor_closing) { - SMA_158.data.u8[2] = 0x6A; - } else { + if (datalayer.system.status.inverter_allows_contactor_closing) { SMA_158.data.u8[2] = 0xAA; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, + HIGH); // Turn on LED to indicate that SMA inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN + } else { + SMA_158.data.u8[2] = 0x6A; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, + LOW); // Turn off LED to indicate that SMA inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } /* @@ -253,5 +261,9 @@ void send_can_inverter() { void setup_inverter(void) { // Performs one time setup at startup over CAN bus strncpy(datalayer.system.info.inverter_protocol, "SMA CAN", 63); datalayer.system.info.inverter_protocol[63] = '\0'; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + pinMode(INVERTER_CONTACTOR_ENABLE_LED_PIN, OUTPUT); + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, LOW); // Turn LED off, until inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } #endif From b9a067800782c6dd54acf8b745c330a6a2a4995b Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Fri, 27 Dec 2024 19:21:16 +1300 Subject: [PATCH 127/225] Update advanced_battery_html.cpp Changed the displayed data format. --- .../webserver/advanced_battery_html.cpp | 111 +++++++++--------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 3e68190e0..12d5f8036 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -495,6 +495,7 @@ String advanced_battery_processor(const String& var) { static const char* HVP_contactor[] = {"NOT_ACTIVE", "ACTIVE", "COMPLETED"}; static const char* falseTrue[] = {"False", "True"}; static const char* noYes[] = {"No", "Yes"}; + static const char* Fault[] = {"NOT_ACTIVE", "ACTIVE"}; //0x20A 522 HVP_contatorState content += "

Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "

"; content += "

HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "

"; @@ -502,18 +503,18 @@ String advanced_battery_processor(const String& var) { "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; content += "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; - content += "

Closing allowed?: " + String(datalayer_extended.tesla.packCtrsClosingAllowed) + "

"; //bool - content += "

Pyrotest in Progress: " + String(datalayer_extended.tesla.pyroTestInProgress) + "

"; //bool + content += "

Closing allowed?: " + String(noYes[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; //bool + content += "

Pyrotest in Progress: " + String(noYes[datalayer_extended.tesla.pyroTestInProgress]) + "

"; //bool content += - "

Contactors Open Now Requested: " + String(datalayer_extended.tesla.battery_packCtrsOpenNowRequested) + + "

Contactors Open Now Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; //bool - content += "

Contactors Open Requested: " + String(datalayer_extended.tesla.battery_packCtrsOpenRequested) + + content += "

Contactors Open Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + "

"; //bool content += "

Contactors Request Status: " + String(HVP_contactor[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; content += "

Contactors Reset Request Required: " + - String(datalayer_extended.tesla.battery_packCtrsResetRequestRequired) + "

"; //bool - content += "

DC Link Allowed to Energize:" + String(datalayer_extended.tesla.battery_dcLinkAllowedToEnergize) + + String(noYes[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; //bool + content += "

DC Link Allowed to Energize: " + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + "

"; //bool // Comment what data you would like to dislay, order can be changed. //0x292 658 BMS_socStates @@ -543,22 +544,22 @@ String advanced_battery_processor(const String& var) { "

Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "

"; content += "

Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "

"; - content += "

PCS Faulted: " + String(datalayer_extended.tesla.battery_PCS_dcdcFaulted) + "

"; //bool + content += "

PCS Faulted: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcFaulted]) + "

"; //bool content += - "

Output Is Limited: " + String(datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited) + "

"; //bool + "

Output Is Limited: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + "

"; //bool content += "

Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A

"; content += - "

Precharge Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt) + "

"; //bool - content += "

12V Support Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt) + + "

Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) + "

"; //bool + content += "

12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) + "

"; // bool content += - "

Discharge Rty Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt) + "

"; //bool + "

Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) + "

"; //bool content += - "

PWM Enable Line: " + String(datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine) + "

"; //bool + "

PWM Enable Line: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + "

"; //bool content += - "

Supporting Fixed LV Target: " + String(datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget) + + "

Supporting Fixed LV Target: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "

"; //bool - content += "

Precharge Restart Cnt: " + String(datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt) + + content += "

Precharge Restart Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "

"; //bool content += "

Initial Precharge Substate: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "

"; @@ -596,7 +597,7 @@ String advanced_battery_processor(const String& var) { content += "

BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; content += - "

BMS PCS PWM Enabled: " + String(datalayer_extended.tesla.battery_BMS_pcsPwmEnabled) + "

"; //bool + "

BMS PCS PWM Enabled: " + String(Fault[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; //bool //0x352 850 BMS_energyStatus content += "

Early BMS 0x352:

"; //if using older BMS <2021 and comment 0x352 without MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy * 100 / beginning_of_life) + "

"; @@ -606,7 +607,7 @@ String advanced_battery_processor(const String& var) { content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer) + " KWh

"; content += - "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "

"; //bool + "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; //bool //0x352 850 BMS_energyStatus content += "

Late BMS 0x352 with Mux:

"; //if using newer BMS >2021 and comment 0x352 with MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "

"; @@ -616,11 +617,11 @@ String advanced_battery_processor(const String& var) { content += "

Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer_m1) + " KWh

"; content += "

Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " KWh

"; - content += "

Fully Charged: " + String(datalayer_extended.tesla.battery_fully_charged) + "

"; //bool + content += "

Fully Charged: " + String(noYes[datalayer_extended.tesla.battery_fully_charged]) + "

"; //bool //0x392 BMS_packConfig - content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; - content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; - content += "

reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "

"; + //content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; + //content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; + //content += "

reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "

"; content += "

Battery Pack Mass: " + String(packMass) + " KG

"; content += "

Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V

"; //0x2D2 722 BMSVAlimits @@ -640,7 +641,7 @@ String advanced_battery_processor(const String& var) { content += "

Max Discharge Power: " + String(BMS_maxDischargePower) + " KW

"; content += "

Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh

"; content += "

HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW

"; - content += "

Not Enough Power For Heat Pump: " + String(datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump) + + content += "

Not Enough Power For Heat Pump: " + String(falseTrue[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + "

"; //bool content += "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; @@ -653,50 +654,50 @@ String advanced_battery_processor(const String& var) { content += "

Inlet Active Heat Target Temp: " + String(BMS_inletActiveHeatTargetT) + " DegC

"; content += "

Pack Temp Min: " + String(BMS_packTMin) + " DegC

"; content += "

Pack Temp Max: " + String(BMS_packTMax) + " DegC

"; - content += "

PCS No Flow Request: " + String(datalayer_extended.tesla.BMS_pcsNoFlowRequest) + "

"; //bool - content += "

BMS No Flow Request: " + String(datalayer_extended.tesla.BMS_noFlowRequest) + "

"; //bool + content += "

PCS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "

"; //bool + content += "

BMS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_noFlowRequest]) + "

"; //bool //0x7AA 1962 HVP_debugMessage content += - "

HVP_gpioPassivePyroDepl: " + String(datalayer_extended.tesla.HVP_gpioPassivePyroDepl) + "

"; //bool - content += "

HVP_gpioPyroIsoEn: " + String(datalayer_extended.tesla.HVP_gpioPyroIsoEn) + "

"; //bool - content += "

HVP_gpioCpFaultIn: " + String(datalayer_extended.tesla.HVP_gpioCpFaultIn) + "

"; //bool - content += - "

HVP_gpioPackContPowerEn: " + String(datalayer_extended.tesla.HVP_gpioPackContPowerEn) + "

"; //bool - content += "

HVP_gpioHvCablesOk: " + String(datalayer_extended.tesla.HVP_gpioHvCablesOk) + "

"; //bool - content += "

HVP_gpioHvpSelfEnable: " + String(datalayer_extended.tesla.HVP_gpioHvpSelfEnable) + "

"; //bool - content += "

HVP_gpioLed: " + String(datalayer_extended.tesla.HVP_gpioLed) + "

"; //bool - content += "

HVP_gpioCrashSignal: " + String(datalayer_extended.tesla.HVP_gpioCrashSignal) + "

"; //bool - content += - "

HVP_gpioShuntDataReady: " + String(datalayer_extended.tesla.HVP_gpioShuntDataReady) + "

"; //bool - content += "

HVP_gpioFcContPosAux: " + String(datalayer_extended.tesla.HVP_gpioFcContPosAux) + "

"; //bool - content += "

HVP_gpioFcContNegAux: " + String(datalayer_extended.tesla.HVP_gpioFcContNegAux) + "

"; //bool - content += "

HVP_gpioBmsEout: " + String(datalayer_extended.tesla.HVP_gpioBmsEout) + "

"; //bool - content += "

HVP_gpioCpFaultOut: " + String(datalayer_extended.tesla.HVP_gpioCpFaultOut) + "

"; //bool - content += "

HVP_gpioPyroPor: " + String(datalayer_extended.tesla.HVP_gpioPyroPor) + "

"; //bool - content += "

HVP_gpioShuntEn: " + String(datalayer_extended.tesla.HVP_gpioShuntEn) + "

"; //bool - content += "

HVP_gpioHvpVerEn: " + String(datalayer_extended.tesla.HVP_gpioHvpVerEn) + "

"; //bool - content += "

HVP_gpioPackCoontPosFlywheel: " + String(datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel) + + "

HVP_gpioPassivePyroDepl: " + String(Fault[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) + "

"; //bool + content += "

HVP_gpioPyroIsoEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroIsoEn]) + "

"; //bool + content += "

HVP_gpioCpFaultIn: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultIn]) + "

"; //bool + content += + "

HVP_gpioPackContPowerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) + "

"; //bool + content += "

HVP_gpioHvCablesOk: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvCablesOk]) + "

"; //bool + content += "

HVP_gpioHvpSelfEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "

"; //bool + content += "

HVP_gpioLed: " + String(Fault[datalayer_extended.tesla.HVP_gpioLed]) + "

"; //bool + content += "

HVP_gpioCrashSignal: " + String(Fault[datalayer_extended.tesla.HVP_gpioCrashSignal]) + "

"; //bool + content += + "

HVP_gpioShuntDataReady: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntDataReady]) + "

"; //bool + content += "

HVP_gpioFcContPosAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "

"; //bool + content += "

HVP_gpioFcContNegAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "

"; //bool + content += "

HVP_gpioBmsEout: " + String(Fault[datalayer_extended.tesla.HVP_gpioBmsEout]) + "

"; //bool + content += "

HVP_gpioCpFaultOut: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultOut]) + "

"; //bool + content += "

HVP_gpioPyroPor: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroPor]) + "

"; //bool + content += "

HVP_gpioShuntEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntEn]) + "

"; //bool + content += "

HVP_gpioHvpVerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpVerEn]) + "

"; //bool + content += "

HVP_gpioPackCoontPosFlywheel: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) + "

"; //bool - content += "

HVP_gpioCpLatchEnable: " + String(datalayer_extended.tesla.HVP_gpioCpLatchEnable) + "

"; //bool - content += "

HVP_gpioPcsEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsEnable) + "

"; //bool + content += "

HVP_gpioCpLatchEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "

"; //bool + content += "

HVP_gpioPcsEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsEnable]) + "

"; //bool content += - "

HVP_gpioPcsDcdcPwmEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable) + "

"; //bool - content += "

HVP_gpioPcsChargePwmEnable: " + String(datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable) + + "

HVP_gpioPcsDcdcPwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) + "

"; //bool + content += "

HVP_gpioPcsChargePwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable]) + "

"; //bool - content += "

HVP_gpioFcContPowerEnable: " + String(datalayer_extended.tesla.HVP_gpioFcContPowerEnable) + + content += "

HVP_gpioFcContPowerEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPowerEnable]) + "

"; //bool - content += "

HVP_gpioHvilEnable: " + String(datalayer_extended.tesla.HVP_gpioHvilEnable) + "

"; //bool - content += "

HVP_gpioSecDrdy: " + String(datalayer_extended.tesla.HVP_gpioSecDrdy) + "

"; //bool + content += "

HVP_gpioHvilEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvilEnable]) + "

"; //bool + content += "

HVP_gpioSecDrdy: " + String(Fault[datalayer_extended.tesla.HVP_gpioSecDrdy]) + "

"; //bool content += "

HVP_hvp1v5Ref: " + String(HVP_hvp1v5Ref) + " V

"; content += "

HVP_shuntCurrentDebug: " + String(HVP_shuntCurrentDebug) + " A

"; - content += "

HVP_packCurrentMia: " + String(datalayer_extended.tesla.HVP_packCurrentMia) + "

"; //bool - content += "

HVP_auxCurrentMia: " + String(datalayer_extended.tesla.HVP_auxCurrentMia) + "

"; //bool - content += "

HVP_currentSenseMia: " + String(datalayer_extended.tesla.HVP_currentSenseMia) + "

"; //bool - content += "

HVP_shuntRefVoltageMismatch: " + String(datalayer_extended.tesla.HVP_shuntRefVoltageMismatch) + + content += "

HVP_packCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_packCurrentMia]) + "

"; //bool + content += "

HVP_auxCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_auxCurrentMia]) + "

"; //bool + content += "

HVP_currentSenseMia: " + String(noYes[datalayer_extended.tesla.HVP_currentSenseMia]) + "

"; //bool + content += "

HVP_shuntRefVoltageMismatch: " + String(noYes[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) + "

"; //bool content += - "

HVP_shuntThermistorMia: " + String(datalayer_extended.tesla.HVP_shuntThermistorMia) + "

"; //bool - content += "

HVP_shuntHwMia: " + String(datalayer_extended.tesla.HVP_shuntHwMia) + "

"; //bool + "

HVP_shuntThermistorMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntThermistorMia]) + "

"; //bool + content += "

HVP_shuntHwMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntHwMia]) + "

"; //bool content += "

HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V

"; content += "

HVP_packVoltage: " + String(HVP_packVoltage) + " V

"; content += "

HVP_fcLinkVoltage: " + String(HVP_fcLinkVoltage) + " V

"; From 256bf19201427b2fc6c207472ea8029be6f5d356 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Fri, 27 Dec 2024 19:21:25 +1300 Subject: [PATCH 128/225] Update advanced_battery_html.cpp --- .../webserver/advanced_battery_html.cpp | 141 ++++++++++-------- 1 file changed, 79 insertions(+), 62 deletions(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 12d5f8036..c15697148 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -503,19 +503,22 @@ String advanced_battery_processor(const String& var) { "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; content += "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; - content += "

Closing allowed?: " + String(noYes[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; //bool - content += "

Pyrotest in Progress: " + String(noYes[datalayer_extended.tesla.pyroTestInProgress]) + "

"; //bool content += - "

Contactors Open Now Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + + "

Closing allowed?: " + String(noYes[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; //bool + content += + "

Pyrotest in Progress: " + String(noYes[datalayer_extended.tesla.pyroTestInProgress]) + "

"; //bool + content += "

Contactors Open Now Requested: " + + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; //bool + content += + "

Contactors Open Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + "

"; //bool - content += "

Contactors Open Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + - "

"; //bool content += "

Contactors Request Status: " + String(HVP_contactor[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; content += "

Contactors Reset Request Required: " + String(noYes[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; //bool - content += "

DC Link Allowed to Energize: " + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + - "

"; //bool + content += + "

DC Link Allowed to Energize: " + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + + "

"; //bool // Comment what data you would like to dislay, order can be changed. //0x292 658 BMS_socStates content += "

Battery Beginning of Life: " + String(beginning_of_life) + " KWh

"; @@ -545,22 +548,22 @@ String advanced_battery_processor(const String& var) { content += "

Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "

"; content += "

PCS Faulted: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcFaulted]) + "

"; //bool - content += - "

Output Is Limited: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + "

"; //bool + content += "

Output Is Limited: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + + "

"; //bool content += "

Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A

"; + content += "

Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) + + "

"; //bool content += - "

Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) + "

"; //bool - content += "

12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) + - "

"; // bool - content += - "

Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) + "

"; //bool - content += - "

PWM Enable Line: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + "

"; //bool - content += - "

Supporting Fixed LV Target: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + - "

"; //bool - content += "

Precharge Restart Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + + "

12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) + + "

"; // bool + content += "

Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) + "

"; //bool + content += "

PWM Enable Line: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + + "

"; //bool + content += "

Supporting Fixed LV Target: " + + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "

"; //bool + content += "

Precharge Restart Cnt: " + + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "

"; //bool content += "

Initial Precharge Substate: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "

"; //0x2C4 708 PCS_logging @@ -596,8 +599,8 @@ String advanced_battery_processor(const String& var) { content += "

BMS HV State: " + String(BMS_hvState[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; content += "

BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; - content += - "

BMS PCS PWM Enabled: " + String(Fault[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "

"; //bool + content += "

BMS PCS PWM Enabled: " + String(Fault[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + + "

"; //bool //0x352 850 BMS_energyStatus content += "

Early BMS 0x352:

"; //if using older BMS <2021 and comment 0x352 without MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy * 100 / beginning_of_life) + "

"; @@ -606,8 +609,8 @@ String advanced_battery_processor(const String& var) { content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " KWh

"; content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh

"; content += "

Energy Buffer: " + String(energy_buffer) + " KWh

"; - content += - "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + "

"; //bool + content += "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + + "

"; //bool //0x352 850 BMS_energyStatus content += "

Late BMS 0x352 with Mux:

"; //if using newer BMS >2021 and comment 0x352 with MUX content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "

"; @@ -641,8 +644,8 @@ String advanced_battery_processor(const String& var) { content += "

Max Discharge Power: " + String(BMS_maxDischargePower) + " KW

"; content += "

Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh

"; content += "

HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW

"; - content += "

Not Enough Power For Heat Pump: " + String(falseTrue[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + - "

"; //bool + content += "

Not Enough Power For Heat Pump: " + + String(falseTrue[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + "

"; //bool content += "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; content += "

Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "

"; @@ -654,50 +657,64 @@ String advanced_battery_processor(const String& var) { content += "

Inlet Active Heat Target Temp: " + String(BMS_inletActiveHeatTargetT) + " DegC

"; content += "

Pack Temp Min: " + String(BMS_packTMin) + " DegC

"; content += "

Pack Temp Max: " + String(BMS_packTMax) + " DegC

"; - content += "

PCS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "

"; //bool - content += "

BMS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_noFlowRequest]) + "

"; //bool + content += + "

PCS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "

"; //bool + content += + "

BMS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_noFlowRequest]) + "

"; //bool //0x7AA 1962 HVP_debugMessage + content += "

HVP_gpioPassivePyroDepl: " + String(Fault[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) + + "

"; //bool + content += "

HVP_gpioPyroIsoEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroIsoEn]) + "

"; //bool + content += "

HVP_gpioCpFaultIn: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultIn]) + "

"; //bool + content += "

HVP_gpioPackContPowerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) + + "

"; //bool + content += + "

HVP_gpioHvCablesOk: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvCablesOk]) + "

"; //bool + content += + "

HVP_gpioHvpSelfEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "

"; //bool + content += "

HVP_gpioLed: " + String(Fault[datalayer_extended.tesla.HVP_gpioLed]) + "

"; //bool + content += + "

HVP_gpioCrashSignal: " + String(Fault[datalayer_extended.tesla.HVP_gpioCrashSignal]) + "

"; //bool + content += "

HVP_gpioShuntDataReady: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntDataReady]) + + "

"; //bool + content += + "

HVP_gpioFcContPosAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "

"; //bool + content += + "

HVP_gpioFcContNegAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "

"; //bool + content += "

HVP_gpioBmsEout: " + String(Fault[datalayer_extended.tesla.HVP_gpioBmsEout]) + "

"; //bool + content += + "

HVP_gpioCpFaultOut: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultOut]) + "

"; //bool + content += "

HVP_gpioPyroPor: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroPor]) + "

"; //bool + content += "

HVP_gpioShuntEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntEn]) + "

"; //bool + content += "

HVP_gpioHvpVerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpVerEn]) + "

"; //bool content += - "

HVP_gpioPassivePyroDepl: " + String(Fault[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) + "

"; //bool - content += "

HVP_gpioPyroIsoEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroIsoEn]) + "

"; //bool - content += "

HVP_gpioCpFaultIn: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultIn]) + "

"; //bool - content += - "

HVP_gpioPackContPowerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) + "

"; //bool - content += "

HVP_gpioHvCablesOk: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvCablesOk]) + "

"; //bool - content += "

HVP_gpioHvpSelfEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "

"; //bool - content += "

HVP_gpioLed: " + String(Fault[datalayer_extended.tesla.HVP_gpioLed]) + "

"; //bool - content += "

HVP_gpioCrashSignal: " + String(Fault[datalayer_extended.tesla.HVP_gpioCrashSignal]) + "

"; //bool - content += - "

HVP_gpioShuntDataReady: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntDataReady]) + "

"; //bool - content += "

HVP_gpioFcContPosAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "

"; //bool - content += "

HVP_gpioFcContNegAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "

"; //bool - content += "

HVP_gpioBmsEout: " + String(Fault[datalayer_extended.tesla.HVP_gpioBmsEout]) + "

"; //bool - content += "

HVP_gpioCpFaultOut: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultOut]) + "

"; //bool - content += "

HVP_gpioPyroPor: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroPor]) + "

"; //bool - content += "

HVP_gpioShuntEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntEn]) + "

"; //bool - content += "

HVP_gpioHvpVerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpVerEn]) + "

"; //bool - content += "

HVP_gpioPackCoontPosFlywheel: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) + - "

"; //bool - content += "

HVP_gpioCpLatchEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "

"; //bool - content += "

HVP_gpioPcsEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsEnable]) + "

"; //bool - content += - "

HVP_gpioPcsDcdcPwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) + "

"; //bool + "

HVP_gpioPackCoontPosFlywheel: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) + + "

"; //bool + content += + "

HVP_gpioCpLatchEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "

"; //bool + content += "

HVP_gpioPcsEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsEnable]) + "

"; //bool + content += "

HVP_gpioPcsDcdcPwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) + + "

"; //bool content += "

HVP_gpioPcsChargePwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable]) + "

"; //bool content += "

HVP_gpioFcContPowerEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPowerEnable]) + - "

"; //bool - content += "

HVP_gpioHvilEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvilEnable]) + "

"; //bool - content += "

HVP_gpioSecDrdy: " + String(Fault[datalayer_extended.tesla.HVP_gpioSecDrdy]) + "

"; //bool + ""; //bool + content += + "

HVP_gpioHvilEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvilEnable]) + "

"; //bool + content += "

HVP_gpioSecDrdy: " + String(Fault[datalayer_extended.tesla.HVP_gpioSecDrdy]) + "

"; //bool content += "

HVP_hvp1v5Ref: " + String(HVP_hvp1v5Ref) + " V

"; content += "

HVP_shuntCurrentDebug: " + String(HVP_shuntCurrentDebug) + " A

"; - content += "

HVP_packCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_packCurrentMia]) + "

"; //bool - content += "

HVP_auxCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_auxCurrentMia]) + "

"; //bool - content += "

HVP_currentSenseMia: " + String(noYes[datalayer_extended.tesla.HVP_currentSenseMia]) + "

"; //bool - content += "

HVP_shuntRefVoltageMismatch: " + String(noYes[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) + - "

"; //bool content += - "

HVP_shuntThermistorMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntThermistorMia]) + "

"; //bool - content += "

HVP_shuntHwMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntHwMia]) + "

"; //bool + "

HVP_packCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_packCurrentMia]) + "

"; //bool + content += "

HVP_auxCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_auxCurrentMia]) + "

"; //bool + content += + "

HVP_currentSenseMia: " + String(noYes[datalayer_extended.tesla.HVP_currentSenseMia]) + "

"; //bool + content += + "

HVP_shuntRefVoltageMismatch: " + String(noYes[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) + + "

"; //bool + content += "

HVP_shuntThermistorMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntThermistorMia]) + + "

"; //bool + content += "

HVP_shuntHwMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntHwMia]) + "

"; //bool content += "

HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V

"; content += "

HVP_packVoltage: " + String(HVP_packVoltage) + " V

"; content += "

HVP_fcLinkVoltage: " + String(HVP_fcLinkVoltage) + " V

"; From f27408b2f3a52e684949e69bb364f21992cb78b7 Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sat, 28 Dec 2024 09:11:04 +1300 Subject: [PATCH 129/225] Update TESLA-BATTERY.cpp Update 0x221 send time to 50ms. Adjust default values before CAN mapping cell voltage, remove delay that was not working. --- Software/src/battery/TESLA-BATTERY.cpp | 35 ++++++++++++-------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index e41f581cd..2467e072d 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -8,8 +8,8 @@ /* Do not change code below unless you are sure what you are doing */ /* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */ -static unsigned long previousMillis30 = 0; // will store last time a 30ms CAN Message was send - +static unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was send +//0x221 545 VCFRONT_LVPowerState: "GenMsgCycleTime" 50ms CAN_frame TESLA_221_1 = { .FD = false, .ext_ID = false, @@ -42,9 +42,9 @@ static uint16_t battery_ideal_energy_remaining = 0; // kWh static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh static uint16_t battery_nominal_energy_remaining = 0; // kWh static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh -static uint16_t battery_nominal_full_pack_energy = 600; // Kwh -static uint16_t battery_nominal_full_pack_energy_m0 = 600; // Kwh -static uint16_t battery_beginning_of_life = 600; // kWh +static uint16_t battery_nominal_full_pack_energy = 0; // Kwh +static uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh +static uint16_t battery_beginning_of_life = 0; // kWh static uint16_t battery_charge_time_remaining = 0; // Minutes static uint16_t battery_regenerative_limit = 0; static uint16_t battery_discharge_limit = 0; @@ -62,8 +62,8 @@ static uint16_t battery_soc_min = 0; static uint16_t battery_soc_max = 0; static uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui static uint16_t battery_soc_ave = 0; -static uint16_t battery_cell_max_v = 3700; -static uint16_t battery_cell_min_v = 3700; +static uint16_t battery_cell_max_v = 3300; //Voltage value used on boot before CAN values have been mapped +static uint16_t battery_cell_min_v = 3300; //Changed from 3700 static uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV static uint8_t battery_max_vno = 0; static uint8_t battery_min_vno = 0; @@ -160,9 +160,9 @@ static uint16_t battery2_ideal_energy_remaining = 0; static uint16_t battery2_ideal_energy_remaining_m0 = 0; // kWh static uint16_t battery2_nominal_energy_remaining = 0; static uint16_t battery2_nominal_energy_remaining_m0 = 0; // kWh -static uint16_t battery2_nominal_full_pack_energy = 600; -static uint16_t battery2_nominal_full_pack_energy_m0 = 600; // Kwh -static uint16_t battery2_beginning_of_life = 600; +static uint16_t battery2_nominal_full_pack_energy = 0; +static uint16_t battery2_nominal_full_pack_energy_m0 = 0; // Kwh +static uint16_t battery2_beginning_of_life = 0; static uint16_t battery2_charge_time_remaining = 0; // Minutes static uint16_t battery2_regenerative_limit = 0; static uint16_t battery2_discharge_limit = 0; @@ -179,8 +179,8 @@ static uint16_t battery2_soc_min = 0; static uint16_t battery2_soc_max = 0; static uint16_t battery2_soc_ui = 0; static uint16_t battery2_soc_ave = 0; -static uint16_t battery2_cell_max_v = 3700; -static uint16_t battery2_cell_min_v = 3700; +static uint16_t battery2_cell_max_v = 3300; +static uint16_t battery2_cell_min_v = 3300; static uint16_t battery2_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV static uint8_t battery2_max_vno = 0; static uint8_t battery2_min_vno = 0; @@ -1198,9 +1198,6 @@ the first, for a few cycles, then stop all messages which causes the contactor unsigned long currentMillis = millis(); - delay( - 3000); // adding 3s delay to allow cell voltage min/max to be read before transmit_can to stop false under/over cell voltage events. - #if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { if (currentMillis - lastSend1CF >= 10) { @@ -1230,14 +1227,14 @@ the first, for a few cycles, then stop all messages which causes the contactor #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) //Send 30ms message - if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { + if (currentMillis - previousMillis50 >= INTERVAL_50_MS) { // Check if sending of CAN messages has been delayed too much. - if ((currentMillis - previousMillis30 >= INTERVAL_30_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { - set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis30)); + if ((currentMillis - previousMillis50 >= INTERVAL_50_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis50)); } else { clear_event(EVENT_CAN_OVERRUN); } - previousMillis30 = currentMillis; + previousMillis50 = currentMillis; if ((datalayer.system.status.inverter_allows_contactor_closing == true) && (datalayer.battery.status.bms_status != FAULT)) { From 7b67eab81de6b4f7a0e0ca0f1a6194ef80b6a03d Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sat, 28 Dec 2024 09:11:54 +1300 Subject: [PATCH 130/225] Update TESLA-BATTERY.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 46 +++++++++++++------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 2467e072d..cc2cd2eea 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -25,27 +25,27 @@ CAN_frame TESLA_221_2 = { static uint16_t sendContactorClosingMessagesStill = 300; static uint32_t battery_total_discharge = 0; static uint32_t battery_total_charge = 0; -static uint16_t battery_volts = 0; // V -static int16_t battery_amps = 0; // A -static uint16_t battery_raw_amps = 0; // A -static int16_t battery_max_temp = 0; // C* -static int16_t battery_min_temp = 0; // C* -static uint16_t battery_energy_buffer = 0; // kWh -static uint16_t battery_energy_buffer_m1 = 0; // kWh -static uint16_t battery_energy_to_charge_complete = 0; // kWh -static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh -static uint16_t battery_expected_energy_remaining = 0; // kWh -static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh -static uint8_t battery_full_charge_complete = 0; // kWh -static uint8_t battery_fully_charged = 0; // kWh -static uint16_t battery_ideal_energy_remaining = 0; // kWh -static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh -static uint16_t battery_nominal_energy_remaining = 0; // kWh -static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh -static uint16_t battery_nominal_full_pack_energy = 0; // Kwh -static uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh -static uint16_t battery_beginning_of_life = 0; // kWh -static uint16_t battery_charge_time_remaining = 0; // Minutes +static uint16_t battery_volts = 0; // V +static int16_t battery_amps = 0; // A +static uint16_t battery_raw_amps = 0; // A +static int16_t battery_max_temp = 0; // C* +static int16_t battery_min_temp = 0; // C* +static uint16_t battery_energy_buffer = 0; // kWh +static uint16_t battery_energy_buffer_m1 = 0; // kWh +static uint16_t battery_energy_to_charge_complete = 0; // kWh +static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh +static uint16_t battery_expected_energy_remaining = 0; // kWh +static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh +static uint8_t battery_full_charge_complete = 0; // kWh +static uint8_t battery_fully_charged = 0; // kWh +static uint16_t battery_ideal_energy_remaining = 0; // kWh +static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh +static uint16_t battery_nominal_energy_remaining = 0; // kWh +static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh +static uint16_t battery_nominal_full_pack_energy = 0; // Kwh +static uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh +static uint16_t battery_beginning_of_life = 0; // kWh +static uint16_t battery_charge_time_remaining = 0; // Minutes static uint16_t battery_regenerative_limit = 0; static uint16_t battery_discharge_limit = 0; static uint16_t battery_max_heat_park = 0; @@ -62,8 +62,8 @@ static uint16_t battery_soc_min = 0; static uint16_t battery_soc_max = 0; static uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui static uint16_t battery_soc_ave = 0; -static uint16_t battery_cell_max_v = 3300; //Voltage value used on boot before CAN values have been mapped -static uint16_t battery_cell_min_v = 3300; //Changed from 3700 +static uint16_t battery_cell_max_v = 3300; //Voltage value used on boot before CAN values have been mapped +static uint16_t battery_cell_min_v = 3300; //Changed from 3700 static uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV static uint8_t battery_max_vno = 0; static uint8_t battery_min_vno = 0; From 30a07aba771e9df2aac572ce54bc6eed9669c7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 28 Dec 2024 12:45:17 +0300 Subject: [PATCH 131/225] Pre-commit fix --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index 2cbecee87..ce84181b1 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -1,6 +1,5 @@ /* 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 "src/include.h" #include "HardwareSerial.h" #include "USER_SECRETS.h" #include "USER_SETTINGS.h" @@ -20,6 +19,7 @@ #include "src/devboard/utils/led_handler.h" #include "src/devboard/utils/logging.h" #include "src/devboard/utils/value_mapping.h" +#include "src/include.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "src/lib/bblanchon-ArduinoJson/ArduinoJson.h" From c9c5e696cbf82f89c86cf8f60ea1a5c5180a7520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 28 Dec 2024 14:42:44 +0300 Subject: [PATCH 132/225] Apply diff from successful testing --- Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 91 ++++++++++++++++------ 1 file changed, 66 insertions(+), 25 deletions(-) diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 1296cbe7d..dac1af9c3 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -12,9 +12,19 @@ */ /* Do not change code below unless you are sure what you are doing */ -static unsigned long previousMillis500ms = 0; // will store last time a 100ms CAN Message was send +static unsigned long previousMillis250ms = 0; // will store last time a 250ms CAN Message was send +static unsigned long previousMillis500ms = 0; // will store last time a 500ms CAN Message was send static unsigned long previousMillis2s = 0; // will store last time a 2s CAN Message was send static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send +static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send + +typedef struct { + CAN_frame* frame; + void (*callback)(); +} Frame; + +static unsigned short listLength = 0; +static Frame framesToSend[20]; static uint32_t inverter_time = 0; static uint16_t inverter_voltage = 0; @@ -33,7 +43,7 @@ CAN_frame SMA_598 = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x598, - .data = {0x12, 0x30, 0x8A, 0x5B, 0x00, 0x00, 0x00, 0x00}}; //B0-4 Serial? + .data = {0x12, 0xD6, 0x43, 0xA4, 0x00, 0x00, 0x00, 0x00}}; //B0-4 Serial 301100932 CAN_frame SMA_5D8 = {.FD = false, .ext_ID = false, .DLC = 8, @@ -168,6 +178,17 @@ void receive_can_inverter(CAN_frame rx_frame) { } } +void pushFrame(CAN_frame* frame, void (*callback)() = NULL) { + if (listLength >= 20) { + return; //TODO: scream. + } + framesToSend[listLength] = { + .frame = frame, + .callback = callback, + }; + listLength++; +} + void send_can_inverter() { unsigned long currentMillis = millis(); @@ -176,43 +197,63 @@ void send_can_inverter() { return; } + if (listLength > 0 && currentMillis - previousMillis250ms >= INTERVAL_250_MS) { + previousMillis250ms = currentMillis; + // Send next frame. + Frame frame = framesToSend[0]; + transmit_can(frame.frame, can_config.inverter); + if (frame.callback != NULL) { + frame.callback(); + } + for (int i = 0; i < listLength - 1; i++) { + framesToSend[i] = framesToSend[i + 1]; + } + listLength--; + } + + if (!pairing_completed) { + return; + } + // Send CAN Message every 2s if (currentMillis - previousMillis2s >= INTERVAL_2_S) { previousMillis2s = currentMillis; - transmit_can(&SMA_358, can_config.inverter); + pushFrame(&SMA_358); } // Send CAN Message every 10s if (currentMillis - previousMillis10s >= INTERVAL_10_S) { previousMillis10s = currentMillis; - transmit_can(&SMA_518, can_config.inverter); - transmit_can(&SMA_4D8, can_config.inverter); - transmit_can(&SMA_3D8, can_config.inverter); - if (pairing_completed) { - transmit_can( - &SMA_458, - can_config - .inverter); //TODO; not confirmed if battery sends. Transmission starts only after battery is paired - } + pushFrame(&SMA_518); + pushFrame(&SMA_4D8); + pushFrame(&SMA_3D8); } } -void send_tripower_init() { - transmit_can(&SMA_558, can_config.inverter); //Pairing start - Vendor - transmit_can(&SMA_598, can_config.inverter); //Serial - transmit_can(&SMA_5D8, can_config.inverter); //BYD - transmit_can(&SMA_618_0, can_config.inverter); //BATTERY - transmit_can(&SMA_618_1, can_config.inverter); //-Box Pr - transmit_can(&SMA_618_2, can_config.inverter); //emium H - transmit_can(&SMA_618_3, can_config.inverter); //VS - transmit_can(&SMA_358, can_config.inverter); - transmit_can(&SMA_3D8, can_config.inverter); - transmit_can(&SMA_458, can_config.inverter); - transmit_can(&SMA_4D8, can_config.inverter); - transmit_can(&SMA_518, can_config.inverter); + +void completePairing() { pairing_completed = true; } +void send_tripower_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, completePairing); +} + void setup_inverter(void) { // Performs one time setup at startup over CAN bus strncpy(datalayer.system.info.inverter_protocol, "SMA Tripower CAN", 63); datalayer.system.info.inverter_protocol[63] = '\0'; + datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first + pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); } #endif From 866357157994fa850b92d91e4c02e104df60837e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 28 Dec 2024 14:58:47 +0300 Subject: [PATCH 133/225] Add SMA Tripower to contactor allow writing --- .../communication/contactorcontrol/comm_contactorcontrol.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index c09e6c171..9a93936a8 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -90,9 +90,9 @@ void init_contactors() { // Main functions void handle_contactors() { -#ifdef BYD_SMA +#if defined(BYD_SMA) || defined(SMA_TRIPOWER_CAN) datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); -#endif // BYD_SMA +#endif #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY handle_contactors_battery2(); From d0ffb97816d251719e2f3c3f216fc2bf7fea02e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 28 Dec 2024 16:19:41 +0300 Subject: [PATCH 134/225] Rename to stellantis, add TODO --- .github/workflows/compile-all-batteries.yml | 1 + ...pile-all-combinations-part2-batteries-N-to-Z.yml | 1 + Software/USER_SETTINGS.h | 2 +- Software/src/battery/BATTERIES.h | 2 +- Software/src/battery/ECMP-BATTERY.cpp | 13 ++++++++++++- Software/src/battery/ECMP-BATTERY.h | 4 ++-- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index 80466e52e..09e852cab 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -70,6 +70,7 @@ jobs: - RENAULT_ZOE_GEN1_BATTERY - RENAULT_ZOE_GEN2_BATTERY - SANTA_FE_PHEV_BATTERY + - STELLANTIS_ECMP_BATTERY - TESLA_MODEL_3Y_BATTERY - TESLA_MODEL_SX_BATTERY - VOLVO_SPA_BATTERY diff --git a/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml b/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml index 8c77e2375..abec324ed 100644 --- a/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml +++ b/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml @@ -63,6 +63,7 @@ jobs: - RENAULT_ZOE_GEN1_BATTERY - RENAULT_ZOE_GEN2_BATTERY - SANTA_FE_PHEV_BATTERY + - STELLANTIS_ECMP_BATTERY - TESLA_MODEL_3Y_BATTERY - TESLA_MODEL_SX_BATTERY - VOLVO_SPA_BATTERY diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 9f8d970e2..2496c2ceb 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -23,7 +23,6 @@ //#define MEB_BATTERY //#define MG_5_BATTERY //#define NISSAN_LEAF_BATTERY -//#define ECMP_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RANGE_ROVER_PHEV_BATTERY @@ -32,6 +31,7 @@ //#define RENAULT_ZOE_GEN1_BATTERY //#define RENAULT_ZOE_GEN2_BATTERY //#define SANTA_FE_PHEV_BATTERY +//#define STELLANTIS_ECMP_BATTERY //#define TESLA_MODEL_3Y_BATTERY //#define TESLA_MODEL_SX_BATTERY //#define VOLVO_SPA_BATTERY diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index aec7d71f0..7be73f225 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -27,7 +27,7 @@ #include "CHADEMO-SHUNTS.h" #endif -#ifdef ECMP_BATTERY +#ifdef STELLANTIS_ECMP_BATTERY #include "ECMP-BATTERY.h" #endif diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index f1ef2ea51..afcfd98b1 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -1,10 +1,21 @@ #include "../include.h" -#ifdef ECMP_BATTERY +#ifdef STELLANTIS_ECMP_BATTERY #include // For std::min and std::max #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" #include "ECMP-BATTERY.h" +/* TODO: +This integration is still ongoing. Here is what still needs to be done in order to use this battery type +- Find SOC% +- Find battery voltage +- Find current value +- Find/estimate charge/discharge limits +- Find temperature +- Figure out contactor closing + - Which CAN messages need to be sent towards the battery? +*/ + /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h index ef4232f9a..14955bd69 100644 --- a/Software/src/battery/ECMP-BATTERY.h +++ b/Software/src/battery/ECMP-BATTERY.h @@ -1,5 +1,5 @@ -#ifndef ECMP_BATTERY_H -#define ECMP_BATTERY_H +#ifndef STELLANTIS_ECMP_BATTERY_H +#define STELLANTIS_ECMP_BATTERY_H #include #include "../include.h" From 7cc63902b048a4405e4b38721e402f52f774a8ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 28 Dec 2024 19:43:48 +0300 Subject: [PATCH 135/225] Make Ultra messages part of normal sending --- Software/src/inverter/SOLAX-CAN.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp index 60f684b96..31adfe16b 100644 --- a/Software/src/inverter/SOLAX-CAN.cpp +++ b/Software/src/inverter/SOLAX-CAN.cpp @@ -68,7 +68,7 @@ CAN_frame SOLAX_187E = {.FD = false, //Needed for Ultra .ext_ID = true, .DLC = 8, .ID = 0x187E, - .data = {0x0, 0x2D, 0x0, 0x0, 0x0, 0x5F, 0x0, 0x0}}; + .data = {0x60, 0xEA, 0x0, 0x0, 0x64, 0x0, 0x0, 0x0}}; CAN_frame SOLAX_187D = {.FD = false, //Needed for Ultra .ext_ID = true, .DLC = 8, @@ -88,7 +88,7 @@ CAN_frame SOLAX_187A = {.FD = false, //Needed for Ultra .ext_ID = true, .DLC = 8, .ID = 0x187A, - .data = {0x01, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + .data = {0x01, (uint8_t)BATTERY_TYPE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; CAN_frame SOLAX_1881 = {.FD = false, .ext_ID = true, .DLC = 8, @@ -190,6 +190,13 @@ void update_values_can_inverter() { //This function maps all the values fetched SOLAX_1801.data.u8[0] = 2; SOLAX_1801.data.u8[2] = 1; SOLAX_1801.data.u8[4] = 1; + + //Ultra messages + SOLAX_187E.data.u8[0] = (uint8_t)capped_remaining_capacity_Wh; + SOLAX_187E.data.u8[1] = (capped_remaining_capacity_Wh >> 8); + SOLAX_187E.data.u8[2] = 0; + SOLAX_187E.data.u8[3] = 0; + SOLAX_187E.data.u8[5] = (uint8_t)(datalayer.battery.status.reported_soc / 100); } void send_can_inverter() { @@ -212,7 +219,9 @@ void receive_can_inverter(CAN_frame rx_frame) { #endif datalayer.system.status.inverter_allows_contactor_closing = false; SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on. - for (int i = 0; i <= number_of_batteries; i++) { + for (uint8_t i = 0; i <= number_of_batteries; i++) { + transmit_can(&SOLAX_187E, can_config.inverter); + transmit_can(&SOLAX_187A, can_config.inverter); transmit_can(&SOLAX_1872, can_config.inverter); transmit_can(&SOLAX_1873, can_config.inverter); transmit_can(&SOLAX_1874, can_config.inverter); @@ -230,6 +239,8 @@ void receive_can_inverter(CAN_frame rx_frame) { case (WAITING_FOR_CONTACTOR): SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on. + transmit_can(&SOLAX_187E, can_config.inverter); + transmit_can(&SOLAX_187A, can_config.inverter); transmit_can(&SOLAX_1872, can_config.inverter); transmit_can(&SOLAX_1873, can_config.inverter); transmit_can(&SOLAX_1874, can_config.inverter); @@ -247,6 +258,8 @@ void receive_can_inverter(CAN_frame rx_frame) { case (CONTACTOR_CLOSED): datalayer.system.status.inverter_allows_contactor_closing = true; SOLAX_1875.data.u8[4] = (0x01); // Inform Inverter: Contactor 0=off, 1=on. + transmit_can(&SOLAX_187E, can_config.inverter); + transmit_can(&SOLAX_187A, can_config.inverter); transmit_can(&SOLAX_1872, can_config.inverter); transmit_can(&SOLAX_1873, can_config.inverter); transmit_can(&SOLAX_1874, can_config.inverter); @@ -281,12 +294,5 @@ void setup_inverter(void) { // Performs one time setup at startup strncpy(datalayer.system.info.inverter_protocol, "SolaX Triple Power LFP over CAN bus", 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first - - // Sending these messages once towards the inverter makes SOC% work on the Ultra variant - transmit_can(&SOLAX_187E, can_config.inverter); - transmit_can(&SOLAX_187D, can_config.inverter); - transmit_can(&SOLAX_187C, can_config.inverter); - transmit_can(&SOLAX_187B, can_config.inverter); - transmit_can(&SOLAX_187A, can_config.inverter); } #endif From fe451cc18a767508b96423d2688fa0ca4eed5612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 28 Dec 2024 19:52:41 +0300 Subject: [PATCH 136/225] Revert to hardcoded ID --- Software/src/inverter/SOLAX-CAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp index 31adfe16b..e3c5dad28 100644 --- a/Software/src/inverter/SOLAX-CAN.cpp +++ b/Software/src/inverter/SOLAX-CAN.cpp @@ -88,7 +88,7 @@ CAN_frame SOLAX_187A = {.FD = false, //Needed for Ultra .ext_ID = true, .DLC = 8, .ID = 0x187A, - .data = {0x01, (uint8_t)BATTERY_TYPE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + .data = {0x01, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; CAN_frame SOLAX_1881 = {.FD = false, .ext_ID = true, .DLC = 8, From a0907b7ef66e73642d814b880e706a46212b1cdb Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sun, 29 Dec 2024 23:02:17 +1300 Subject: [PATCH 137/225] Update TESLA-BATTERY.cpp Update starting cell voltage to 3300mV, update starting pack energy to 0kWh, add cellvoltageRead to 0x332, add check of cellvoltageRead in send_can. --- Software/src/battery/TESLA-BATTERY.cpp | 29 ++++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 5bcff8aff..80aae62d4 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -24,9 +24,10 @@ CAN_frame TESLA_221_2 = { .data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive static uint16_t sendContactorClosingMessagesStill = 300; -static uint16_t battery_cell_max_v = 3700; -static uint16_t battery_cell_min_v = 3700; +static uint16_t battery_cell_max_v = 3300; +static uint16_t battery_cell_min_v = 3300; static uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV +static bool cellvoltagesRead = false; //0x3d2: 978 BMS_kwhCounter static uint32_t battery_total_discharge = 0; static uint32_t battery_total_charge = 0; @@ -68,8 +69,8 @@ static uint16_t battery_ideal_energy_remaining = 0; // kWh static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh static uint16_t battery_nominal_energy_remaining = 0; // kWh static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh -static uint16_t battery_nominal_full_pack_energy = 600; // Kwh -static uint16_t battery_nominal_full_pack_energy_m0 = 600; // Kwh +static uint16_t battery_nominal_full_pack_energy = 0; // Kwh +static uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh //0x132 306 HVBattAmpVolt static uint16_t battery_volts = 0; // V static int16_t battery_amps = 0; // A @@ -94,7 +95,7 @@ static uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_volt static uint16_t battery_dcdcLvOutputCurrent = 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent //0x292: 658 BMS_socStatus -static uint16_t battery_beginning_of_life = 600; // kWh +static uint16_t battery_beginning_of_life = 0; // kWh static uint16_t battery_soc_min = 0; static uint16_t battery_soc_max = 0; static uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui @@ -445,9 +446,10 @@ static bool battery_BMS_a180_SW_ECU_reset_blocked = false; #ifdef DOUBLE_BATTERY //need to update for battery2 -static uint16_t battery2_cell_max_v = 3700; -static uint16_t battery2_cell_min_v = 3700; +static uint16_t battery2_cell_max_v = 3300; +static uint16_t battery2_cell_min_v = 3300; static uint16_t battery2_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV +static bool battery2_cellvoltagesRead = false; //0x3d2: 978 BMS_kwhCounter static uint32_t battery2_total_discharge = 0; static uint32_t battery2_total_charge = 0; @@ -466,9 +468,8 @@ static uint16_t battery2_nominal_energy_remaining = 0; static uint16_t battery2_nominal_energy_remaining_m0 = 0; // kWh static uint16_t battery2_nominal_full_pack_energy = 0; static uint16_t battery2_nominal_full_pack_energy_m0 = 0; // Kwh -static uint16_t battery2_beginning_of_life = 0; -static uint16_t battery2_nominal_full_pack_energy = 600; -static uint16_t battery2_nominal_full_pack_energy_m0 = 600; // Kwh +static uint16_t battery2_nominal_full_pack_energy = 0; +static uint16_t battery2_nominal_full_pack_energy_m0 = 0; // Kwh //0x132 306 HVBattAmpVolt static uint16_t battery2_volts = 0; // V static int16_t battery2_amps = 0; // A @@ -492,7 +493,7 @@ static uint16_t battery2_dcdcHvBusVolt = 0; //update name static uint16_t battery2_dcdcLvBusVolt = 0; //update name static uint16_t battery2_dcdcLvOutputCurrent = 0; //update name //0x292: 658 BMS_socStatus -static uint16_t battery2_beginning_of_life = 600; +static uint16_t battery2_beginning_of_life = 0; static uint16_t battery2_soc_min = 0; static uint16_t battery2_soc_max = 0; static uint16_t battery2_soc_ui = 0; @@ -1398,6 +1399,7 @@ void receive_can_battery(CAN_frame rx_frame) { temp = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); temp = (temp & 0xFFF); battery_cell_min_v = temp * 2; + cellvoltagesRead = true; //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[1] & (0x3FU)) << 6) | ((_d[0] >> 2) & (0x3FU)); battery_BrickVoltageMax = ((rx_frame.data.u8[1] & (0x3F)) << 6) | ((rx_frame.data.u8[0] >> 2) & (0x3F)); //to datalayer_extended @@ -2043,6 +2045,7 @@ void receive_can_battery2(CAN_frame rx_frame) { temp = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); temp = (temp & 0xFFF); battery2_cell_min_v = temp * 2; + battery2_cellvoltagesRead = true; //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[1] & (0x3FU)) << 6) | ((_d[0] >> 2) & (0x3FU)); battery2_BrickVoltageMax = ((rx_frame.data.u8[1] & (0x3F)) << 6) | ((rx_frame.data.u8[0] >> 2) & (0x3F)); //to datalayer_extended @@ -2681,6 +2684,10 @@ the first, for a few cycles, then stop all messages which causes the contactor unsigned long currentMillis = millis(); +if (!cellvoltagesRead ) { + return; //All cellvoltages not read yet, do not proceed with contactor closing +} + #if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { if (currentMillis - lastSend1CF >= 10) { From 1bbbaacb7011b5c69631e094ac04289822b6a7eb Mon Sep 17 00:00:00 2001 From: josiahhiggs <79869367+josiahhiggs@users.noreply.github.com> Date: Sun, 29 Dec 2024 23:02:32 +1300 Subject: [PATCH 138/225] Update TESLA-BATTERY.cpp --- Software/src/battery/TESLA-BATTERY.cpp | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index 80aae62d4..4e17068e1 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -57,20 +57,20 @@ static uint16_t battery_discharge_limit = 0; static uint16_t battery_max_heat_park = 0; static uint16_t battery_hvac_max_power = 0; //0x352: 850 BMS_energyStatus -static uint16_t battery_energy_buffer = 0; // kWh -static uint16_t battery_energy_buffer_m1 = 0; // kWh -static uint16_t battery_energy_to_charge_complete = 0; // kWh -static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh -static uint16_t battery_expected_energy_remaining = 0; // kWh -static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh -static bool battery_full_charge_complete = false; // Changed to bool -static bool battery_fully_charged = false; // Changed to bool -static uint16_t battery_ideal_energy_remaining = 0; // kWh -static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh -static uint16_t battery_nominal_energy_remaining = 0; // kWh -static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh -static uint16_t battery_nominal_full_pack_energy = 0; // Kwh -static uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh +static uint16_t battery_energy_buffer = 0; // kWh +static uint16_t battery_energy_buffer_m1 = 0; // kWh +static uint16_t battery_energy_to_charge_complete = 0; // kWh +static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh +static uint16_t battery_expected_energy_remaining = 0; // kWh +static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh +static bool battery_full_charge_complete = false; // Changed to bool +static bool battery_fully_charged = false; // Changed to bool +static uint16_t battery_ideal_energy_remaining = 0; // kWh +static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh +static uint16_t battery_nominal_energy_remaining = 0; // kWh +static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh +static uint16_t battery_nominal_full_pack_energy = 0; // Kwh +static uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh //0x132 306 HVBattAmpVolt static uint16_t battery_volts = 0; // V static int16_t battery_amps = 0; // A @@ -2684,9 +2684,9 @@ the first, for a few cycles, then stop all messages which causes the contactor unsigned long currentMillis = millis(); -if (!cellvoltagesRead ) { - return; //All cellvoltages not read yet, do not proceed with contactor closing -} + if (!cellvoltagesRead) { + return; //All cellvoltages not read yet, do not proceed with contactor closing + } #if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { From 40399b446e162cce7f448d9413ba31822db9d3d6 Mon Sep 17 00:00:00 2001 From: No-Signal Date: Sun, 29 Dec 2024 13:42:14 +0000 Subject: [PATCH 139/225] Adding ability to log CAN frames to SD card --- Software/Software.ino | 22 +++ Software/USER_SETTINGS.h | 1 + Software/src/communication/can/comm_can.cpp | 9 ++ Software/src/communication/can/comm_can.h | 2 - Software/src/devboard/sdcard/sdcard.cpp | 151 ++++++++++++++++++ Software/src/devboard/sdcard/sdcard.h | 23 +++ Software/src/devboard/utils/types.h | 7 + .../devboard/webserver/can_logging_html.cpp | 6 + Software/src/devboard/webserver/webserver.cpp | 18 +++ 9 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 Software/src/devboard/sdcard/sdcard.cpp create mode 100644 Software/src/devboard/sdcard/sdcard.h diff --git a/Software/Software.ino b/Software/Software.ino index 60cc30d21..306bd994d 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -18,6 +18,7 @@ #include "src/communication/rs485/comm_rs485.h" #include "src/communication/seriallink/comm_seriallink.h" #include "src/datalayer/datalayer.h" +#include "src/devboard/sdcard/sdcard.h" #include "src/devboard/utils/events.h" #include "src/devboard/utils/led_handler.h" #include "src/devboard/utils/logging.h" @@ -78,12 +79,16 @@ MyTimer core_task_timer_10s(INTERVAL_10_S); int64_t connectivity_task_time_us; MyTimer connectivity_task_timer_10s(INTERVAL_10_S); +int64_t logging_task_time_us; +MyTimer logging_task_timer_10s(INTERVAL_10_S); + MyTimer loop_task_timer_10s(INTERVAL_10_S); MyTimer check_pause_2s(INTERVAL_2_S); TaskHandle_t main_loop_task; TaskHandle_t connectivity_loop_task; +TaskHandle_t logging_loop_task; Logging logging; @@ -98,6 +103,11 @@ void setup() { TASK_CONNECTIVITY_PRIO, &connectivity_loop_task, WIFI_CORE); #endif +#ifdef LOG_CAN_TO_SD + xTaskCreatePinnedToCore((TaskFunction_t)&logging_loop, "logging_loop", 4096, &logging_task_time_us, + TASK_CONNECTIVITY_PRIO, &logging_loop_task, WIFI_CORE); +#endif + init_events(); init_CAN(); @@ -137,6 +147,18 @@ void loop() { #endif } +#ifdef LOG_CAN_TO_SD +void logging_loop(void* task_time_us) { + + init_logging_buffer(); + init_sdcard(); + + while (true) { + write_can_frame_to_sdcard(); + } +} +#endif + #ifdef WIFI void connectivity_loop(void* task_time_us) { diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index a73799c50..bacd3d9ad 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -73,6 +73,7 @@ #endif //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) +//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card //#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting //#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/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index 8fa2ab3d9..4a04959da 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -1,5 +1,6 @@ #include "comm_can.h" #include "../../include.h" +#include "src/devboard/sdcard/sdcard.h" // Parameters @@ -107,6 +108,10 @@ void transmit_can(CAN_frame* tx_frame, int interface) { } print_can_frame(*tx_frame, frameDirection(MSG_TX)); +#ifdef LOG_CAN_TO_SD + add_can_frame_to_buffer(*tx_frame, frameDirection(MSG_TX)); +#endif + switch (interface) { case CAN_NATIVE: CAN_frame_t frame; @@ -186,6 +191,10 @@ void send_can() { void receive_can(CAN_frame* rx_frame, int interface) { print_can_frame(*rx_frame, frameDirection(MSG_RX)); +#ifdef LOG_CAN_TO_SD + add_can_frame_to_buffer(*rx_frame, frameDirection(MSG_RX)); +#endif + if (interface == can_config.battery) { receive_can_battery(*rx_frame); #ifdef CHADEMO_BATTERY diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h index 48e3c9c38..38ca2da85 100644 --- a/Software/src/communication/can/comm_can.h +++ b/Software/src/communication/can/comm_can.h @@ -15,8 +15,6 @@ #include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" #endif //CANFD_ADDON -enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 - /** * @brief Initialization function for CAN. * diff --git a/Software/src/devboard/sdcard/sdcard.cpp b/Software/src/devboard/sdcard/sdcard.cpp new file mode 100644 index 000000000..9cb2ff61b --- /dev/null +++ b/Software/src/devboard/sdcard/sdcard.cpp @@ -0,0 +1,151 @@ +#include "sdcard.h" +#include "freertos/ringbuf.h" + +File can_log_file; +RingbufHandle_t can_bufferHandle; + +bool can_logging_paused = false; +bool can_file_open = false; +bool delete_can_file = false; +bool sd_card_active = false; + +void delete_can_log() { + can_logging_paused = true; + delete_can_file = true; +} + +void resume_can_writing() { + can_logging_paused = false; + can_log_file = SD.open(CAN_LOG_FILE, FILE_APPEND); + can_file_open = true; +} + +void pause_can_writing() { + can_logging_paused = true; +} + +void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir) { + + if (!sd_card_active) + return; + + CAN_log_frame log_frame = {frame, msgDir}; + if (xRingbufferSend(can_bufferHandle, &log_frame, sizeof(log_frame), 0) != pdTRUE) { + Serial.println("Failed to send CAN frame to ring buffer!"); + return; + } +} + +void write_can_frame_to_sdcard() { + + if (!sd_card_active) + return; + + size_t receivedMessageSize; + CAN_log_frame* log_frame = + (CAN_log_frame*)xRingbufferReceive(can_bufferHandle, &receivedMessageSize, pdMS_TO_TICKS(10)); + + if (log_frame != NULL) { + + if (can_logging_paused) { + if (can_file_open) { + can_log_file.close(); + can_file_open = false; + } + if (delete_can_file) { + SD.remove(CAN_LOG_FILE); + delete_can_file = false; + can_logging_paused = false; + } + vRingbufferReturnItem(can_bufferHandle, (void*)log_frame); + return; + } + + if (can_file_open == false) { + can_log_file = SD.open(CAN_LOG_FILE, FILE_APPEND); + can_file_open = true; + } + + uint8_t i = 0; + can_log_file.print("("); + can_log_file.print(millis() / 1000.0); + (log_frame->direction == MSG_RX) ? can_log_file.print(") RX0 ") : can_log_file.print(") TX1 "); + can_log_file.print(log_frame->frame.ID, HEX); + can_log_file.print(" ["); + can_log_file.print(log_frame->frame.DLC); + can_log_file.print("] "); + for (i = 0; i < log_frame->frame.DLC; i++) { + can_log_file.print(log_frame->frame.data.u8[i] < 16 ? "0" : ""); + can_log_file.print(log_frame->frame.data.u8[i], HEX); + if (i < log_frame->frame.DLC - 1) + can_log_file.print(" "); + } + can_log_file.println(""); + + vRingbufferReturnItem(can_bufferHandle, (void*)log_frame); + } +} + +void init_logging_buffer() { + can_bufferHandle = xRingbufferCreate(64 * 1024, RINGBUF_TYPE_BYTEBUF); + if (can_bufferHandle == NULL) { + Serial.println("Failed to create CAN ring buffer!"); + return; + } +} + +void init_sdcard() { + + pinMode(SD_CS_PIN, OUTPUT); + digitalWrite(SD_CS_PIN, HIGH); + pinMode(SD_SCLK_PIN, OUTPUT); + pinMode(SD_MOSI_PIN, OUTPUT); + pinMode(SD_MISO_PIN, INPUT); + + SPI.begin(SD_SCLK_PIN, SD_MISO_PIN, SD_MOSI_PIN, SD_CS_PIN); + if (!SD.begin(SD_CS_PIN)) { + Serial.println("SD Card initialization failed!"); + return; + } + + Serial.println("SD Card initialization successful."); + sd_card_active = true; + + print_sdcard_details(); +} + +void print_sdcard_details() { + + Serial.print("SD Card Type: "); + switch (SD.cardType()) { + case CARD_MMC: + Serial.println("MMC"); + break; + case CARD_SD: + Serial.println("SD"); + break; + case CARD_SDHC: + Serial.println("SDHC"); + break; + case CARD_UNKNOWN: + Serial.println("UNKNOWN"); + break; + case CARD_NONE: + Serial.println("No SD Card found"); + break; + } + + if (SD.cardType() != CARD_NONE) { + Serial.print("SD Card Size: "); + Serial.print(SD.cardSize() / 1024 / 1024); + Serial.println(" MB"); + + Serial.print("Total space: "); + Serial.print(SD.totalBytes() / 1024 / 1024); + Serial.println(" MB"); + + Serial.print("Used space: "); + Serial.print(SD.usedBytes() / 1024 / 1024); + Serial.println(" MB"); + } +} diff --git a/Software/src/devboard/sdcard/sdcard.h b/Software/src/devboard/sdcard/sdcard.h new file mode 100644 index 000000000..0f7923589 --- /dev/null +++ b/Software/src/devboard/sdcard/sdcard.h @@ -0,0 +1,23 @@ +#ifndef SDCARD_H +#define SDCARD_H + +#include +#include +#include "../../communication/can/comm_can.h" +#include "../hal/hal.h" + +#define CAN_LOG_FILE "/canlog.txt" + +void init_logging_buffer(); + +void init_sdcard(); +void print_sdcard_details(); + +void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir); +void write_can_frame_to_sdcard(); + +void pause_can_writing(); +void resume_can_writing(); +void delete_can_log(); + +#endif diff --git a/Software/src/devboard/utils/types.h b/Software/src/devboard/utils/types.h index 126aff261..d5cbf2c75 100644 --- a/Software/src/devboard/utils/types.h +++ b/Software/src/devboard/utils/types.h @@ -51,6 +51,13 @@ typedef struct { } data; } CAN_frame; +enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 + +typedef struct { + CAN_frame frame; + frameDirection direction; +} CAN_log_frame; + std::string getBMSStatus(bms_status_enum status); #endif diff --git a/Software/src/devboard/webserver/can_logging_html.cpp b/Software/src/devboard/webserver/can_logging_html.cpp index 77f1975e7..e64de2326 100644 --- a/Software/src/devboard/webserver/can_logging_html.cpp +++ b/Software/src/devboard/webserver/can_logging_html.cpp @@ -24,6 +24,9 @@ String can_logger_processor(const String& var) { content += ""; content += " "; content += " "; +#ifdef LOG_CAN_TO_SD + content += " "; +#endif content += ""; // Start a new block for the CAN messages @@ -52,6 +55,9 @@ String can_logger_processor(const String& var) { content += ""; - return content; - } - return String(); + content += "function stopLoggingAndGoToMainPage() {"; + content += " fetch('/stop_can_logging').then(() => window.location.href = '/');"; + content += "}"; + content += ""; + content += index_html_footer; + return content; } diff --git a/Software/src/devboard/webserver/can_logging_html.h b/Software/src/devboard/webserver/can_logging_html.h index f208c3fff..8d68e6840 100644 --- a/Software/src/devboard/webserver/can_logging_html.h +++ b/Software/src/devboard/webserver/can_logging_html.h @@ -11,6 +11,6 @@ * * @return String */ -String can_logger_processor(const String& var); +String can_logger_processor(void); #endif diff --git a/Software/src/devboard/webserver/debug_logging_html.cpp b/Software/src/devboard/webserver/debug_logging_html.cpp index 7dd9ede44..ce2740689 100644 --- a/Software/src/devboard/webserver/debug_logging_html.cpp +++ b/Software/src/devboard/webserver/debug_logging_html.cpp @@ -1,10 +1,11 @@ #include "debug_logging_html.h" #include #include "../../datalayer/datalayer.h" +#include "index_html.h" #ifdef DEBUG_VIA_WEB -String debug_logger_processor(const String& var) { - String content = ""; +String debug_logger_processor(void) { + String content = String(index_html_header); // Page format content += "%X% -)rawliteral"; +#include "index_html.h" + +#define INDEX_HTML_HEADER \ + R"rawliteral(Battery Emulator)rawliteral" +#define INDEX_HTML_FOOTER R"rawliteral()rawliteral"; + +const char index_html[] = INDEX_HTML_HEADER "%X%" INDEX_HTML_FOOTER; +const char index_html_header[] = INDEX_HTML_HEADER; +const char index_html_footer[] = INDEX_HTML_FOOTER; /* The above code is minified (https://kangax.github.io/html-minifier/) to increase performance. Here is the full HTML function: diff --git a/Software/src/devboard/webserver/index_html.h b/Software/src/devboard/webserver/index_html.h new file mode 100644 index 000000000..8a095650a --- /dev/null +++ b/Software/src/devboard/webserver/index_html.h @@ -0,0 +1,8 @@ +#ifndef INDEX_HTML_H +#define INDEX_HTML_H + +extern const char index_html[]; +extern const char index_html_header[]; +extern const char index_html_footer[]; + +#endif // INDEX_HTML_H diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 61c28f303..696873c78 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -21,7 +21,7 @@ unsigned long ota_progress_millis = 0; #include "cellmonitor_html.h" #include "debug_logging_html.h" #include "events_html.h" -#include "index_html.cpp" +#include "index_html.h" #include "settings_html.h" MyTimer ota_timeout_timer = MyTimer(15000); @@ -31,8 +31,6 @@ const char get_firmware_info_html[] = R"rawliteral(%X%)rawliteral"; void init_webserver() { - String content = index_html; - server.on("/logout", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(401); }); // Route for firmware info from ota update page @@ -63,13 +61,15 @@ void init_webserver() { // Route for going to CAN logging web page server.on("/canlog", HTTP_GET, [](AsyncWebServerRequest* request) { - request->send_P(200, "text/html", index_html, can_logger_processor); + AsyncWebServerResponse* response = request->beginResponse(200, "text/html", can_logger_processor()); + request->send(response); }); #ifdef DEBUG_VIA_WEB // Route for going to debug logging web page server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) { - request->send_P(200, "text/html", index_html, debug_logger_processor); + AsyncWebServerResponse* response = request->beginResponse(200, "text/html", debug_logger_processor()); + request->send(response); }); #endif // DEBUG_VIA_WEB From 884ed718d3740923f735e0b52afe430291c4bc22 Mon Sep 17 00:00:00 2001 From: LevinSwe Date: Thu, 2 Jan 2025 15:05:33 +0100 Subject: [PATCH 174/225] Update KIA-HYUNDAI-64-BATTERY.cpp - Expand the time of parameterID polling to increase the ID-counter every other time instead of every 100ms cycle. - Sometimes the cell voltages are corrupted if polled to fast. --- Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index d14e78cd0..5824ec07f 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -25,6 +25,7 @@ static int16_t batteryAmps = 0; static int16_t temperatureMax = 0; static int16_t temperatureMin = 0; static int16_t poll_data_pid = 0; +static bool holdPidCounter = false; static uint8_t CellVmaxNo = 0; static uint8_t CellVminNo = 0; static uint8_t batteryManagementMode = 0; @@ -262,11 +263,16 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { case 0x5D8: startedUp = true; - //PID data is polled after last message sent from battery: - if (poll_data_pid >= 10) { //polling one of ten PIDs at 100ms, resolution = 1s + //PID data is polled after last message sent from battery every other time: + if (poll_data_pid >= 10) { //polling one of ten PIDs at 100ms*2, resolution = 2s poll_data_pid = 0; } - poll_data_pid++; + if (holdPidCounter == false) { + poll_data_pid++; + holdPidCounter = true; + } else { + holdPidCounter = false; + } if (poll_data_pid == 1) { transmit_can_frame(&KIA64_7E4_id1, can_config.battery); } else if (poll_data_pid == 2) { From 91e0e55fd51be834db4761c2b20ab451e6088624 Mon Sep 17 00:00:00 2001 From: LevinSwe Date: Thu, 2 Jan 2025 15:29:40 +0100 Subject: [PATCH 175/225] Update KIA-HYUNDAI-64-BATTERY.cpp --- .../src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 5824ec07f..b95e08c53 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -267,28 +267,28 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { if (poll_data_pid >= 10) { //polling one of ten PIDs at 100ms*2, resolution = 2s poll_data_pid = 0; } - if (holdPidCounter == false) { - poll_data_pid++; - holdPidCounter = true; - } else { + if (holdPidCounter == true) { holdPidCounter = false; - } - if (poll_data_pid == 1) { - transmit_can_frame(&KIA64_7E4_id1, can_config.battery); - } else if (poll_data_pid == 2) { - transmit_can_frame(&KIA64_7E4_id2, can_config.battery); - } else if (poll_data_pid == 3) { - transmit_can_frame(&KIA64_7E4_id3, can_config.battery); - } else if (poll_data_pid == 4) { - transmit_can_frame(&KIA64_7E4_id4, can_config.battery); - } else if (poll_data_pid == 5) { - transmit_can_frame(&KIA64_7E4_id5, can_config.battery); - } else if (poll_data_pid == 6) { - transmit_can_frame(&KIA64_7E4_id6, can_config.battery); - } else if (poll_data_pid == 7) { - } else if (poll_data_pid == 8) { - } else if (poll_data_pid == 9) { - } else if (poll_data_pid == 10) { + } else { + holdPidCounter = true; + poll_data_pid++; + if (poll_data_pid == 1) { + transmit_can_frame(&KIA64_7E4_id1, can_config.battery); + } else if (poll_data_pid == 2) { + transmit_can_frame(&KIA64_7E4_id2, can_config.battery); + } else if (poll_data_pid == 3) { + transmit_can_frame(&KIA64_7E4_id3, can_config.battery); + } else if (poll_data_pid == 4) { + transmit_can_frame(&KIA64_7E4_id4, can_config.battery); + } else if (poll_data_pid == 5) { + transmit_can_frame(&KIA64_7E4_id5, can_config.battery); + } else if (poll_data_pid == 6) { + transmit_can_frame(&KIA64_7E4_id6, can_config.battery); + } else if (poll_data_pid == 7) { + } else if (poll_data_pid == 8) { + } else if (poll_data_pid == 9) { + } else if (poll_data_pid == 10) { + } } break; case 0x7EC: //Data From polled PID group, BigEndian From 5babcc03bda0e03d61a20481dd63cb30ffdb3cf2 Mon Sep 17 00:00:00 2001 From: LevinSwe Date: Thu, 2 Jan 2025 19:14:08 +0100 Subject: [PATCH 176/225] Update KIA-HYUNDAI-64-BATTERY.cpp - Removed Non-used parameter polling IDs 7 -- 10 - Moved the PID counter Max value code inside the if (hold counter) code. --- Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index b95e08c53..6b4651b4c 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -264,13 +264,13 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { startedUp = true; //PID data is polled after last message sent from battery every other time: - if (poll_data_pid >= 10) { //polling one of ten PIDs at 100ms*2, resolution = 2s - poll_data_pid = 0; - } if (holdPidCounter == true) { holdPidCounter = false; } else { holdPidCounter = true; + if (poll_data_pid >= 6) { //polling one of six PIDs at 100ms*2, resolution = 1200ms + poll_data_pid = 0; + } poll_data_pid++; if (poll_data_pid == 1) { transmit_can_frame(&KIA64_7E4_id1, can_config.battery); @@ -284,10 +284,6 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { transmit_can_frame(&KIA64_7E4_id5, can_config.battery); } else if (poll_data_pid == 6) { transmit_can_frame(&KIA64_7E4_id6, can_config.battery); - } else if (poll_data_pid == 7) { - } else if (poll_data_pid == 8) { - } else if (poll_data_pid == 9) { - } else if (poll_data_pid == 10) { } } break; From f138f97905e0f7bf3d824de2e1c5b96f1cf8f7ae Mon Sep 17 00:00:00 2001 From: Matt Holmes Date: Thu, 2 Jan 2025 19:46:10 +0000 Subject: [PATCH 177/225] Adding feature to log to SD Card (#708) * Adding feature to log to SD Card Co-authored-by: mvgalen --- Software/Software.ino | 11 +- Software/USER_SETTINGS.h | 3 +- Software/src/devboard/sdcard/sdcard.cpp | 79 ++++++++- Software/src/devboard/sdcard/sdcard.h | 11 +- Software/src/devboard/utils/logging.cpp | 157 ++++++++++++------ Software/src/devboard/utils/logging.h | 2 + .../devboard/webserver/debug_logging_html.cpp | 12 +- Software/src/devboard/webserver/webserver.cpp | 21 ++- Software/src/devboard/wifi/wifi.cpp | 2 +- Software/src/include.h | 2 +- 10 files changed, 233 insertions(+), 67 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index c8a8316eb..7c75b07d5 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -104,7 +104,7 @@ void setup() { TASK_CONNECTIVITY_PRIO, &connectivity_loop_task, WIFI_CORE); #endif -#ifdef LOG_CAN_TO_SD +#if defined(LOG_CAN_TO_SD) || defined(LOG_TO_SD) xTaskCreatePinnedToCore((TaskFunction_t)&logging_loop, "logging_loop", 4096, &logging_task_time_us, TASK_CONNECTIVITY_PRIO, &logging_loop_task, WIFI_CORE); #endif @@ -151,14 +151,19 @@ void loop() { #endif } -#ifdef LOG_CAN_TO_SD +#if defined(LOG_CAN_TO_SD) || defined(LOG_TO_SD) void logging_loop(void* task_time_us) { - init_logging_buffer(); + init_logging_buffers(); init_sdcard(); while (true) { +#ifdef LOG_TO_SD + write_log_to_sdcard(); +#endif +#ifdef LOG_CAN_TO_SD write_can_frame_to_sdcard(); +#endif } } #endif diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 0d60bdd00..301c7caee 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -71,9 +71,10 @@ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement /* Other options */ +//#define LOG_TO_SD //Enable this line to log diagnostic data to SD card //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) //#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) -#if defined(DEBUG_VIA_USB) || defined(DEBUG_VIA_WEB) +#if defined(DEBUG_VIA_USB) || defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD) #define DEBUG_LOG #endif diff --git a/Software/src/devboard/sdcard/sdcard.cpp b/Software/src/devboard/sdcard/sdcard.cpp index b6b755abb..76c8989b5 100644 --- a/Software/src/devboard/sdcard/sdcard.cpp +++ b/Software/src/devboard/sdcard/sdcard.cpp @@ -5,11 +5,18 @@ defined(SD_MISO_PIN) // ensure code is only compiled if all SD card pins are defined File can_log_file; +File log_file; RingbufHandle_t can_bufferHandle; +RingbufHandle_t log_bufferHandle; bool can_logging_paused = false; bool can_file_open = false; bool delete_can_file = false; + +bool logging_paused = false; +bool log_file_open = false; +bool delete_log_file = false; + bool sd_card_active = false; void delete_can_log() { @@ -27,6 +34,26 @@ void pause_can_writing() { can_logging_paused = true; } +void delete_log() { + logging_paused = true; + if (log_file_open) { + log_file.close(); + log_file_open = false; + } + SD.remove(LOG_FILE); + logging_paused = false; +} + +void resume_log_writing() { + logging_paused = false; + log_file = SD.open(LOG_FILE, FILE_APPEND); + log_file_open = true; +} + +void pause_log_writing() { + logging_paused = true; +} + void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir) { if (!sd_card_active) @@ -84,17 +111,65 @@ void write_can_frame_to_sdcard() { can_log_file.print(" "); } can_log_file.println(""); + can_log_file.flush(); vRingbufferReturnItem(can_bufferHandle, (void*)log_frame); } } -void init_logging_buffer() { - can_bufferHandle = xRingbufferCreate(64 * 1024, RINGBUF_TYPE_BYTEBUF); +void add_log_to_buffer(const uint8_t* buffer, size_t size) { + + if (!sd_card_active) + return; + + if (xRingbufferSend(log_bufferHandle, buffer, size, 0) != pdTRUE) { + Serial.println("Failed to send log to ring buffer!"); + return; + } +} + +void write_log_to_sdcard() { + + if (!sd_card_active) + return; + + size_t receivedMessageSize; + uint8_t* buffer = (uint8_t*)xRingbufferReceive(log_bufferHandle, &receivedMessageSize, pdMS_TO_TICKS(10)); + + if (buffer != NULL) { + + if (logging_paused) { + vRingbufferReturnItem(log_bufferHandle, (void*)buffer); + return; + } + + if (log_file_open == false) { + log_file = SD.open(LOG_FILE, FILE_APPEND); + log_file_open = true; + } + + log_file.write(buffer, receivedMessageSize); + log_file.flush(); + vRingbufferReturnItem(log_bufferHandle, (void*)buffer); + } +} + +void init_logging_buffers() { +#if defined(LOG_CAN_TO_SD) + can_bufferHandle = xRingbufferCreate(32 * 1024, RINGBUF_TYPE_BYTEBUF); if (can_bufferHandle == NULL) { Serial.println("Failed to create CAN ring buffer!"); return; } +#endif // defined(LOG_CAN_TO_SD) + +#if defined(LOG_TO_SD) + log_bufferHandle = xRingbufferCreate(1024, RINGBUF_TYPE_BYTEBUF); + if (log_bufferHandle == NULL) { + Serial.println("Failed to create log ring buffer!"); + return; + } +#endif // defined(LOG_TO_SD) } void init_sdcard() { diff --git a/Software/src/devboard/sdcard/sdcard.h b/Software/src/devboard/sdcard/sdcard.h index 8dffeec28..60cb22fbd 100644 --- a/Software/src/devboard/sdcard/sdcard.h +++ b/Software/src/devboard/sdcard/sdcard.h @@ -9,8 +9,9 @@ #if defined(SD_CS_PIN) && defined(SD_SCLK_PIN) && defined(SD_MOSI_PIN) && \ defined(SD_MISO_PIN) // ensure code is only compiled if all SD card pins are defined #define CAN_LOG_FILE "/canlog.txt" +#define LOG_FILE "/log.txt" -void init_logging_buffer(); +void init_logging_buffers(); void init_sdcard(); void print_sdcard_details(); @@ -21,6 +22,12 @@ void write_can_frame_to_sdcard(); void pause_can_writing(); void resume_can_writing(); void delete_can_log(); -#endif // defined(SD_CS_PIN) && defined(SD_SCLK_PIN) && defined(SD_MOSI_PIN) && defined(SD_MISO_PIN) +void delete_log(); +void resume_log_writing(); +void pause_log_writing(); + +void add_log_to_buffer(const uint8_t* buffer, size_t size); +void write_log_to_sdcard(); +#endif // defined(SD_CS_PIN) && defined(SD_SCLK_PIN) && defined(SD_MOSI_PIN) && defined(SD_MISO_PIN) #endif // SDCARD_H diff --git a/Software/src/devboard/utils/logging.cpp b/Software/src/devboard/utils/logging.cpp index 0f78956f7..548c1833c 100644 --- a/Software/src/devboard/utils/logging.cpp +++ b/Software/src/devboard/utils/logging.cpp @@ -1,38 +1,84 @@ #include "logging.h" #include "../../datalayer/datalayer.h" +#include "../sdcard/sdcard.h" -size_t Logging::write(const uint8_t* buffer, size_t size) { +#define MAX_LINE_LENGTH_PRINTF 128 +#define MAX_LENGTH_TIME_STR 14 + +bool previous_message_was_newline = true; + +void Logging::add_timestamp(size_t size) { #ifdef DEBUG_LOG 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); unsigned long currentTime = millis(); -#ifdef DEBUG_VIA_USB - size_t n = 0; - while (size--) { - if (Serial.write(*buffer++)) - n++; - else - break; + char* timestr; + static char timestr_buffer[MAX_LENGTH_TIME_STR]; + +#ifdef DEBUG_VIA_WEB + if (!datalayer.system.info.can_logging_active) { + /* If web debug is active and can logging is inactive, + * we use the debug logging memory directly for writing the timestring */ + if (offset + size + MAX_LENGTH_TIME_STR > message_string_size) { + offset = 0; + } + timestr = datalayer.system.info.logged_can_messages + offset; + } else { + timestr = timestr_buffer; } - return n; -#endif +#else + timestr = timestr_buffer; +#endif // DEBUG_VIA_WEB + + offset += min(MAX_LENGTH_TIME_STR - 1, + snprintf(timestr, MAX_LENGTH_TIME_STR, "%8lu.%03lu ", currentTime / 1000, currentTime % 1000)); + #ifdef DEBUG_VIA_WEB - if (datalayer.system.info.can_logging_active) { - return 0; + if (!datalayer.system.info.can_logging_active) { + datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer } - if (offset + size + 13 > sizeof(datalayer.system.info.logged_can_messages)) { - offset = 0; +#endif // DEBUG_VIA_WEB + +#ifdef LOG_TO_SD + add_log_to_buffer((uint8_t*)timestr, MAX_LENGTH_TIME_STR); +#endif // LOG_TO_SD + +#ifdef DEBUG_VIA_USB + Serial.write(timestr); +#endif // DEBUG_VIA_USB + +#endif // DEBUG_LOG +} + +size_t Logging::write(const uint8_t* buffer, size_t size) { +#ifdef DEBUG_LOG + if (previous_message_was_newline) { + add_timestamp(size); } - if (buffer[0] != '\r' && buffer[0] != '\n' && - (offset == 0 || message_string[offset - 1] == '\r' || message_string[offset - 1] == '\n')) { - offset += snprintf(message_string + offset, message_string_size - offset - 1, "%8lu.%03lu ", currentTime / 1000, - currentTime % 1000); + +#ifdef LOG_TO_SD + add_log_to_buffer(buffer, size); +#endif +#ifdef DEBUG_VIA_USB + Serial.write(buffer, size); +#endif +#ifdef DEBUG_VIA_WEB + if (!datalayer.system.info.can_logging_active) { + 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); + + if (offset + size > message_string_size) { + offset = 0; + } + memcpy(message_string + offset, buffer, size); + datalayer.system.info.logged_can_messages_offset = offset + size; // Update offset in buffer } - memcpy(message_string + offset, buffer, size); - datalayer.system.info.logged_can_messages_offset = offset + size; // Update offset in buffer - return size; #endif // DEBUG_VIA_WEB + + previous_message_was_newline = buffer[size - 1] == '\n'; + return size; #endif // DEBUG_LOG return 0; } @@ -42,45 +88,50 @@ void Logging::printf(const char* fmt, ...) { 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); -#ifdef DEBUG_VIA_USB - static char buf[128]; - message_string = buf; - offset = 0; - message_string_size = sizeof(buf); -#endif -#ifdef DEBUG_VIA_WEB - if (datalayer.system.info.can_logging_active) { - return; + + if (previous_message_was_newline) { + add_timestamp(MAX_LINE_LENGTH_PRINTF); } - message_string = datalayer.system.info.logged_can_messages; - offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer - message_string_size = sizeof(datalayer.system.info.logged_can_messages); -#endif - if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { - // Not enough space, reset and start from the beginning - offset = 0; + + static char buffer[MAX_LINE_LENGTH_PRINTF]; + char* message_buffer; +#ifdef DEBUG_VIA_WEB + if (!datalayer.system.info.can_logging_active) { + /* If web debug is active and can logging is inactive, + * we use the debug logging memory directly for writing the output */ + if (offset + MAX_LINE_LENGTH_PRINTF > message_string_size) { + // Not enough space, reset and start from the beginning + offset = 0; + } + message_buffer = message_string + offset; + } else { + message_buffer = buffer; } - unsigned long currentTime = millis(); - // Add timestamp - offset += snprintf(message_string + offset, message_string_size - offset - 1, "%8lu.%03lu ", currentTime / 1000, - currentTime % 1000); +#else + message_buffer = buffer; +#endif // DEBUG_VIA_WEB va_list(args); va_start(args, fmt); - offset += vsnprintf(message_string + offset, message_string_size - offset - 1, fmt, args); + int size = min(MAX_LINE_LENGTH_PRINTF - 1, vsnprintf(message_buffer, MAX_LINE_LENGTH_PRINTF, fmt, args)); va_end(args); - if (datalayer.system.info.can_logging_active) { - size_t size = offset; - size_t n = 0; - while (size--) { - if (Serial.write(*message_string++)) - n++; - else - break; - } - } else { - datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer +#ifdef LOG_TO_SD + add_log_to_buffer((uint8_t*)message_buffer, size); +#endif // LOG_TO_SD + +#ifdef DEBUG_VIA_USB + Serial.write(message_buffer, size); +#endif // DEBUG_VIA_USB + +#ifdef DEBUG_VIA_WEB + if (!datalayer.system.info.can_logging_active) { + // Data was already added to buffer, just move offset + datalayer.system.info.logged_can_messages_offset = + offset + size; // Keeps track of the current position in the buffer } +#endif // DEBUG_VIA_WEB + + previous_message_was_newline = buffer[size - 1] == '\n'; #endif // DEBUG_LOG } diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h index 09b914589..84fc9a97f 100644 --- a/Software/src/devboard/utils/logging.h +++ b/Software/src/devboard/utils/logging.h @@ -5,6 +5,8 @@ #include "Print.h" class Logging : public Print { + void add_timestamp(size_t size); + public: virtual size_t write(const uint8_t* buffer, size_t size); virtual size_t write(uint8_t) { return 0; } diff --git a/Software/src/devboard/webserver/debug_logging_html.cpp b/Software/src/devboard/webserver/debug_logging_html.cpp index ce2740689..eff74dd4e 100644 --- a/Software/src/devboard/webserver/debug_logging_html.cpp +++ b/Software/src/devboard/webserver/debug_logging_html.cpp @@ -3,7 +3,7 @@ #include "../../datalayer/datalayer.h" #include "index_html.h" -#ifdef DEBUG_VIA_WEB +#if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD) String debug_logger_processor(void) { String content = String(index_html_header); // Page format @@ -17,8 +17,13 @@ String debug_logger_processor(void) { ".can-message { background-color: #404E57; margin-bottom: 5px; padding: 10px; border-radius: 5px; font-family: " "monospace; }"; content += ""; +#ifdef DEBUG_VIA_WEB content += " "; +#endif content += " "; +#ifdef LOG_TO_SD + content += " "; +#endif content += ""; // Start a new block for the debug log messages @@ -30,9 +35,12 @@ String debug_logger_processor(void) { content += ""; content += index_html_footer; return content; } -#endif // DEBUG_VIA_WEB +#endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 696873c78..be08406fc 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -65,7 +65,7 @@ void init_webserver() { request->send(response); }); -#ifdef DEBUG_VIA_WEB +#if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD) // Route for going to debug logging web page server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) { AsyncWebServerResponse* response = request->beginResponse(200, "text/html", debug_logger_processor()); @@ -123,6 +123,22 @@ void init_webserver() { }); #endif +#ifdef LOG_TO_SD + // Define the handler to delete log file + server.on("/delete_log", HTTP_GET, [](AsyncWebServerRequest* request) { + delete_log(); + request->send_P(200, "text/plain", "Log file deleted"); + }); + + // Define the handler to export debug log + server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) { + pause_log_writing(); + request->send(SD, LOG_FILE, String(), true); + resume_log_writing(); + }); +#endif + +#ifndef LOG_TO_SD // Define the handler to export debug log server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) { String logs = String(datalayer.system.info.logged_can_messages); @@ -149,6 +165,7 @@ void init_webserver() { response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\""); request->send(response); }); +#endif // Route for going to cellmonitor web page server.on("/cellmonitor", HTTP_GET, [](AsyncWebServerRequest* request) { @@ -1061,7 +1078,7 @@ String processor(const String& var) { content += " "; content += " "; content += " "; -#ifdef DEBUG_VIA_WEB +#if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD) content += " "; #endif // DEBUG_VIA_WEB content += " "; diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 7ebcc9c3b..c158b52ad 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -206,7 +206,7 @@ void init_WiFi_AP() { #ifdef DEBUG_LOG logging.println("Access Point created."); logging.print("IP address: "); - logging.println(IP); + logging.println(IP.toString()); #endif } #endif // WIFIAP diff --git a/Software/src/include.h b/Software/src/include.h index 1d88550ac..ace86b893 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -48,7 +48,7 @@ #error No battery selected! Choose one from the USER_SETTINGS.h file #endif -#ifdef LOG_CAN_TO_SD +#if defined(LOG_CAN_TO_SD) || defined(LOG_TO_SD) #if !defined(HW_LILYGO) #error The SD card logging feature is only available on LilyGo hardware #endif From 33aa75bd7c734e5dcc1b978446bec97c8c537412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 3 Jan 2025 00:43:31 +0300 Subject: [PATCH 178/225] Add BMS power reset functionality (#706) --- Software/USER_SETTINGS.h | 1 + .../comm_contactorcontrol.cpp | 55 +++++++++++++++++-- .../contactorcontrol/comm_contactorcontrol.h | 9 +++ Software/src/devboard/hal/hw_lilygo.h | 1 + Software/src/include.h | 9 +++ 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 301c7caee..b4d027fb9 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -66,6 +66,7 @@ //#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 /* Shunt/Contactor settings */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index b45aec89b..60763adae 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -39,6 +39,11 @@ unsigned long negativeStartTime = 0; unsigned long prechargeCompletedTime = 0; unsigned long timeSpentInFaultedMode = 0; #endif +unsigned long currentTime = 0; +unsigned long lastPowerRemovalTime = 0; +const unsigned long powerRemovalInterval = 24 * 60 * 60 * 1000; // 24 hours in milliseconds +const unsigned long powerRemovalDuration = 30000; // 30 seconds in milliseconds +bool isBMSResetActive = false; void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) { #ifdef PWM_CONTACTOR_CONTROL @@ -82,18 +87,24 @@ void init_contactors() { set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); #endif // CONTACTOR_CONTROL_DOUBLE_BATTERY // Init BMS contactor -#ifdef HW_STARK // TODO: Rewrite this so LilyGo can also handle this BMS contactor +#ifdef HW_STARK // This hardware has dedicated pin, always enable on start pinMode(BMS_POWER, OUTPUT); digitalWrite(BMS_POWER, HIGH); -#endif // HW_STARK +#endif // HW_STARK +#ifdef PERIODIC_BMS_RESET // User has enabled BMS reset, turn on output on start + pinMode(BMS_POWER, OUTPUT); + digitalWrite(BMS_POWER, HIGH); +#endif //PERIODIC_BMS_RESET } -// Main functions +// Main functions of the handle_contactors include checking if inverter allows for closing, checking battery 2, checking BMS power output, and actual contactor closing/precharge via GPIO void handle_contactors() { #if defined(SMA_BYD_H_CAN) || defined(SMA_BYD_HVS_CAN) || defined(SMA_TRIPOWER_CAN) datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); #endif + handle_BMSpower(); // Some batteries need to be periodically power cycled + #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY handle_contactors_battery2(); #endif // CONTACTOR_CONTROL_DOUBLE_BATTERY @@ -142,7 +153,7 @@ void handle_contactors() { return; } - unsigned long currentTime = millis(); + currentTime = millis(); if (currentTime < INTERVAL_10_S) { // Skip running the state machine before system has started up. @@ -202,3 +213,39 @@ void handle_contactors_battery2() { } } #endif // CONTACTOR_CONTROL_DOUBLE_BATTERY + +/* Once every 24 hours we remove power from the BMS_power pin for 30 seconds. 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 */ + +void handle_BMSpower() { +#ifdef PERIODIC_BMS_RESET + // Get current time + currentTime = millis(); + + // Check if 24 hours have passed since the last power removal + if (currentTime - lastPowerRemovalTime >= powerRemovalInterval && !isBMSResetActive) { + lastPowerRemovalTime = currentTime; // Record the time when BMS reset was started + + // Set emulator state to paused (Max Charge/Discharge = 0 & CAN = stop) + // TODO: We try to keep contactors engaged during this pause, and just ramp power down to 0. + // If this turns out to not work properly, set also the third option to true to open contactors + setBatteryPause(true, true, false, false); + + digitalWrite(BMS_POWER, LOW); // Remove power by setting the BMS power pin to LOW + + isBMSResetActive = true; // Set a flag to indicate power removal is active + } + + // If power has been removed for 30 seconds, restore the power and resume the emulator + if (isBMSResetActive && currentTime - lastPowerRemovalTime >= powerRemovalDuration) { + // Reapply power to the BMS + digitalWrite(BMS_POWER, HIGH); + + //Resume the battery pause and CAN communication + setBatteryPause(false, false, false, false); + + isBMSResetActive = false; // Reset the power removal flag + } +#endif //PERIODIC_BMS_RESET +} diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h index 2f4e1e0cb..ce2c0e842 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h @@ -6,6 +6,15 @@ #include "../../datalayer/datalayer.h" #include "../../devboard/utils/events.h" +/** + * @brief Handle BMS power output + * + * @param[in] void + * + * @return void + */ +void handle_BMSpower(); + /** * @brief Contactor initialization * diff --git a/Software/src/devboard/hal/hw_lilygo.h b/Software/src/devboard/hal/hw_lilygo.h index 6ffcd34ed..887f925f6 100644 --- a/Software/src/devboard/hal/hw_lilygo.h +++ b/Software/src/devboard/hal/hw_lilygo.h @@ -51,6 +51,7 @@ #define POSITIVE_CONTACTOR_PIN 32 #define NEGATIVE_CONTACTOR_PIN 33 #define PRECHARGE_PIN 25 +#define BMS_POWER 18 // Note, this pin collides with CAN add-ons and Chademo // SMA CAN contactor pins #define INVERTER_CONTACTOR_ENABLE_PIN 5 diff --git a/Software/src/include.h b/Software/src/include.h index ace86b893..bb49e8653 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -44,6 +44,15 @@ #endif #endif +#ifdef HW_LILYGO +#ifdef PERIODIC_BMS_RESET +#if defined(CAN_ADDON) || defined(CANFD_ADDON) || defined(CHADEMO_BATTERY) +//Check that BMS reset is not used at the same time as Chademo and CAN addons +#error BMS RESET CANNOT BE USED AT SAME TIME AS CAN-ADDONS / CHADMEO! NOT ENOUGH GPIO! +#endif +#endif +#endif + #ifndef BATTERY_SELECTED #error No battery selected! Choose one from the USER_SETTINGS.h file #endif From 8246e1d869005656e445365126cda44a848e1c4b Mon Sep 17 00:00:00 2001 From: mvgalen Date: Fri, 3 Jan 2025 14:31:44 +0100 Subject: [PATCH 179/225] Fix bugs in printf logging code & add version to log - Fix printf end of line detection - Fix overwriting of timestamp in printf path - Add version + build date/time to log --- Software/src/devboard/utils/logging.cpp | 9 ++++----- Software/src/devboard/utils/logging.h | 4 +++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Software/src/devboard/utils/logging.cpp b/Software/src/devboard/utils/logging.cpp index 548c1833c..c6811697d 100644 --- a/Software/src/devboard/utils/logging.cpp +++ b/Software/src/devboard/utils/logging.cpp @@ -85,14 +85,13 @@ size_t Logging::write(const uint8_t* buffer, size_t size) { void Logging::printf(const char* fmt, ...) { #ifdef DEBUG_LOG - 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); - if (previous_message_was_newline) { add_timestamp(MAX_LINE_LENGTH_PRINTF); } + char* message_string = datalayer.system.info.logged_can_messages; + size_t message_string_size = sizeof(datalayer.system.info.logged_can_messages); + int offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer static char buffer[MAX_LINE_LENGTH_PRINTF]; char* message_buffer; #ifdef DEBUG_VIA_WEB @@ -132,6 +131,6 @@ void Logging::printf(const char* fmt, ...) { } #endif // DEBUG_VIA_WEB - previous_message_was_newline = buffer[size - 1] == '\n'; + previous_message_was_newline = message_buffer[size - 1] == '\n'; #endif // DEBUG_LOG } diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h index 84fc9a97f..89d579cf2 100644 --- a/Software/src/devboard/utils/logging.h +++ b/Software/src/devboard/utils/logging.h @@ -4,6 +4,8 @@ #include #include "Print.h" +extern const char* version_number; // The current software version, shown on webserver + class Logging : public Print { void add_timestamp(size_t size); @@ -11,7 +13,7 @@ class Logging : public Print { virtual size_t write(const uint8_t* buffer, size_t size); virtual size_t write(uint8_t) { return 0; } void printf(const char* fmt, ...); - Logging() {} + Logging() {printf("Battery emulator %s build "__DATE__ " " __TIME__ "\n", version_number);} }; extern Logging logging; From 3705d27fc3dfec057854fe94e2a008d8e9452762 Mon Sep 17 00:00:00 2001 From: mvgalen Date: Fri, 3 Jan 2025 14:34:07 +0100 Subject: [PATCH 180/225] Fix code formatting --- Software/src/devboard/utils/logging.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h index 89d579cf2..09e9a6202 100644 --- a/Software/src/devboard/utils/logging.h +++ b/Software/src/devboard/utils/logging.h @@ -13,7 +13,11 @@ class Logging : public Print { virtual size_t write(const uint8_t* buffer, size_t size); virtual size_t write(uint8_t) { return 0; } void printf(const char* fmt, ...); - Logging() {printf("Battery emulator %s build "__DATE__ " " __TIME__ "\n", version_number);} + Logging() { + printf("Battery emulator %s build "__DATE__ + " " __TIME__ "\n", + version_number); + } }; extern Logging logging; From fd76959a211503152492ad50723ff06cbf45d245 Mon Sep 17 00:00:00 2001 From: mvgalen Date: Fri, 3 Jan 2025 14:39:19 +0100 Subject: [PATCH 181/225] Fix code formatting. --- Software/src/devboard/utils/logging.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h index 09e9a6202..102c0d80e 100644 --- a/Software/src/devboard/utils/logging.h +++ b/Software/src/devboard/utils/logging.h @@ -14,9 +14,10 @@ class Logging : public Print { virtual size_t write(uint8_t) { return 0; } void printf(const char* fmt, ...); Logging() { - printf("Battery emulator %s build "__DATE__ - " " __TIME__ "\n", - version_number); + printf( + "Battery emulator %s build "__DATE__ + " " __TIME__ "\n", + version_number); } }; From c8efe2ff6307a12d215f7ae026e12e4281d50c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 3 Jan 2025 16:52:58 +0300 Subject: [PATCH 182/225] Add support for BMS2 power (#741) --- .../comm_contactorcontrol.cpp | 20 ++++++++++++++++--- Software/src/devboard/hal/hw_3LB.h | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index 60763adae..8accc245e 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -87,13 +87,21 @@ void init_contactors() { set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); #endif // CONTACTOR_CONTROL_DOUBLE_BATTERY // Init BMS contactor -#ifdef HW_STARK // This hardware has dedicated pin, always enable on start - pinMode(BMS_POWER, OUTPUT); +#if defined HW_STARK || defined HW_3LB // This hardware has dedicated pin, always enable on start + pinMode(BMS_POWER, OUTPUT); //LilyGo is omitted from this, only enabled if user selects PERIODIC_BMS_RESET digitalWrite(BMS_POWER, HIGH); -#endif // HW_STARK +#ifdef BMS_2_POWER //Hardware supports 2x BMS + pinMode(BMS_2_POWER, OUTPUT); + digitalWrite(BMS_2_POWER, HIGH); +#endif BMS_2_POWER +#endif // HW with dedicated BMS pins #ifdef PERIODIC_BMS_RESET // User has enabled BMS reset, turn on output on start pinMode(BMS_POWER, OUTPUT); digitalWrite(BMS_POWER, HIGH); +#ifdef BMS_2_POWER //Hardware supports 2x BMS + pinMode(BMS_2_POWER, OUTPUT); + digitalWrite(BMS_2_POWER, HIGH); +#endif BMS_2_POWER #endif //PERIODIC_BMS_RESET } @@ -233,6 +241,9 @@ void handle_BMSpower() { setBatteryPause(true, true, false, false); digitalWrite(BMS_POWER, LOW); // Remove power by setting the BMS power pin to LOW +#ifdef BMS_2_POWER + digitalWrite(BMS_2_POWER, LOW); // Same for battery 2 +#endif isBMSResetActive = true; // Set a flag to indicate power removal is active } @@ -241,6 +252,9 @@ void handle_BMSpower() { if (isBMSResetActive && currentTime - lastPowerRemovalTime >= powerRemovalDuration) { // Reapply power to the BMS digitalWrite(BMS_POWER, HIGH); +#ifdef BMS_2_POWER + digitalWrite(BMS_2_POWER, HIGH); // Same for battery 2 +#endif //Resume the battery pause and CAN communication setBatteryPause(false, false, false, false); diff --git a/Software/src/devboard/hal/hw_3LB.h b/Software/src/devboard/hal/hw_3LB.h index 5fd8ef6f5..ded31420d 100644 --- a/Software/src/devboard/hal/hw_3LB.h +++ b/Software/src/devboard/hal/hw_3LB.h @@ -51,10 +51,12 @@ #define POSITIVE_CONTACTOR_PIN 32 #define NEGATIVE_CONTACTOR_PIN 33 #define PRECHARGE_PIN 25 +#define BMS_POWER 2 #define SECOND_POSITIVE_CONTACTOR_PIN 13 #define SECOND_NEGATIVE_CONTACTOR_PIN 16 #define SECOND_PRECHARGE_PIN 18 +#define BMS_2_POWER 12 // SMA CAN contactor pins #define INVERTER_CONTACTOR_ENABLE_PIN 36 From 7df7992149a43a74c39a085d4fb284d5244dae82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 3 Jan 2025 22:53:04 +0300 Subject: [PATCH 183/225] Kia64: Add sanity checking for last cellvoltages (#745) * Add sanity checking for last cellvoltages --- Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 6b4651b4c..2a052e6a5 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -440,6 +440,12 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { } break; case 0x26: //Sixth datarow in PID group + //We have read all cells, check that content is valid: + for (uint8_t i = 85; i < 97; ++i) { + if (cellvoltages_mv[i] < 300) { // Zero the value if it's below 300 + cellvoltages_mv[i] = 0; // Some packs incorrectly report the last unpopulated cells as 20-60mV + } + } //Map all cell voltages to the global array memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages_mv, 98 * sizeof(uint16_t)); //Update number of cells From 01ae0c12785fae0902011d4c57b861a0383c0a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 3 Jan 2025 23:53:38 +0300 Subject: [PATCH 184/225] Volvo/Polestar: Add contactor closing and DTC reset (#744) * Add contactor closing and DTC reset --- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 132 ++++++++++++++++- Software/src/datalayer/datalayer_extended.h | 31 ++++ .../webserver/advanced_battery_html.cpp | 136 +++++++++++++++++- Software/src/devboard/webserver/webserver.cpp | 27 ++++ 4 files changed, 316 insertions(+), 10 deletions(-) diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index 2d27b02f4..a2517696b 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -1,6 +1,7 @@ #include "../include.h" #ifdef VOLVO_SPA_BATTERY #include "../datalayer/datalayer.h" +#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage #include "../devboard/utils/events.h" #include "VOLVO-SPA-BATTERY.h" @@ -19,11 +20,14 @@ static float BATT_T_MIN = 0; //0x413 static float BATT_T_AVG = 0; //0x413 static uint16_t SOC_BMS = 0; //0X37D static uint16_t SOC_CALC = 0; -static uint16_t CELL_U_MAX = 3700; //0x37D -static uint16_t CELL_U_MIN = 3700; //0x37D -static uint8_t CELL_ID_U_MAX = 0; //0x37D -static uint16_t HvBattPwrLimDchaSoft = 0; //0x369 -static uint8_t batteryModuleNumber = 0x10; // First battery module +static uint16_t CELL_U_MAX = 3700; //0x37D +static uint16_t CELL_U_MIN = 3700; //0x37D +static uint8_t CELL_ID_U_MAX = 0; //0x37D +static uint16_t HvBattPwrLimDchaSoft = 0; //0x369 +static uint16_t HvBattPwrLimDcha1 = 0; //0x175 +static uint16_t HvBattPwrLimDchaSlowAgi = 0; //0x177 +static uint16_t HvBattPwrLimChrgSlowAgi = 0; //0x177 +static uint8_t batteryModuleNumber = 0x10; // First battery module static uint8_t battery_request_idx = 0; static uint8_t rxConsecutiveFrames = 0; static uint16_t min_max_voltage[2]; //contains cell min[0] and max[1] values in mV @@ -35,7 +39,21 @@ CAN_frame VOLVO_536 = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x536, - .data = {0x00, 0x40, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Network manage frame + //.data = {0x00, 0x40, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Network manage frame + .data = {0x00, 0x40, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}; //Network manage frame + +CAN_frame VOLVO_140_CLOSE = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x140, + .data = {0x00, 0x02, 0x00, 0xB7, 0xFF, 0x03, 0xFF, 0x83}}; //Close contactors message + +CAN_frame VOLVO_140_OPEN = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x140, + .data = {0x00, 0x02, 0x00, 0x9E, 0xFF, 0x03, 0xFF, 0x83}}; //Open contactor message + CAN_frame VOLVO_372 = { .FD = false, .ext_ID = false, @@ -57,10 +75,62 @@ CAN_frame VOLVO_SOH_Req = {.FD = false, .DLC = 8, .ID = 0x735, .data = {0x03, 0x22, 0x49, 0x6D, 0x00, 0x00, 0x00, 0x00}}; //Battery SOH request frame +CAN_frame VOLVO_BECMsupplyVoltage_Req = { + .FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x735, + .data = {0x03, 0x22, 0xF4, 0x42, 0x00, 0x00, 0x00, 0x00}}; //BECM supply voltage request frame +CAN_frame VOLVO_DTC_Erase = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7FF, + .data = {0x04, 0x14, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}}; //Global DTC erase +CAN_frame VOLVO_BECM_ECUreset = { + .FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x735, + .data = {0x02, 0x11, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00}}; //BECM ECU reset command (reboot/powercycle BECM) +CAN_frame VOLVO_DTCreadout = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7FF, + .data = {0x02, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Global DTC readout void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter uint8_t cnt = 0; + // Update webserver datalayer + datalayer_extended.VolvoPolestar.soc_bms = SOC_BMS; + datalayer_extended.VolvoPolestar.soc_calc = SOC_CALC; + datalayer_extended.VolvoPolestar.soc_rescaled = datalayer.battery.status.reported_soc; + datalayer_extended.VolvoPolestar.soh_bms = datalayer.battery.status.soh_pptt; + + datalayer_extended.VolvoPolestar.BECMBatteryVoltage = BATT_U; + datalayer_extended.VolvoPolestar.BECMBatteryCurrent = BATT_I; + datalayer_extended.VolvoPolestar.BECMUDynMaxLim = MAX_U; + datalayer_extended.VolvoPolestar.BECMUDynMinLim = MIN_U; + + datalayer_extended.VolvoPolestar.HvBattPwrLimDcha1 = HvBattPwrLimDcha1; + datalayer_extended.VolvoPolestar.HvBattPwrLimDchaSoft = HvBattPwrLimDchaSoft; + datalayer_extended.VolvoPolestar.HvBattPwrLimDchaSlowAgi = HvBattPwrLimDchaSlowAgi; + datalayer_extended.VolvoPolestar.HvBattPwrLimChrgSlowAgi = HvBattPwrLimChrgSlowAgi; + + // Update requests from webserver datalayer + if (datalayer_extended.VolvoPolestar.UserRequestDTCreset) { + transmit_can_frame(&VOLVO_DTC_Erase, can_config.battery); //Send global DTC erase command + datalayer_extended.VolvoPolestar.UserRequestDTCreset = false; + } + if (datalayer_extended.VolvoPolestar.UserRequestBECMecuReset) { + transmit_can_frame(&VOLVO_BECM_ECUreset, can_config.battery); //Send BECM ecu reset command + datalayer_extended.VolvoPolestar.UserRequestBECMecuReset = false; + } + if (datalayer_extended.VolvoPolestar.UserRequestDTCreadout) { + transmit_can_frame(&VOLVO_DTCreadout, can_config.battery); //Send DTC readout command + datalayer_extended.VolvoPolestar.UserRequestDTCreadout = false; + } + remaining_capacity = (78200 - CHARGE_ENERGY); //datalayer.battery.status.real_soc = SOC_BMS; // Use BMS reported SOC, havent figured out how to get the BMS to calibrate empty/full yet @@ -175,6 +245,25 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { logging.println("BATT_U not valid"); #endif } + + if ((rx_frame.data.u8[0] & 0x40) == 0x40) + datalayer_extended.VolvoPolestar.HVSysRlySts = ((rx_frame.data.u8[0] & 0x30) >> 4); + else + datalayer_extended.VolvoPolestar.HVSysRlySts = 0xFF; + + if ((rx_frame.data.u8[2] & 0x40) == 0x40) + datalayer_extended.VolvoPolestar.HVSysDCRlySts1 = ((rx_frame.data.u8[2] & 0x30) >> 4); + else + datalayer_extended.VolvoPolestar.HVSysDCRlySts1 = 0xFF; + if ((rx_frame.data.u8[2] & 0x80) == 0x80) + datalayer_extended.VolvoPolestar.HVSysDCRlySts2 = ((rx_frame.data.u8[4] & 0x30) >> 4); + else + datalayer_extended.VolvoPolestar.HVSysDCRlySts2 = 0xFF; + if ((rx_frame.data.u8[0] & 0x80) == 0x80) + datalayer_extended.VolvoPolestar.HVSysIsoRMonrSts = ((rx_frame.data.u8[4] & 0xC0) >> 6); + else + datalayer_extended.VolvoPolestar.HVSysIsoRMonrSts = 0xFF; + break; case 0x1A1: if ((rx_frame.data.u8[4] & 0x10) == 0x10) @@ -216,6 +305,25 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { #endif } break; + case 0x175: + if ((rx_frame.data.u8[4] & 0x80) == 0x80) { + HvBattPwrLimDcha1 = (((rx_frame.data.u8[2] & 0x07) * 256 + rx_frame.data.u8[3]) >> 2); + } else { + HvBattPwrLimDcha1 = 0; + } + break; + case 0x177: + if ((rx_frame.data.u8[4] & 0x08) == 0x08) { + HvBattPwrLimDchaSlowAgi = (((rx_frame.data.u8[4] & 0x07) * 256 + rx_frame.data.u8[5]) >> 2); + } else { + HvBattPwrLimDchaSlowAgi = 0; + } + if ((rx_frame.data.u8[2] & 0x08) == 0x08) { + HvBattPwrLimChrgSlowAgi = (((rx_frame.data.u8[2] & 0x07) * 256 + rx_frame.data.u8[3]) >> 2); + } else { + HvBattPwrLimChrgSlowAgi = 0; + } + break; case 0x37D: if ((rx_frame.data.u8[0] & 0x40) == 0x40) { SOC_BMS = ((rx_frame.data.u8[6] & 0x03) * 256 + rx_frame.data.u8[7]); @@ -258,6 +366,11 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { (rx_frame.data.u8[3] == 0x6D)) // SOH response frame { datalayer.battery.status.soh_pptt = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + transmit_can_frame(&VOLVO_BECMsupplyVoltage_Req, can_config.battery); //Send BECM supply voltage req + } else if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x62) && (rx_frame.data.u8[2] == 0xF4) && + (rx_frame.data.u8[3] == 0x42)) // BECM module voltage supply + { + datalayer_extended.VolvoPolestar.BECMsupplyVoltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); } else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[1] == 0x0B) && (rx_frame.data.u8[2] == 0x62) && (rx_frame.data.u8[3] == 0x4B)) // First response frame of cell voltages { @@ -265,6 +378,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control rxConsecutiveFrames = 1; + } else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[2] == 0x59) && + (rx_frame.data.u8[3] == 0x03)) // First response frame for DTC with more than one code + { + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x21) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; @@ -283,7 +400,6 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { if (min_max_voltage[1] < cell_voltages[cellcounter]) min_max_voltage[1] = cell_voltages[cellcounter]; } - transmit_can_frame(&VOLVO_SOH_Req, can_config.battery); //Send SOH read request } rxConsecutiveFrames = 0; @@ -319,8 +435,10 @@ void transmit_can_battery() { if (datalayer.battery.status.bms_status == ACTIVE) { datalayer.system.status.battery_allows_contactor_closing = true; + transmit_can_frame(&VOLVO_140_CLOSE, can_config.battery); //Send 0x140 Close contactors message } else { //datalayer.battery.status.bms_status == FAULT or inverter requested opening contactors datalayer.system.status.battery_allows_contactor_closing = false; + transmit_can_frame(&VOLVO_140_OPEN, can_config.battery); //Send 0x140 Open contactors message } } if (currentMillis - previousMillis60s >= INTERVAL_60_S) { diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 190640357..3148194ea 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -523,6 +523,36 @@ typedef struct { int32_t BMS_voltage_dV = 0; } DATALAYER_INFO_MEB; +typedef struct { + uint16_t soc_bms = 0; + uint16_t soc_calc = 0; + uint16_t soc_rescaled = 0; + uint16_t soh_bms = 0; + uint16_t BECMsupplyVoltage = 0; + + uint16_t BECMBatteryVoltage = 0; + uint16_t BECMBatteryCurrent = 0; + uint16_t BECMUDynMaxLim = 0; + uint16_t BECMUDynMinLim = 0; + + uint16_t HvBattPwrLimDcha1 = 0; + uint16_t HvBattPwrLimDchaSoft = 0; + uint16_t HvBattPwrLimDchaSlowAgi = 0; + uint16_t HvBattPwrLimChrgSlowAgi = 0; + + uint8_t HVSysRlySts = 0; + uint8_t HVSysDCRlySts1 = 0; + uint8_t HVSysDCRlySts2 = 0; + uint8_t HVSysIsoRMonrSts = 0; + /** User requesting DTC reset via WebUI*/ + bool UserRequestDTCreset = false; + /** User requesting DTC readout via WebUI*/ + bool UserRequestDTCreadout = false; + /** User requesting BECM reset via WebUI*/ + bool UserRequestBECMecuReset = false; + +} DATALAYER_INFO_VOLVO_POLESTAR; + typedef struct { /** uint16_t */ /** Values WIP*/ @@ -579,6 +609,7 @@ class DataLayerExtended { DATALAYER_INFO_TESLA tesla; DATALAYER_INFO_NISSAN_LEAF nissanleaf; DATALAYER_INFO_MEB meb; + DATALAYER_INFO_VOLVO_POLESTAR VolvoPolestar; DATALAYER_INFO_ZOE_PH2 zoePH2; }; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index c15697148..308d22a74 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -1030,10 +1030,107 @@ String advanced_battery_processor(const String& var) { content += "

soc max: " + String(datalayer_extended.zoePH2.battery_soc_max) + "

"; #endif //RENAULT_ZOE_GEN2_BATTERY +#ifdef VOLVO_SPA_BATTERY + content += "

BECM reported SOC: " + String(datalayer_extended.VolvoPolestar.soc_bms) + "

"; + content += "

Calculated SOC: " + String(datalayer_extended.VolvoPolestar.soc_calc) + "

"; + content += "

Rescaled SOC: " + String(datalayer_extended.VolvoPolestar.soc_rescaled / 10) + "

"; + content += "

BECM reported SOH: " + String(datalayer_extended.VolvoPolestar.soh_bms) + "

"; + content += "

BECM supply voltage: " + String(datalayer_extended.VolvoPolestar.BECMsupplyVoltage) + " mV

"; + + content += "

HV voltage: " + String(datalayer_extended.VolvoPolestar.BECMBatteryVoltage) + " V

"; + content += "

HV current: " + String(datalayer_extended.VolvoPolestar.BECMBatteryCurrent) + " A

"; + content += "

Dynamic max voltage: " + String(datalayer_extended.VolvoPolestar.BECMUDynMaxLim) + " V

"; + content += "

Dynamic min voltage: " + String(datalayer_extended.VolvoPolestar.BECMUDynMinLim) + " V

"; + + content += + "

Discharge power limit 1: " + String(datalayer_extended.VolvoPolestar.HvBattPwrLimDcha1) + " kW

"; + content += + "

Discharge soft power limit: " + String(datalayer_extended.VolvoPolestar.HvBattPwrLimDchaSoft) + " kW

"; + content += + "

Discharge power limit slow aging: " + String(datalayer_extended.VolvoPolestar.HvBattPwrLimDchaSlowAgi) + + " kW

"; + content += + "

Charge power limit slow aging: " + String(datalayer_extended.VolvoPolestar.HvBattPwrLimChrgSlowAgi) + + " kW

"; + + content += "

HV system relay status: "; + switch (datalayer_extended.VolvoPolestar.HVSysRlySts) { + case 0: + content += String("Open"); + break; + case 1: + content += String("Closed"); + break; + case 2: + content += String("KeepStatus"); + break; + case 3: + content += String("OpenAndRequestActiveDischarge"); + break; + default: + content += String("Not valid"); + } + content += "

HV system relay status 1: "; + switch (datalayer_extended.VolvoPolestar.HVSysDCRlySts1) { + case 0: + content += String("Open"); + break; + case 1: + content += String("Closed"); + break; + case 2: + content += String("KeepStatus"); + break; + case 3: + content += String("Fault"); + break; + default: + content += String("Not valid"); + } + content += "

HV system relay status 2: "; + switch (datalayer_extended.VolvoPolestar.HVSysDCRlySts2) { + case 0: + content += String("Open"); + break; + case 1: + content += String("Closed"); + break; + case 2: + content += String("KeepStatus"); + break; + case 3: + content += String("Fault"); + break; + default: + content += String("Not valid"); + } + content += "

HV system isolation resistance monitoring status: "; + switch (datalayer_extended.VolvoPolestar.HVSysIsoRMonrSts) { + case 0: + content += String("Not valid 1"); + break; + case 1: + content += String("False"); + break; + case 2: + content += String("True"); + break; + case 3: + content += String("Not valid 2"); + break; + default: + content += String("Not valid"); + } + + content += "


"; + content += "
"; + content += ""; +#endif // VOLVO_SPA_BATTERY + #if !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_BATTERY) && !defined(TESLA_BATTERY) && \ !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && !defined(BYD_ATTO_3_BATTERY) && \ - !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ - !defined(MEB_BATTERY) // Only the listed types have extra info + !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && !defined(MEB_BATTERY) && \ + !defined(VOLVO_SPA_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif @@ -1051,7 +1148,40 @@ String advanced_battery_processor(const String& var) { content += "}"; content += "function goToMainPage() { window.location.href = '/'; }"; content += ""; - return content; + + content += ""; + + content += ""; + + content += ""; } return String(); } diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index be08406fc..135489904 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -394,6 +394,33 @@ void init_webserver() { request->send(200, "text/plain", "Updated successfully"); }); + // Route for erasing DTC on Volvo/Polestar batteries + server.on("/volvoEraseDTC", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + datalayer_extended.VolvoPolestar.UserRequestDTCreset = true; + request->send(200, "text/plain", "Updated successfully"); + }); + + // Route for reading DTC on Volvo/Polestar batteries + server.on("/volvoReadDTC", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + datalayer_extended.VolvoPolestar.UserRequestDTCreadout = true; + request->send(200, "text/plain", "Updated successfully"); + }); + + // Route for performing ECU reset on Volvo/Polestar batteries + server.on("/volvoBECMecuReset", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + datalayer_extended.VolvoPolestar.UserRequestBECMecuReset = true; + request->send(200, "text/plain", "Updated successfully"); + }); + #ifdef TEST_FAKE_BATTERY // Route for editing FakeBatteryVoltage server.on("/updateFakeBatteryVoltage", HTTP_GET, [](AsyncWebServerRequest* request) { From 3f993f7d235a195cbb7e0dbf868add61812d4d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 4 Jan 2025 11:14:19 +0200 Subject: [PATCH 185/225] Add more battery info data --- .../src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 14 +++++++++++-- Software/src/datalayer/datalayer_extended.h | 12 +++++++++++ .../webserver/advanced_battery_html.cpp | 21 ++++++++++++++++--- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 2a052e6a5..97c500c2f 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -1,6 +1,7 @@ #include "../include.h" #ifdef KIA_HYUNDAI_64_BATTERY #include "../datalayer/datalayer.h" +#include "../datalayer/datalayer_extended.h" #include "../devboard/utils/events.h" #include "KIA-HYUNDAI-64-BATTERY.h" @@ -141,8 +142,17 @@ void update_values_battery() { //This function maps all the values fetched via set_event(EVENT_12V_LOW, leadAcidBatteryVoltage); } - /* Safeties verified. Perform USB serial printout if configured to do so */ - + // Update webserver datalayer + datalayer_extended.KiaHyundai64.total_cell_count = datalayer.battery.info.number_of_cells; + datalayer_extended.KiaHyundai64.battery_12V = leadAcidBatteryVoltage; + datalayer_extended.KiaHyundai64.waterleakageSensor = waterleakageSensor; + datalayer_extended.KiaHyundai64.temperature_water_inlet = temperature_water_inlet; + datalayer_extended.KiaHyundai64.powerRelayTemperature = powerRelayTemperature * 2; + datalayer_extended.KiaHyundai64.batteryManagementMode = batteryManagementMode; + datalayer_extended.KiaHyundai64.BMS_ign = BMS_ign; + datalayer_extended.KiaHyundai64.batteryRelay = batteryRelay; + + //Perform logging if configured to do so #ifdef DEBUG_LOG logging.println(); //sepatator logging.println("Values from battery: "); diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 3148194ea..3bf20f218 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -194,6 +194,17 @@ typedef struct { bool warning_Charger_not_responding = false; } DATALAYER_INFO_CELLPOWER; +typedef struct { + uint8_t total_cell_count = 0; + int16_t battery_12V = 0; + uint8_t waterleakageSensor = 0; + int8_t temperature_water_inlet = 0; + int8_t powerRelayTemperature = 0; + uint8_t batteryManagementMode = 0; + uint8_t BMS_ign = 0; + uint8_t batteryRelay = 0; +} DATALAYER_INFO_KIAHYUNDAI64; + typedef struct { /** uint8_t */ /** Contactor status */ @@ -606,6 +617,7 @@ class DataLayerExtended { DATALAYER_INFO_BMWI3 bmwi3; DATALAYER_INFO_BYDATTO3 bydAtto3; DATALAYER_INFO_CELLPOWER cellpower; + DATALAYER_INFO_KIAHYUNDAI64 KiaHyundai64; DATALAYER_INFO_TESLA tesla; DATALAYER_INFO_NISSAN_LEAF nissanleaf; DATALAYER_INFO_MEB meb; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 308d22a74..8413c5fe9 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -316,6 +316,19 @@ String advanced_battery_processor(const String& var) { String(falseTrue[datalayer_extended.cellpower.warning_Charger_not_responding]) + "

"; #endif //CELLPOWER_BMS +#ifdef KIA_HYUNDAI_64_BATTERY + /* + content += "

Cells: " + String(datalayer_extended.KiaHyundai64.total_cell_count) + "S

"; + content += "

12V voltage: " + String(datalayer_extended.KiaHyundai64.battery_12V) + "

"; + content += "

Waterleakage: " + String(datalayer_extended.KiaHyundai64.waterleakageSensor) + "

"; + content += "

Temperature, water inlet: " + String(datalayer_extended.KiaHyundai64.temperature_water_inlet) + "

"; + content += "

Temperature, power relay: " + String(datalayer_extended.KiaHyundai64.powerRelayTemperature) + "

"; + content += "

Batterymanagement mode: " + String(datalayer_extended.KiaHyundai64.batteryManagementMode) + "

"; + content += "

BMS ignition: " + String(datalayer_extended.KiaHyundai64.BMS_ign) + "

"; + content += "

Battery relay: " + String(datalayer_extended.KiaHyundai64.batteryRelay) + "

"; + */ +#endif //KIA_HYUNDAI_64_BATTERY + #ifdef BYD_ATTO_3_BATTERY static const char* SOCmethod[2] = {"Estimated from voltage", "Measured by BMS"}; content += "

SOC method used: " + String(SOCmethod[datalayer_extended.bydAtto3.SOC_method]) + "

"; @@ -1130,12 +1143,12 @@ String advanced_battery_processor(const String& var) { #if !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_BATTERY) && !defined(TESLA_BATTERY) && \ !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && !defined(BYD_ATTO_3_BATTERY) && \ !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && !defined(MEB_BATTERY) && \ - !defined(VOLVO_SPA_BATTERY) //Only the listed types have extra info + !defined(VOLVO_SPA_BATTERY) && !defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif content += "
"; - +#ifdef NISSAN_LEAF_BATTERY content += ""; - +#endif //NISSAN_LEAF_BATTERY +#ifdef VOLVO_SPA_BATTERY content += ""; +#endif //VOLVO_SPA_BATTERY } return String(); } From bf08d5b852f43e6b2015c29c4c1a7b0202a170b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 4 Jan 2025 11:31:34 +0200 Subject: [PATCH 186/225] Add more sanity checking to cellvoltage reading --- .../src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 36 +++++++++++++------ .../webserver/advanced_battery_html.cpp | 26 +++++++------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 97c500c2f..4555cd455 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -420,7 +420,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cellvoltages_mv[87] = (rx_frame.data.u8[4] * 20); cellvoltages_mv[88] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[89] = (rx_frame.data.u8[6] * 20); - cellvoltages_mv[90] = (rx_frame.data.u8[7] * 20); + if (rx_frame.data.u8[7] > 4) { // Data only valid on 98S + cellvoltages_mv[90] = (rx_frame.data.u8[7] * 20); // Perform extra checks + } } else if (poll_data_pid == 5) { batterySOH = ((rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3]); } @@ -438,15 +440,29 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cellvoltages_mv[61] = (rx_frame.data.u8[3] * 20); cellvoltages_mv[62] = (rx_frame.data.u8[4] * 20); cellvoltages_mv[63] = (rx_frame.data.u8[5] * 20); - } else if (poll_data_pid == 4) { - cellvoltages_mv[91] = (rx_frame.data.u8[1] * 20); - cellvoltages_mv[92] = (rx_frame.data.u8[2] * 20); - cellvoltages_mv[93] = (rx_frame.data.u8[3] * 20); - cellvoltages_mv[94] = (rx_frame.data.u8[4] * 20); - cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20); - } else if (poll_data_pid == 5) { - cellvoltages_mv[96] = (rx_frame.data.u8[4] * 20); - cellvoltages_mv[97] = (rx_frame.data.u8[5] * 20); + } else if (poll_data_pid == 4) { // Data only valid on 98S + if (rx_frame.data.u8[1] > 4) { // Perform extra checks + cellvoltages_mv[91] = (rx_frame.data.u8[1] * 20); + } + if (rx_frame.data.u8[2] > 4) { // Perform extra checks + cellvoltages_mv[92] = (rx_frame.data.u8[2] * 20); + } + if (rx_frame.data.u8[3] > 4) { // Perform extra checks + cellvoltages_mv[93] = (rx_frame.data.u8[3] * 20); + } + if (rx_frame.data.u8[4] > 4) { // Perform extra checks + cellvoltages_mv[94] = (rx_frame.data.u8[4] * 20); + } + if (rx_frame.data.u8[5] > 4) { // Perform extra checks + cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20); + } + } else if (poll_data_pid == 5) { // Data only valid on 98S + if (rx_frame.data.u8[4] > 4) { // Perform extra checks + cellvoltages_mv[96] = (rx_frame.data.u8[4] * 20); + } + if (rx_frame.data.u8[5] > 4) { // Perform extra checks + cellvoltages_mv[97] = (rx_frame.data.u8[5] * 20); + } } break; case 0x26: //Sixth datarow in PID group diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 8413c5fe9..b999e6e39 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -317,16 +317,16 @@ String advanced_battery_processor(const String& var) { #endif //CELLPOWER_BMS #ifdef KIA_HYUNDAI_64_BATTERY - /* - content += "

Cells: " + String(datalayer_extended.KiaHyundai64.total_cell_count) + "S

"; - content += "

12V voltage: " + String(datalayer_extended.KiaHyundai64.battery_12V) + "

"; - content += "

Waterleakage: " + String(datalayer_extended.KiaHyundai64.waterleakageSensor) + "

"; - content += "

Temperature, water inlet: " + String(datalayer_extended.KiaHyundai64.temperature_water_inlet) + "

"; - content += "

Temperature, power relay: " + String(datalayer_extended.KiaHyundai64.powerRelayTemperature) + "

"; - content += "

Batterymanagement mode: " + String(datalayer_extended.KiaHyundai64.batteryManagementMode) + "

"; - content += "

BMS ignition: " + String(datalayer_extended.KiaHyundai64.BMS_ign) + "

"; - content += "

Battery relay: " + String(datalayer_extended.KiaHyundai64.batteryRelay) + "

"; - */ + content += "

Cells: " + String(datalayer_extended.KiaHyundai64.total_cell_count) + "S

"; + content += "

12V voltage: " + String(datalayer_extended.KiaHyundai64.battery_12V / 10.0, 1) + "

"; + content += "

Waterleakage: " + String(datalayer_extended.KiaHyundai64.waterleakageSensor) + "

"; + content += + "

Temperature, water inlet: " + String(datalayer_extended.KiaHyundai64.temperature_water_inlet) + "

"; + content += + "

Temperature, power relay: " + String(datalayer_extended.KiaHyundai64.powerRelayTemperature) + "

"; + content += "

Batterymanagement mode: " + String(datalayer_extended.KiaHyundai64.batteryManagementMode) + "

"; + content += "

BMS ignition: " + String(datalayer_extended.KiaHyundai64.BMS_ign) + "

"; + content += "

Battery relay: " + String(datalayer_extended.KiaHyundai64.batteryRelay) + "

"; #endif //KIA_HYUNDAI_64_BATTERY #ifdef BYD_ATTO_3_BATTERY @@ -1148,7 +1148,6 @@ String advanced_battery_processor(const String& var) { #endif content += "
"; -#ifdef NISSAN_LEAF_BATTERY content += ""; -#endif //NISSAN_LEAF_BATTERY -#ifdef VOLVO_SPA_BATTERY content += ""; -#endif //VOLVO_SPA_BATTERY + + return content; } return String(); } From 8c8fddd32b4fc6127e9840e98794d02b95b36a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 4 Jan 2025 21:52:56 +0200 Subject: [PATCH 187/225] Make SPA use BMS allowed charge/discharge values --- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index a2517696b..99fd777cf 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -150,9 +150,8 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.current_dA = BATT_I * 10; datalayer.battery.status.remaining_capacity_Wh = remaining_capacity; - //datalayer.battery.status.max_discharge_power_W = HvBattPwrLimDchaSoft * 1000; // Use power limit reported from BMS, not trusted ATM - datalayer.battery.status.max_discharge_power_W = 30000; - datalayer.battery.status.max_charge_power_W = 30000; + datalayer.battery.status.max_discharge_power_W = HvBattPwrLimDchaSlowAgi * 1000; //kW to W + datalayer.battery.status.max_charge_power_W = HvBattPwrLimChrgSlowAgi * 1000; //kW to W datalayer.battery.status.temperature_min_dC = BATT_T_MIN; datalayer.battery.status.temperature_max_dC = BATT_T_MAX; From f47f5ca9d3304d9035234d65185cd227b6ce094b Mon Sep 17 00:00:00 2001 From: mvgalen Date: Sat, 4 Jan 2025 22:29:46 +0100 Subject: [PATCH 188/225] Move logging of version/data/time to setup() Move logging of version/data/time to setup() to ensure it is also printed to serial. --- Software/Software.ino | 4 ++++ Software/src/devboard/utils/logging.h | 9 +-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 7c75b07d5..44016637e 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -97,6 +97,10 @@ Logging logging; void setup() { init_serial(); + // We print this after setting up serial, such that is also printed to serial with DEBUG_VIA_USB set. + logging.printf("Battery emulator %s build " __DATE__ + " " __TIME__ "\n", version_number); + init_stored_settings(); #ifdef WIFI diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h index 102c0d80e..84fc9a97f 100644 --- a/Software/src/devboard/utils/logging.h +++ b/Software/src/devboard/utils/logging.h @@ -4,8 +4,6 @@ #include #include "Print.h" -extern const char* version_number; // The current software version, shown on webserver - class Logging : public Print { void add_timestamp(size_t size); @@ -13,12 +11,7 @@ class Logging : public Print { virtual size_t write(const uint8_t* buffer, size_t size); virtual size_t write(uint8_t) { return 0; } void printf(const char* fmt, ...); - Logging() { - printf( - "Battery emulator %s build "__DATE__ - " " __TIME__ "\n", - version_number); - } + Logging() {} }; extern Logging logging; From 54d96a63398d4198588410e05c1f9df80b0f2206 Mon Sep 17 00:00:00 2001 From: mvgalen Date: Sat, 4 Jan 2025 22:34:20 +0100 Subject: [PATCH 189/225] Fix code formatting. --- Software/Software.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 44016637e..be99d1ec8 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -98,8 +98,7 @@ void setup() { init_serial(); // We print this after setting up serial, such that is also printed to serial with DEBUG_VIA_USB set. - logging.printf("Battery emulator %s build " __DATE__ - " " __TIME__ "\n", version_number); + logging.printf("Battery emulator %s build " __DATE__ " " __TIME__ "\n", version_number); init_stored_settings(); From ae0506125f19e031d24d09d2de4a70434a002f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 4 Jan 2025 23:41:13 +0200 Subject: [PATCH 190/225] Move BYD startup messages to 10s block --- Software/src/inverter/BYD-CAN.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 477fbf2a6..1ac35f0b4 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -83,7 +83,7 @@ static int16_t inverter_temperature = 0; static uint16_t remaining_capacity_ah = 0; static uint16_t fully_charged_capacity_ah = 0; static long inverter_timestamp = 0; -static bool initialDataSent = 0; +static bool initialDataSent = false; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages @@ -198,11 +198,6 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { void transmit_can_inverter() { unsigned long currentMillis = millis(); - // Send initial CAN data once on bootup - if (!initialDataSent) { - send_intial_data(); - initialDataSent = 1; - } // Send 2s CAN Message if (currentMillis - previousMillis2s >= INTERVAL_2_S) { @@ -217,6 +212,12 @@ void transmit_can_inverter() { transmit_can_frame(&BYD_150, can_config.inverter); transmit_can_frame(&BYD_1D0, can_config.inverter); transmit_can_frame(&BYD_210, can_config.inverter); + + // Send initial CAN data once on bootup + if (!initialDataSent) { + send_intial_data(); + initialDataSent = true; + } } //Send 60s message if (currentMillis - previousMillis60s >= INTERVAL_60_S) { From b81e0f5647874651605c0610c5e15d10dcdcfa16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 5 Jan 2025 16:58:19 +0200 Subject: [PATCH 191/225] Change forced startup messages to 60 second interval --- Software/src/inverter/BYD-CAN.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 1ac35f0b4..b6250adcf 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -212,18 +212,18 @@ void transmit_can_inverter() { transmit_can_frame(&BYD_150, can_config.inverter); transmit_can_frame(&BYD_1D0, can_config.inverter); transmit_can_frame(&BYD_210, can_config.inverter); - - // Send initial CAN data once on bootup - if (!initialDataSent) { - send_intial_data(); - initialDataSent = true; - } } //Send 60s message if (currentMillis - previousMillis60s >= INTERVAL_60_S) { previousMillis60s = currentMillis; transmit_can_frame(&BYD_190, can_config.inverter); + + // Send initial CAN data once on bootup + if (!initialDataSent) { + send_intial_data(); + initialDataSent = true; + } } } From 6cb892b4bc6c0c7e4a1a34da4c3a2e24729d1643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 5 Jan 2025 23:49:25 +0300 Subject: [PATCH 192/225] Update ArduinoJson to v7.3.0 (#750) --- .../lib/bblanchon-ArduinoJson/ArduinoJson.h | 4360 ++++++++++------- 1 file changed, 2509 insertions(+), 1851 deletions(-) diff --git a/Software/src/lib/bblanchon-ArduinoJson/ArduinoJson.h b/Software/src/lib/bblanchon-ArduinoJson/ArduinoJson.h index 7ef4fa1a0..644d19c6c 100644 --- a/Software/src/lib/bblanchon-ArduinoJson/ArduinoJson.h +++ b/Software/src/lib/bblanchon-ArduinoJson/ArduinoJson.h @@ -53,9 +53,6 @@ # define ARDUINOJSON_ENABLE_STRING_VIEW 0 # endif #endif -#ifndef ARDUINOJSON_USE_DOUBLE -# define ARDUINOJSON_USE_DOUBLE 1 -#endif #ifndef ARDUINOJSON_SIZEOF_POINTER # if defined(__SIZEOF_POINTER__) # define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__ @@ -65,6 +62,13 @@ # define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise # endif #endif +#ifndef ARDUINOJSON_USE_DOUBLE +# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems +# define ARDUINOJSON_USE_DOUBLE 1 +# else +# define ARDUINOJSON_USE_DOUBLE 0 +# endif +#endif #ifndef ARDUINOJSON_USE_LONG_LONG # if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems # define ARDUINOJSON_USE_LONG_LONG 1 @@ -77,20 +81,20 @@ #endif #ifndef ARDUINOJSON_SLOT_ID_SIZE # if ARDUINOJSON_SIZEOF_POINTER <= 2 -# define ARDUINOJSON_SLOT_ID_SIZE 1 // up to 255 slots +# define ARDUINOJSON_SLOT_ID_SIZE 1 # elif ARDUINOJSON_SIZEOF_POINTER == 4 -# define ARDUINOJSON_SLOT_ID_SIZE 2 // up to 65535 slots +# define ARDUINOJSON_SLOT_ID_SIZE 2 # else -# define ARDUINOJSON_SLOT_ID_SIZE 4 // up to 4294967295 slots +# define ARDUINOJSON_SLOT_ID_SIZE 4 # endif #endif #ifndef ARDUINOJSON_POOL_CAPACITY -# if ARDUINOJSON_SIZEOF_POINTER <= 2 -# define ARDUINOJSON_POOL_CAPACITY 16 // 128 bytes -# elif ARDUINOJSON_SIZEOF_POINTER == 4 -# define ARDUINOJSON_POOL_CAPACITY 64 // 1024 bytes +# if ARDUINOJSON_SLOT_ID_SIZE == 1 +# define ARDUINOJSON_POOL_CAPACITY 16 // 96 bytes +# elif ARDUINOJSON_SLOT_ID_SIZE == 2 +# define ARDUINOJSON_POOL_CAPACITY 128 // 1024 bytes # else -# define ARDUINOJSON_POOL_CAPACITY 128 // 3072 bytes +# define ARDUINOJSON_POOL_CAPACITY 256 // 4096 bytes # endif #endif #ifndef ARDUINOJSON_INITIAL_POOL_COUNT @@ -189,6 +193,11 @@ # define ARDUINOJSON_DEBUG 0 # endif #endif +#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE +# define ARDUINOJSON_USE_EXTENSIONS 1 +#else +# define ARDUINOJSON_USE_EXTENSIONS 0 +#endif #if defined(nullptr) # error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr #endif @@ -206,8 +215,12 @@ #endif #define ARDUINOJSON_CONCAT_(A, B) A##B #define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B) +#define ARDUINOJSON_CONCAT3(A, B, C) \ + ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), C) #define ARDUINOJSON_CONCAT4(A, B, C, D) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) + ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT3(A, B, C), D) +#define ARDUINOJSON_CONCAT5(A, B, C, D, E) \ + ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), E) #define ARDUINOJSON_BIN2ALPHA_0000() A #define ARDUINOJSON_BIN2ALPHA_0001() B #define ARDUINOJSON_BIN2ALPHA_0010() C @@ -226,22 +239,22 @@ #define ARDUINOJSON_BIN2ALPHA_1111() P #define ARDUINOJSON_BIN2ALPHA_(A, B, C, D) ARDUINOJSON_BIN2ALPHA_##A##B##C##D() #define ARDUINOJSON_BIN2ALPHA(A, B, C, D) ARDUINOJSON_BIN2ALPHA_(A, B, C, D) -#define ARDUINOJSON_VERSION "7.0.4" +#define ARDUINOJSON_VERSION "7.3.0" #define ARDUINOJSON_VERSION_MAJOR 7 -#define ARDUINOJSON_VERSION_MINOR 0 -#define ARDUINOJSON_VERSION_REVISION 4 -#define ARDUINOJSON_VERSION_MACRO V704 +#define ARDUINOJSON_VERSION_MINOR 3 +#define ARDUINOJSON_VERSION_REVISION 0 +#define ARDUINOJSON_VERSION_MACRO V730 #ifndef ARDUINOJSON_VERSION_NAMESPACE -# define ARDUINOJSON_VERSION_NAMESPACE \ - ARDUINOJSON_CONCAT4(ARDUINOJSON_VERSION_MACRO, \ - ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_PROGMEM, \ - ARDUINOJSON_USE_LONG_LONG, \ - ARDUINOJSON_USE_DOUBLE, 1), \ - ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_NAN, \ - ARDUINOJSON_ENABLE_INFINITY, \ - ARDUINOJSON_ENABLE_COMMENTS, \ - ARDUINOJSON_DECODE_UNICODE), \ - ARDUINOJSON_SLOT_ID_SIZE) +# define ARDUINOJSON_VERSION_NAMESPACE \ + ARDUINOJSON_CONCAT5( \ + ARDUINOJSON_VERSION_MACRO, \ + ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_PROGMEM, \ + ARDUINOJSON_USE_LONG_LONG, \ + ARDUINOJSON_USE_DOUBLE, 1), \ + ARDUINOJSON_BIN2ALPHA( \ + ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ + ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE), \ + ARDUINOJSON_SLOT_ID_SIZE, ARDUINOJSON_STRING_LENGTH_SIZE) #endif #define ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE \ namespace ArduinoJson { \ @@ -264,8 +277,6 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template class InvalidConversion; // Error here? See https://arduinojson.org/v7/invalid-conversion/ -template -struct ConverterNeedsWriteableRef; ARDUINOJSON_END_PRIVATE_NAMESPACE #include #include @@ -309,39 +320,155 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE #endif ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template -struct uint_t; +struct uint_; template <> -struct uint_t<8> { - typedef uint8_t type; +struct uint_<8> { + using type = uint8_t; }; template <> -struct uint_t<16> { - typedef uint16_t type; +struct uint_<16> { + using type = uint16_t; }; template <> -struct uint_t<32> { - typedef uint32_t type; +struct uint_<32> { + using type = uint32_t; +}; +template +using uint_t = typename uint_::type; +using SlotId = uint_t; +using SlotCount = SlotId; +const SlotId NULL_SLOT = SlotId(-1); +template +class Slot { + public: + Slot() : ptr_(nullptr), id_(NULL_SLOT) {} + Slot(T* p, SlotId id) : ptr_(p), id_(id) { + ARDUINOJSON_ASSERT((p == nullptr) == (id == NULL_SLOT)); + } + explicit operator bool() const { + return ptr_ != nullptr; + } + SlotId id() const { + return id_; + } + T* ptr() const { + return ptr_; + } + T* operator->() const { + ARDUINOJSON_ASSERT(ptr_ != nullptr); + return ptr_; + } + private: + T* ptr_; + SlotId id_; +}; +template +class MemoryPool { + public: + void create(SlotCount cap, Allocator* allocator) { + ARDUINOJSON_ASSERT(cap > 0); + slots_ = reinterpret_cast(allocator->allocate(slotsToBytes(cap))); + capacity_ = slots_ ? cap : 0; + usage_ = 0; + } + void destroy(Allocator* allocator) { + if (slots_) + allocator->deallocate(slots_); + slots_ = nullptr; + capacity_ = 0; + usage_ = 0; + } + Slot allocSlot() { + if (!slots_) + return {}; + if (usage_ >= capacity_) + return {}; + auto index = usage_++; + return {slots_ + index, SlotId(index)}; + } + T* getSlot(SlotId id) const { + ARDUINOJSON_ASSERT(id < usage_); + return slots_ + id; + } + void clear() { + usage_ = 0; + } + void shrinkToFit(Allocator* allocator) { + auto newSlots = reinterpret_cast( + allocator->reallocate(slots_, slotsToBytes(usage_))); + if (newSlots) { + slots_ = newSlots; + capacity_ = usage_; + } + } + SlotCount usage() const { + return usage_; + } + static SlotCount bytesToSlots(size_t n) { + return static_cast(n / sizeof(T)); + } + static size_t slotsToBytes(SlotCount n) { + return n * sizeof(T); + } + private: + SlotCount capacity_; + SlotCount usage_; + T* slots_; }; template struct conditional { - typedef TrueType type; + using type = TrueType; }; template struct conditional { - typedef FalseType type; + using type = FalseType; +}; +template +using conditional_t = + typename conditional::type; +template +struct decay { + using type = T; }; +template +struct decay : decay {}; +template +struct decay : decay {}; +template +struct decay : decay {}; +template +struct decay : decay {}; +template +using decay_t = typename decay::type; template struct enable_if {}; template struct enable_if { - typedef T type; + using type = T; +}; +template +using enable_if_t = typename enable_if::type; +template +struct function_traits; +template +struct function_traits { + using return_type = ReturnType; + using arg1_type = Arg1; +}; +template +struct function_traits { + using return_type = ReturnType; + using arg1_type = Arg1; + using arg2_type = Arg2; }; template struct integral_constant { static const T value = v; }; -typedef integral_constant true_type; -typedef integral_constant false_type; +template +using bool_constant = integral_constant; +using true_type = bool_constant; +using false_type = bool_constant; template struct is_array : false_type {}; template @@ -350,12 +477,14 @@ template struct is_array : true_type {}; template struct remove_reference { - typedef T type; + using type = T; }; template struct remove_reference { - typedef T type; + using type = T; }; +template +using remove_reference_t = typename remove_reference::type; template class is_base_of { protected: // <- to avoid GCC's "all member functions in class are private" @@ -363,8 +492,8 @@ class is_base_of { static char probe(...); public: static const bool value = - sizeof(probe(reinterpret_cast::type*>( - 0))) == sizeof(int); + sizeof(probe(reinterpret_cast*>(0))) == + sizeof(int); }; template T&& declval(); @@ -396,7 +525,7 @@ struct is_convertible { protected: // <- to avoid GCC's "all member functions in class are private" static int probe(To); static char probe(...); - static From& from_; + static const From& from_; public: static const bool value = sizeof(probe(from_)) == sizeof(int); }; @@ -414,43 +543,44 @@ template struct is_same : true_type {}; template struct remove_cv { - typedef T type; + using type = T; }; template struct remove_cv { - typedef T type; + using type = T; }; template struct remove_cv { - typedef T type; + using type = T; }; template struct remove_cv { - typedef T type; + using type = T; }; +template +using remove_cv_t = typename remove_cv::type; template struct is_floating_point - : integral_constant< - bool, // - is_same::type>::value || - is_same::type>::value> {}; + : integral_constant>::value || + is_same>::value> {}; template struct is_integral : integral_constant::type, signed char>::value || - is_same::type, unsigned char>::value || - is_same::type, signed short>::value || - is_same::type, unsigned short>::value || - is_same::type, signed int>::value || - is_same::type, unsigned int>::value || - is_same::type, signed long>::value || - is_same::type, unsigned long>::value || - is_same::type, signed long long>::value || - is_same::type, unsigned long long>::value || - is_same::type, char>::value || - is_same::type, bool>::value> {}; + is_same, signed char>::value || + is_same, unsigned char>::value || + is_same, signed short>::value || + is_same, unsigned short>::value || + is_same, signed int>::value || + is_same, unsigned int>::value || + is_same, signed long>::value || + is_same, unsigned long>::value || + is_same, signed long long>::value || + is_same, unsigned long long>::value || + is_same, char>::value || + is_same, bool>::value> {}; template struct is_enum { - static const bool value = is_convertible::value && + static const bool value = is_convertible::value && !is_class::value && !is_integral::value && !is_floating_point::value; }; @@ -460,25 +590,25 @@ template struct is_pointer : true_type {}; template struct is_signed : integral_constant::type, char>::value || - is_same::type, signed char>::value || - is_same::type, signed short>::value || - is_same::type, signed int>::value || - is_same::type, signed long>::value || - is_same::type, signed long long>::value || - is_same::type, float>::value || - is_same::type, double>::value> {}; + is_same, char>::value || + is_same, signed char>::value || + is_same, signed short>::value || + is_same, signed int>::value || + is_same, signed long>::value || + is_same, signed long long>::value || + is_same, float>::value || + is_same, double>::value> {}; template struct is_unsigned : integral_constant::type, unsigned char>::value || - is_same::type, unsigned short>::value || - is_same::type, unsigned int>::value || - is_same::type, unsigned long>::value || - is_same::type, unsigned long long>::value || - is_same::type, bool>::value> {}; + is_same, unsigned char>::value || + is_same, unsigned short>::value || + is_same, unsigned int>::value || + is_same, unsigned long>::value || + is_same, unsigned long long>::value || + is_same, bool>::value> {}; template struct type_identity { - typedef T type; + using type = T; }; template struct make_unsigned; @@ -504,17 +634,204 @@ template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; -template -struct make_void { - typedef void type; -}; +template +using make_unsigned_t = typename make_unsigned::type; template struct remove_const { - typedef T type; + using type = T; }; template struct remove_const { - typedef T type; + using type = T; +}; +template +using remove_const_t = typename remove_const::type; +template +struct make_void { + using type = void; +}; +template +using void_t = typename make_void::type; +using nullptr_t = decltype(nullptr); +template +T&& forward(remove_reference_t& t) noexcept { + return static_cast(t); +} +template +remove_reference_t&& move(T&& t) { + return static_cast&&>(t); +} +template +void swap_(T& a, T& b) { + T tmp = move(a); + a = move(b); + b = move(tmp); +} +ARDUINOJSON_END_PRIVATE_NAMESPACE +#include +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE +using PoolCount = SlotId; +template +class MemoryPoolList { + struct FreeSlot { + SlotId next; + }; + static_assert(sizeof(FreeSlot) <= sizeof(T), "T is too small"); + public: + using Pool = MemoryPool; + MemoryPoolList() = default; + ~MemoryPoolList() { + ARDUINOJSON_ASSERT(count_ == 0); + } + friend void swap(MemoryPoolList& a, MemoryPoolList& b) { + bool aUsedPreallocated = a.pools_ == a.preallocatedPools_; + bool bUsedPreallocated = b.pools_ == b.preallocatedPools_; + if (aUsedPreallocated && bUsedPreallocated) { + for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++) + swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]); + } else if (bUsedPreallocated) { + for (PoolCount i = 0; i < b.count_; i++) + a.preallocatedPools_[i] = b.preallocatedPools_[i]; + b.pools_ = a.pools_; + a.pools_ = a.preallocatedPools_; + } else if (aUsedPreallocated) { + for (PoolCount i = 0; i < a.count_; i++) + b.preallocatedPools_[i] = a.preallocatedPools_[i]; + a.pools_ = b.pools_; + b.pools_ = b.preallocatedPools_; + } else { + swap_(a.pools_, b.pools_); + } + swap_(a.count_, b.count_); + swap_(a.capacity_, b.capacity_); + swap_(a.freeList_, b.freeList_); + } + MemoryPoolList& operator=(MemoryPoolList&& src) { + ARDUINOJSON_ASSERT(count_ == 0); + if (src.pools_ == src.preallocatedPools_) { + memcpy(preallocatedPools_, src.preallocatedPools_, + sizeof(preallocatedPools_)); + pools_ = preallocatedPools_; + } else { + pools_ = src.pools_; + src.pools_ = nullptr; + } + count_ = src.count_; + capacity_ = src.capacity_; + src.count_ = 0; + src.capacity_ = 0; + return *this; + } + Slot allocSlot(Allocator* allocator) { + if (freeList_ != NULL_SLOT) { + return allocFromFreeList(); + } + if (count_) { + auto slot = allocFromLastPool(); + if (slot) + return slot; + } + auto pool = addPool(allocator); + if (!pool) + return {}; + return allocFromLastPool(); + } + void freeSlot(Slot slot) { + reinterpret_cast(slot.ptr())->next = freeList_; + freeList_ = slot.id(); + } + T* getSlot(SlotId id) const { + if (id == NULL_SLOT) + return nullptr; + auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY); + auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY); + ARDUINOJSON_ASSERT(poolIndex < count_); + return pools_[poolIndex].getSlot(indexInPool); + } + void clear(Allocator* allocator) { + for (PoolCount i = 0; i < count_; i++) + pools_[i].destroy(allocator); + count_ = 0; + freeList_ = NULL_SLOT; + if (pools_ != preallocatedPools_) { + allocator->deallocate(pools_); + pools_ = preallocatedPools_; + capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT; + } + } + SlotCount usage() const { + SlotCount total = 0; + for (PoolCount i = 0; i < count_; i++) + total = SlotCount(total + pools_[i].usage()); + return total; + } + size_t size() const { + return Pool::slotsToBytes(usage()); + } + void shrinkToFit(Allocator* allocator) { + if (count_ > 0) + pools_[count_ - 1].shrinkToFit(allocator); + if (pools_ != preallocatedPools_ && count_ != capacity_) { + pools_ = static_cast( + allocator->reallocate(pools_, count_ * sizeof(Pool))); + ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail + capacity_ = count_; + } + } + private: + Slot allocFromFreeList() { + ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT); + auto id = freeList_; + auto slot = getSlot(freeList_); + freeList_ = reinterpret_cast(slot)->next; + return {slot, id}; + } + Slot allocFromLastPool() { + ARDUINOJSON_ASSERT(count_ > 0); + auto poolIndex = SlotId(count_ - 1); + auto slot = pools_[poolIndex].allocSlot(); + if (!slot) + return {}; + return {slot.ptr(), + SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())}; + } + Pool* addPool(Allocator* allocator) { + if (count_ == capacity_ && !increaseCapacity(allocator)) + return nullptr; + auto pool = &pools_[count_++]; + SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY; + if (count_ == maxPools) // last pool is smaller because of NULL_SLOT + poolCapacity--; + pool->create(poolCapacity, allocator); + return pool; + } + bool increaseCapacity(Allocator* allocator) { + if (capacity_ == maxPools) + return false; + void* newPools; + auto newCapacity = PoolCount(capacity_ * 2); + if (pools_ == preallocatedPools_) { + newPools = allocator->allocate(newCapacity * sizeof(Pool)); + if (!newPools) + return false; + memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_)); + } else { + newPools = allocator->reallocate(pools_, newCapacity * sizeof(Pool)); + if (!newPools) + return false; + } + pools_ = static_cast(newPools); + capacity_ = newCapacity; + return true; + } + Pool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT]; + Pool* pools_ = preallocatedPools_; + PoolCount count_ = 0; + PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT; + SlotId freeList_ = NULL_SLOT; + public: + static const PoolCount maxPools = + PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1); }; ARDUINOJSON_END_PRIVATE_NAMESPACE #ifdef _MSC_VER @@ -525,7 +842,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template struct numeric_limits; template -struct numeric_limits::value>::type> { +struct numeric_limits::value>> { static constexpr T lowest() { return 0; } @@ -535,7 +852,7 @@ struct numeric_limits::value>::type> { }; template struct numeric_limits< - T, typename enable_if::value && is_signed::value>::type> { + T, enable_if_t::value && is_signed::value>> { static constexpr T lowest() { return T(T(1) << (sizeof(T) * 8 - 1)); } @@ -549,8 +866,8 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE #endif ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE struct StringNode { - using references_type = uint_t::type; - using length_type = uint_t::type; + using references_type = uint_t; + using length_type = uint_t; struct StringNode* next; references_type references; length_type length; @@ -562,8 +879,10 @@ struct StringNode { static StringNode* create(size_t length, Allocator* allocator) { if (length > maxLength) return nullptr; - auto node = reinterpret_cast( - allocator->allocate(sizeForLength(length))); + auto size = sizeForLength(length); + if (size < length) // integer overflow + return nullptr; // (not testable on 64-bit) + auto node = reinterpret_cast(allocator->allocate(size)); if (node) { node->length = length_type(length); node->references = 1; @@ -592,23 +911,7 @@ struct StringNode { constexpr size_t sizeofString(size_t n) { return StringNode::sizeForLength(n); } -using nullptr_t = decltype(nullptr); -template -T&& forward(typename remove_reference::type& t) noexcept { - return static_cast(t); -} -template -typename remove_reference::type&& move(T&& t) { - return static_cast::type&&>(t); -} -template -void swap_(T& a, T& b) { - T tmp = move(a); - a = move(b); - b = move(tmp); -} ARDUINOJSON_END_PRIVATE_NAMESPACE -#include #ifdef _MSC_VER // Visual Studio # define FORCE_INLINE // __forceinline causes C4714 when returning std::string # ifndef ARDUINOJSON_DEPRECATED @@ -639,35 +942,52 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE # define ARDUINOJSON_NO_SANITIZE(check) #endif ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE +template +struct IsStringLiteral : false_type {}; +template +struct IsStringLiteral : true_type {}; template struct StringAdapter; template struct SizedStringAdapter; template -typename StringAdapter::AdaptedString adaptString(const TString& s) { - return StringAdapter::adapt(s); +using StringAdapterFor = + StringAdapter::value, TString, + remove_cv_t>>>; +template +using AdaptedString = typename StringAdapterFor::AdaptedString; +template +AdaptedString adaptString(TString&& s) { + return StringAdapterFor::adapt(detail::forward(s)); } -template -typename StringAdapter::AdaptedString adaptString(TChar* p) { +template ::value, int> = 0> +AdaptedString adaptString(TChar* p) { return StringAdapter::adapt(p); } template -typename SizedStringAdapter::AdaptedString adaptString(TChar* p, - size_t n) { +AdaptedString adaptString(TChar* p, size_t n) { return SizedStringAdapter::adapt(p, n); } template struct IsChar : integral_constant::value && sizeof(T) == 1> {}; -class ZeroTerminatedRamString { +class RamString { public: - static const size_t typeSortKey = 3; - ZeroTerminatedRamString(const char* str) : str_(str) {} + static const size_t typeSortKey = 2; +#if ARDUINOJSON_SIZEOF_POINTER <= 2 + static constexpr size_t sizeMask = size_t(-1) >> 1; +#else + static constexpr size_t sizeMask = size_t(-1); +#endif + RamString(const char* str, size_t sz, bool isStatic = false) + : str_(str), size_(sz & sizeMask), static_(isStatic) { + ARDUINOJSON_ASSERT(size_ == sz); + } bool isNull() const { return !str_; } - FORCE_INLINE size_t size() const { - return str_ ? ::strlen(str_) : 0; + size_t size() const { + return size_; } char operator[](size_t i) const { ARDUINOJSON_ASSERT(str_ != 0); @@ -677,183 +997,71 @@ class ZeroTerminatedRamString { const char* data() const { return str_; } - friend int stringCompare(ZeroTerminatedRamString a, - ZeroTerminatedRamString b) { - ARDUINOJSON_ASSERT(!a.isNull()); - ARDUINOJSON_ASSERT(!b.isNull()); - return ::strcmp(a.str_, b.str_); - } - friend bool stringEquals(ZeroTerminatedRamString a, - ZeroTerminatedRamString b) { - return stringCompare(a, b) == 0; - } - bool isLinked() const { - return false; + bool isStatic() const { + return static_; } protected: const char* str_; +#if ARDUINOJSON_SIZEOF_POINTER <= 2 + size_t size_ : sizeof(size_t) * 8 - 1; + bool static_ : 1; +#else + size_t size_; + bool static_; +#endif }; template -struct StringAdapter::value>::type> { - typedef ZeroTerminatedRamString AdaptedString; +struct StringAdapter::value>> { + using AdaptedString = RamString; static AdaptedString adapt(const TChar* p) { - return AdaptedString(reinterpret_cast(p)); + auto str = reinterpret_cast(p); + return AdaptedString(str, str ? ::strlen(str) : 0); } }; -template -struct StringAdapter::value>::type> { - typedef ZeroTerminatedRamString AdaptedString; - static AdaptedString adapt(const TChar* p) { - return AdaptedString(reinterpret_cast(p)); - } -}; -class StaticStringAdapter : public ZeroTerminatedRamString { - public: - StaticStringAdapter(const char* str) : ZeroTerminatedRamString(str) {} - bool isLinked() const { - return true; - } -}; -template <> -struct StringAdapter { - typedef StaticStringAdapter AdaptedString; - static AdaptedString adapt(const char* p) { - return AdaptedString(p); +template +struct StringAdapter { + using AdaptedString = RamString; + static AdaptedString adapt(const char (&p)[N]) { + return RamString(p, N - 1, true); } }; -class SizedRamString { - public: - static const size_t typeSortKey = 2; - SizedRamString(const char* str, size_t sz) : str_(str), size_(sz) {} - bool isNull() const { - return !str_; - } - size_t size() const { - return size_; - } - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(str_ != 0); - ARDUINOJSON_ASSERT(i <= size()); - return str_[i]; - } - const char* data() const { - return str_; - } - bool isLinked() const { - return false; +template +struct StringAdapter::value>> { + using AdaptedString = RamString; + static AdaptedString adapt(const TChar* p) { + auto str = reinterpret_cast(p); + return AdaptedString(str, str ? ::strlen(str) : 0); } - protected: - const char* str_; - size_t size_; }; template -struct SizedStringAdapter::value>::type> { - typedef SizedRamString AdaptedString; +struct SizedStringAdapter::value>> { + using AdaptedString = RamString; static AdaptedString adapt(const TChar* p, size_t n) { return AdaptedString(reinterpret_cast(p), n); } }; -ARDUINOJSON_END_PRIVATE_NAMESPACE -#if ARDUINOJSON_ENABLE_STD_STREAM -#include -#endif -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class JsonString { - public: - enum Ownership { Copied, Linked }; - JsonString() : data_(0), size_(0), ownership_(Linked) {} - JsonString(const char* data, Ownership ownership = Linked) - : data_(data), size_(data ? ::strlen(data) : 0), ownership_(ownership) {} - JsonString(const char* data, size_t sz, Ownership ownership = Linked) - : data_(data), size_(sz), ownership_(ownership) {} - const char* c_str() const { - return data_; - } - bool isNull() const { - return !data_; - } - bool isLinked() const { - return ownership_ == Linked; - } - size_t size() const { - return size_; - } - explicit operator bool() const { - return data_ != 0; - } - friend bool operator==(JsonString lhs, JsonString rhs) { - if (lhs.size_ != rhs.size_) - return false; - if (lhs.data_ == rhs.data_) - return true; - if (!lhs.data_) - return false; - if (!rhs.data_) - return false; - return memcmp(lhs.data_, rhs.data_, lhs.size_) == 0; - } - friend bool operator!=(JsonString lhs, JsonString rhs) { - return !(lhs == rhs); - } -#if ARDUINOJSON_ENABLE_STD_STREAM - friend std::ostream& operator<<(std::ostream& lhs, const JsonString& rhs) { - lhs.write(rhs.c_str(), static_cast(rhs.size())); - return lhs; - } -#endif - private: - const char* data_; - size_t size_; - Ownership ownership_; -}; -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class JsonStringAdapter : public SizedRamString { - public: - JsonStringAdapter(const JsonString& s) - : SizedRamString(s.c_str(), s.size()), linked_(s.isLinked()) {} - bool isLinked() const { - return linked_; - } - private: - bool linked_; -}; -template <> -struct StringAdapter { - typedef JsonStringAdapter AdaptedString; - static AdaptedString adapt(const JsonString& s) { - return AdaptedString(s); - } -}; namespace string_traits_impl { template struct has_cstr : false_type {}; template -struct has_cstr().c_str()), - const char*>::value>::type> - : true_type {}; +struct has_cstr().c_str()), + const char*>::value>> : true_type {}; template struct has_data : false_type {}; template -struct has_data().data()), - const char*>::value>::type> - : true_type {}; +struct has_data().data()), + const char*>::value>> : true_type {}; template struct has_length : false_type {}; template struct has_length< - T, typename enable_if< - is_same().length()), size_t>::value>::type> + T, enable_if_t().length())>::value>> : true_type {}; template struct has_size : false_type {}; template struct has_size< - T, typename enable_if< - is_same().size()), size_t>::value>::type> + T, enable_if_t().size()), size_t>::value>> : true_type {}; } // namespace string_traits_impl template @@ -868,32 +1076,29 @@ struct string_traits { template struct StringAdapter< T, - typename enable_if< - (string_traits::has_cstr || string_traits::has_data) && - (string_traits::has_length || string_traits::has_size)>::type> { - typedef SizedRamString AdaptedString; + enable_if_t<(string_traits::has_cstr || string_traits::has_data) && + (string_traits::has_length || string_traits::has_size)>> { + using AdaptedString = RamString; static AdaptedString adapt(const T& s) { return AdaptedString(get_data(s), get_size(s)); } private: template - static typename enable_if::has_size, size_t>::type get_size( - const U& s) { + static enable_if_t::has_size, size_t> get_size(const U& s) { return s.size(); } template - static typename enable_if::has_size, size_t>::type get_size( - const U& s) { + static enable_if_t::has_size, size_t> get_size(const U& s) { return s.length(); } template - static typename enable_if::has_data, const char*>::type - get_data(const U& s) { + static enable_if_t::has_data, const char*> get_data( + const U& s) { return s.data(); } template - static typename enable_if::has_data, const char*>::type - get_data(const U& s) { + static enable_if_t::has_data, const char*> get_data( + const U& s) { return s.c_str(); } }; @@ -1038,7 +1243,7 @@ class FlashString { size_t size() const { return size_; } - friend bool stringEquals(FlashString a, SizedRamString b) { + friend bool stringEquals(FlashString a, RamString b) { ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey); ARDUINOJSON_ASSERT(!a.isNull()); ARDUINOJSON_ASSERT(!b.isNull()); @@ -1046,7 +1251,7 @@ class FlashString { return false; return ::memcmp_P(b.data(), a.str_, a.size_) == 0; } - friend int stringCompare(FlashString a, SizedRamString b) { + friend int stringCompare(FlashString a, RamString b) { ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey); ARDUINOJSON_ASSERT(!a.isNull()); ARDUINOJSON_ASSERT(!b.isNull()); @@ -1064,7 +1269,7 @@ class FlashString { ARDUINOJSON_ASSERT(s.size() <= n); ::memcpy_P(p, s.str_, n); } - bool isLinked() const { + bool isStatic() const { return false; } private: @@ -1073,14 +1278,14 @@ class FlashString { }; template <> struct StringAdapter { - typedef FlashString AdaptedString; + using AdaptedString = FlashString; static AdaptedString adapt(const __FlashStringHelper* s) { return AdaptedString(s, s ? strlen_P(reinterpret_cast(s)) : 0); } }; template <> struct SizedStringAdapter { - typedef FlashString AdaptedString; + using AdaptedString = FlashString; static AdaptedString adapt(const __FlashStringHelper* s, size_t n) { return AdaptedString(s, n); } @@ -1089,8 +1294,7 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE #endif ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template -typename enable_if::type +enable_if_t stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { ARDUINOJSON_ASSERT(!s1.isNull()); ARDUINOJSON_ASSERT(!s2.isNull()); @@ -1108,14 +1312,12 @@ stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { return 0; } template -typename enable_if< - (TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), int>::type +enable_if_t<(TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), int> stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { return -stringCompare(s2, s1); } template -typename enable_if::type +enable_if_t stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { ARDUINOJSON_ASSERT(!s1.isNull()); ARDUINOJSON_ASSERT(!s2.isNull()); @@ -1130,8 +1332,7 @@ stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { return true; } template -typename enable_if< - (TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), bool>::type +enable_if_t<(TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), bool> stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { return stringEquals(s2, s1); } @@ -1142,8 +1343,6 @@ static void stringGetChars(TAdaptedString s, char* p, size_t n) { p[i] = s[i]; } } -class VariantSlot; -class VariantPool; class StringPool { public: StringPool() = default; @@ -1217,285 +1416,6 @@ class StringPool { private: StringNode* strings_ = nullptr; }; -class VariantSlot; -using SlotId = uint_t::type; -using SlotCount = SlotId; -const SlotId NULL_SLOT = SlotId(-1); -class SlotWithId { - public: - SlotWithId() : slot_(nullptr), id_(NULL_SLOT) {} - SlotWithId(VariantSlot* slot, SlotId id) : slot_(slot), id_(id) { - ARDUINOJSON_ASSERT((slot == nullptr) == (id == NULL_SLOT)); - } - SlotId id() const { - return id_; - } - operator VariantSlot*() { - return slot_; - } - VariantSlot* operator->() { - ARDUINOJSON_ASSERT(slot_ != nullptr); - return slot_; - } - private: - VariantSlot* slot_; - SlotId id_; -}; -class VariantPool { - public: - void create(SlotCount cap, Allocator* allocator); - void destroy(Allocator* allocator); - SlotWithId allocSlot(); - VariantSlot* getSlot(SlotId id) const; - void clear(); - void shrinkToFit(Allocator*); - SlotCount usage() const; - static SlotCount bytesToSlots(size_t); - static size_t slotsToBytes(SlotCount); - private: - SlotCount capacity_; - SlotCount usage_; - VariantSlot* slots_; -}; -using PoolCount = SlotId; -class VariantPoolList { - public: - VariantPoolList() = default; - ~VariantPoolList() { - ARDUINOJSON_ASSERT(count_ == 0); - } - friend void swap(VariantPoolList& a, VariantPoolList& b) { - bool aUsedPreallocated = a.pools_ == a.preallocatedPools_; - bool bUsedPreallocated = b.pools_ == b.preallocatedPools_; - if (aUsedPreallocated && bUsedPreallocated) { - for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++) - swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]); - } else if (bUsedPreallocated) { - for (PoolCount i = 0; i < b.count_; i++) - a.preallocatedPools_[i] = b.preallocatedPools_[i]; - b.pools_ = a.pools_; - a.pools_ = a.preallocatedPools_; - } else if (aUsedPreallocated) { - for (PoolCount i = 0; i < a.count_; i++) - b.preallocatedPools_[i] = a.preallocatedPools_[i]; - a.pools_ = b.pools_; - b.pools_ = b.preallocatedPools_; - } else { - swap_(a.pools_, b.pools_); - } - swap_(a.count_, b.count_); - swap_(a.capacity_, b.capacity_); - swap_(a.freeList_, b.freeList_); - } - VariantPoolList& operator=(VariantPoolList&& src) { - ARDUINOJSON_ASSERT(count_ == 0); - if (src.pools_ == src.preallocatedPools_) { - memcpy(preallocatedPools_, src.preallocatedPools_, - sizeof(preallocatedPools_)); - pools_ = preallocatedPools_; - } else { - pools_ = src.pools_; - src.pools_ = nullptr; - } - count_ = src.count_; - capacity_ = src.capacity_; - src.count_ = 0; - src.capacity_ = 0; - return *this; - } - SlotWithId allocSlot(Allocator* allocator) { - if (freeList_ != NULL_SLOT) { - return allocFromFreeList(); - } - if (count_) { - auto slot = allocFromLastPool(); - if (slot) - return slot; - } - auto pool = addPool(allocator); - if (!pool) - return {}; - return allocFromLastPool(); - } - void freeSlot(SlotWithId slot); - VariantSlot* getSlot(SlotId id) const { - if (id == NULL_SLOT) - return nullptr; - auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY); - auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY); - ARDUINOJSON_ASSERT(poolIndex < count_); - return pools_[poolIndex].getSlot(indexInPool); - } - void clear(Allocator* allocator) { - for (PoolCount i = 0; i < count_; i++) - pools_[i].destroy(allocator); - count_ = 0; - freeList_ = NULL_SLOT; - if (pools_ != preallocatedPools_) { - allocator->deallocate(pools_); - pools_ = preallocatedPools_; - capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT; - } - } - SlotCount usage() const { - SlotCount total = 0; - for (PoolCount i = 0; i < count_; i++) - total = SlotCount(total + pools_[i].usage()); - return total; - } - void shrinkToFit(Allocator* allocator) { - if (count_ > 0) - pools_[count_ - 1].shrinkToFit(allocator); - if (pools_ != preallocatedPools_ && count_ != capacity_) { - pools_ = static_cast( - allocator->reallocate(pools_, count_ * sizeof(VariantPool))); - ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail - capacity_ = count_; - } - } - private: - SlotWithId allocFromFreeList(); - SlotWithId allocFromLastPool() { - ARDUINOJSON_ASSERT(count_ > 0); - auto poolIndex = SlotId(count_ - 1); - auto slot = pools_[poolIndex].allocSlot(); - if (!slot) - return {}; - return {slot, SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())}; - } - VariantPool* addPool(Allocator* allocator) { - if (count_ == capacity_ && !increaseCapacity(allocator)) - return nullptr; - auto pool = &pools_[count_++]; - SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY; - if (count_ == maxPools) // last pool is smaller because of NULL_SLOT - poolCapacity--; - pool->create(poolCapacity, allocator); - return pool; - } - bool increaseCapacity(Allocator* allocator) { - if (capacity_ == maxPools) - return false; - void* newPools; - auto newCapacity = PoolCount(capacity_ * 2); - if (pools_ == preallocatedPools_) { - newPools = allocator->allocate(newCapacity * sizeof(VariantPool)); - if (!newPools) - return false; - memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_)); - } else { - newPools = - allocator->reallocate(pools_, newCapacity * sizeof(VariantPool)); - if (!newPools) - return false; - } - pools_ = static_cast(newPools); - capacity_ = newCapacity; - return true; - } - VariantPool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT]; - VariantPool* pools_ = preallocatedPools_; - PoolCount count_ = 0; - PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT; - SlotId freeList_ = NULL_SLOT; - public: - static const PoolCount maxPools = - PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1); -}; -class VariantSlot; -class VariantPool; -class ResourceManager { - public: - ResourceManager(Allocator* allocator = DefaultAllocator::instance()) - : allocator_(allocator), overflowed_(false) {} - ~ResourceManager() { - stringPool_.clear(allocator_); - variantPools_.clear(allocator_); - } - ResourceManager(const ResourceManager&) = delete; - ResourceManager& operator=(const ResourceManager& src) = delete; - friend void swap(ResourceManager& a, ResourceManager& b) { - swap(a.stringPool_, b.stringPool_); - swap(a.variantPools_, b.variantPools_); - swap_(a.allocator_, b.allocator_); - swap_(a.overflowed_, b.overflowed_); - } - Allocator* allocator() const { - return allocator_; - } - size_t size() const { - return VariantPool::slotsToBytes(variantPools_.usage()) + - stringPool_.size(); - } - bool overflowed() const { - return overflowed_; - } - SlotWithId allocSlot() { - auto p = variantPools_.allocSlot(allocator_); - if (!p) - overflowed_ = true; - return p; - } - void freeSlot(SlotWithId id) { - variantPools_.freeSlot(id); - } - VariantSlot* getSlot(SlotId id) const { - return variantPools_.getSlot(id); - } - template - StringNode* saveString(TAdaptedString str) { - if (str.isNull()) - return 0; - auto node = stringPool_.add(str, allocator_); - if (!node) - overflowed_ = true; - return node; - } - void saveString(StringNode* node) { - stringPool_.add(node); - } - template - StringNode* getString(const TAdaptedString& str) const { - return stringPool_.get(str); - } - StringNode* createString(size_t length) { - auto node = StringNode::create(length, allocator_); - if (!node) - overflowed_ = true; - return node; - } - StringNode* resizeString(StringNode* node, size_t length) { - node = StringNode::resize(node, length, allocator_); - if (!node) - overflowed_ = true; - return node; - } - void destroyString(StringNode* node) { - StringNode::destroy(node, allocator_); - } - void dereferenceString(const char* s) { - stringPool_.dereference(s, allocator_); - } - void clear() { - variantPools_.clear(allocator_); - overflowed_ = false; - stringPool_.clear(allocator_); - } - void shrinkToFit() { - variantPools_.shrinkToFit(allocator_); - } - private: - Allocator* allocator_; - bool overflowed_; - StringPool stringPool_; - VariantPoolList variantPools_; -}; -template -struct IsString : false_type {}; -template -struct IsString< - T, typename make_void::AdaptedString>::type> - : true_type {}; ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE template @@ -1624,11 +1544,11 @@ template struct FloatTraits {}; template struct FloatTraits { - typedef uint64_t mantissa_type; + using mantissa_type = uint64_t; static const short mantissa_bits = 52; static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; - typedef int16_t exponent_type; + using exponent_type = int16_t; static const exponent_type exponent_max = 308; static pgm_ptr positiveBinaryPowersOfTen() { ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // @@ -1673,16 +1593,16 @@ struct FloatTraits { } template // int64_t static T highest_for( - typename enable_if::value && is_signed::value && - sizeof(TOut) == 8, - signed>::type* = 0) { + enable_if_t::value && is_signed::value && + sizeof(TOut) == 8, + signed>* = 0) { return forge(0x43DFFFFFFFFFFFFF); // 9.2233720368547748e+18 } template // uint64_t static T highest_for( - typename enable_if::value && is_unsigned::value && - sizeof(TOut) == 8, - unsigned>::type* = 0) { + enable_if_t::value && is_unsigned::value && + sizeof(TOut) == 8, + unsigned>* = 0) { return forge(0x43EFFFFFFFFFFFFF); // 1.8446744073709549568e+19 } static T lowest() { @@ -1694,11 +1614,11 @@ struct FloatTraits { }; template struct FloatTraits { - typedef uint32_t mantissa_type; + using mantissa_type = uint32_t; static const short mantissa_bits = 23; static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; - typedef int8_t exponent_type; + using exponent_type = int8_t; static const exponent_type exponent_max = 38; static pgm_ptr positiveBinaryPowersOfTen() { ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, @@ -1738,30 +1658,30 @@ struct FloatTraits { } template // int32_t static T highest_for( - typename enable_if::value && is_signed::value && - sizeof(TOut) == 4, - signed>::type* = 0) { + enable_if_t::value && is_signed::value && + sizeof(TOut) == 4, + signed>* = 0) { return forge(0x4EFFFFFF); // 2.14748352E9 } template // uint32_t static T highest_for( - typename enable_if::value && is_unsigned::value && - sizeof(TOut) == 4, - unsigned>::type* = 0) { + enable_if_t::value && is_unsigned::value && + sizeof(TOut) == 4, + unsigned>* = 0) { return forge(0x4F7FFFFF); // 4.29496704E9 } template // int64_t static T highest_for( - typename enable_if::value && is_signed::value && - sizeof(TOut) == 8, - signed>::type* = 0) { + enable_if_t::value && is_signed::value && + sizeof(TOut) == 8, + signed>* = 0) { return forge(0x5EFFFFFF); // 9.22337148709896192E18 } template // uint64_t static T highest_for( - typename enable_if::value && is_unsigned::value && - sizeof(TOut) == 8, - unsigned>::type* = 0) { + enable_if_t::value && is_unsigned::value && + sizeof(TOut) == 8, + unsigned>* = 0) { return forge(0x5F7FFFFF); // 1.844674297419792384E19 } static T lowest() { @@ -1785,86 +1705,91 @@ inline TFloat make_float(TFloat m, TExponent e) { ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE #if ARDUINOJSON_USE_DOUBLE -typedef double JsonFloat; +using JsonFloat = double; #else -typedef float JsonFloat; +using JsonFloat = float; #endif ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template -typename enable_if::value && is_unsigned::value && - is_integral::value && sizeof(TOut) <= sizeof(TIn), - bool>::type +enable_if_t::value && is_unsigned::value && + is_integral::value && sizeof(TOut) <= sizeof(TIn), + bool> canConvertNumber(TIn value) { return value <= TIn(numeric_limits::highest()); } template -typename enable_if::value && is_unsigned::value && - is_integral::value && sizeof(TIn) < sizeof(TOut), - bool>::type +enable_if_t::value && is_unsigned::value && + is_integral::value && sizeof(TIn) < sizeof(TOut), + bool> canConvertNumber(TIn) { return true; } template -typename enable_if::value && is_floating_point::value, - bool>::type +enable_if_t::value && is_floating_point::value, bool> canConvertNumber(TIn) { return true; } template -typename enable_if::value && is_signed::value && - is_integral::value && is_signed::value && - sizeof(TOut) < sizeof(TIn), - bool>::type +enable_if_t::value && is_signed::value && + is_integral::value && is_signed::value && + sizeof(TOut) < sizeof(TIn), + bool> canConvertNumber(TIn value) { return value >= TIn(numeric_limits::lowest()) && value <= TIn(numeric_limits::highest()); } template -typename enable_if::value && is_signed::value && - is_integral::value && is_signed::value && - sizeof(TIn) <= sizeof(TOut), - bool>::type +enable_if_t::value && is_signed::value && + is_integral::value && is_signed::value && + sizeof(TIn) <= sizeof(TOut), + bool> canConvertNumber(TIn) { return true; } template -typename enable_if::value && is_signed::value && - is_integral::value && is_unsigned::value && - sizeof(TOut) >= sizeof(TIn), - bool>::type +enable_if_t::value && is_signed::value && + is_integral::value && is_unsigned::value && + sizeof(TOut) >= sizeof(TIn), + bool> canConvertNumber(TIn value) { if (value < 0) return false; return TOut(value) <= numeric_limits::highest(); } template -typename enable_if::value && is_signed::value && - is_integral::value && is_unsigned::value && - sizeof(TOut) < sizeof(TIn), - bool>::type +enable_if_t::value && is_signed::value && + is_integral::value && is_unsigned::value && + sizeof(TOut) < sizeof(TIn), + bool> canConvertNumber(TIn value) { if (value < 0) return false; return value <= TIn(numeric_limits::highest()); } template -typename enable_if::value && is_integral::value && - sizeof(TOut) < sizeof(TIn), - bool>::type +enable_if_t::value && is_integral::value && + sizeof(TOut) < sizeof(TIn), + bool> canConvertNumber(TIn value) { return value >= numeric_limits::lowest() && value <= numeric_limits::highest(); } template -typename enable_if::value && is_integral::value && - sizeof(TOut) >= sizeof(TIn), - bool>::type +enable_if_t::value && is_integral::value && + sizeof(TOut) >= sizeof(TIn), + bool> canConvertNumber(TIn value) { return value >= numeric_limits::lowest() && value <= FloatTraits::template highest_for(); } template +enable_if_t::value && is_floating_point::value, + bool> +canConvertNumber(TIn) { + return true; +} +template TOut convertNumber(TIn value) { return canConvertNumber(value) ? TOut(value) : 0; } @@ -1874,9 +1799,73 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE #elif defined(__GNUC__) # pragma GCC diagnostic pop #endif +#if ARDUINOJSON_ENABLE_STD_STREAM +#include +#endif +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE +class JsonString { + friend struct detail::StringAdapter; + public: + JsonString() : str_(nullptr, 0, true) {} + JsonString(const char* data, bool isStatic = false) + : str_(data, data ? ::strlen(data) : 0, isStatic) {} + template ::value && + !detail::is_same::value, + int> = 0> + JsonString(const char* data, TSize sz, bool isStatic = false) + : str_(data, size_t(sz), isStatic) {} + const char* c_str() const { + return str_.data(); + } + bool isNull() const { + return str_.isNull(); + } + bool isStatic() const { + return str_.isStatic(); + } + size_t size() const { + return str_.size(); + } + explicit operator bool() const { + return str_.data() != 0; + } + friend bool operator==(JsonString lhs, JsonString rhs) { + if (lhs.size() != rhs.size()) + return false; + if (lhs.c_str() == rhs.c_str()) + return true; + if (!lhs.c_str()) + return false; + if (!rhs.c_str()) + return false; + return memcmp(lhs.c_str(), rhs.c_str(), lhs.size()) == 0; + } + friend bool operator!=(JsonString lhs, JsonString rhs) { + return !(lhs == rhs); + } +#if ARDUINOJSON_ENABLE_STD_STREAM + friend std::ostream& operator<<(std::ostream& lhs, const JsonString& rhs) { + lhs.write(rhs.c_str(), static_cast(rhs.size())); + return lhs; + } +#endif + private: + detail::RamString str_; +}; +namespace detail { +template <> +struct StringAdapter { + using AdaptedString = RamString; + static const AdaptedString& adapt(const JsonString& s) { + return s.str_; + } +}; +} // namespace detail +ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class VariantData; -class VariantSlot; +class ResourceManager; class CollectionIterator { friend class CollectionData; public: @@ -1903,10 +1892,6 @@ class CollectionIterator { ARDUINOJSON_ASSERT(slot_ != nullptr); return *data(); } - const char* key() const; - bool ownsKey() const; - void setKey(StringNode*); - void setKey(const char*); VariantData* data() { return reinterpret_cast(slot_); } @@ -1914,8 +1899,8 @@ class CollectionIterator { return reinterpret_cast(slot_); } private: - CollectionIterator(VariantSlot* slot, SlotId slotId); - VariantSlot* slot_; + CollectionIterator(VariantData* slot, SlotId slotId); + VariantData* slot_; SlotId currentId_, nextId_; }; class CollectionData { @@ -1927,9 +1912,7 @@ class CollectionData { } static void operator delete(void*, void*) noexcept {} using iterator = CollectionIterator; - iterator createIterator(const ResourceManager* resources) const { - return iterator(resources->getSlot(head_), head_); - } + iterator createIterator(const ResourceManager* resources) const; size_t size(const ResourceManager*) const; size_t nesting(const ResourceManager*) const; void clear(ResourceManager* resources); @@ -1938,20 +1921,17 @@ class CollectionData { return; collection->clear(resources); } - void remove(iterator it, ResourceManager* resources); - static void remove(CollectionData* collection, iterator it, - ResourceManager* resources) { - if (collection) - return collection->remove(it, resources); - } SlotId head() const { return head_; } protected: - iterator addSlot(ResourceManager*); + void appendOne(Slot slot, const ResourceManager* resources); + void appendPair(Slot key, Slot value, + const ResourceManager* resources); + void removeOne(iterator it, ResourceManager* resources); + void removePair(iterator it, ResourceManager* resources); private: - SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const; - void releaseSlot(SlotWithId, ResourceManager*); + Slot getPreviousSlot(VariantData*, const ResourceManager*) const; }; inline const VariantData* collectionToVariant( const CollectionData* collection) { @@ -1964,14 +1944,21 @@ inline VariantData* collectionToVariant(CollectionData* collection) { } class ArrayData : public CollectionData { public: - VariantData* addElement(ResourceManager* resources) { - return addSlot(resources).data(); - } + VariantData* addElement(ResourceManager* resources); static VariantData* addElement(ArrayData* array, ResourceManager* resources) { if (!array) return nullptr; return array->addElement(resources); } + template + bool addValue(const T& value, ResourceManager* resources); + template + static bool addValue(ArrayData* array, const T& value, + ResourceManager* resources) { + if (!array) + return false; + return array->addValue(value, resources); + } VariantData* getOrAddElement(size_t index, ResourceManager* resources); VariantData* getElement(size_t index, const ResourceManager* resources) const; static VariantData* getElement(const ArrayData* array, size_t index, @@ -1987,12 +1974,13 @@ class ArrayData : public CollectionData { return; array->removeElement(index, resources); } - bool copyFrom(const ArrayData& src, ResourceManager* resources); - static bool copy(ArrayData* dst, const ArrayData* src, - ResourceManager* resources) { - if (!dst || !src) - return false; - return dst->copyFrom(*src, resources); + void remove(iterator it, ResourceManager* resources) { + CollectionData::removeOne(it, resources); + } + static void remove(ArrayData* array, iterator it, + ResourceManager* resources) { + if (array) + return array->remove(it, resources); } private: iterator at(size_t index, const ResourceManager* resources) const; @@ -2000,11 +1988,11 @@ class ArrayData : public CollectionData { ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE #if ARDUINOJSON_USE_LONG_LONG -typedef int64_t JsonInteger; -typedef uint64_t JsonUInt; +using JsonInteger = int64_t; +using JsonUInt = uint64_t; #else -typedef long JsonInteger; -typedef unsigned long JsonUInt; +using JsonInteger = long; +using JsonUInt = unsigned long; #endif ARDUINOJSON_END_PUBLIC_NAMESPACE #define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ @@ -2015,32 +2003,8 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class ObjectData : public CollectionData { public: - VariantData* addMember(StringNode* key, ResourceManager* resources) { - ARDUINOJSON_ASSERT(key != nullptr); - auto it = addSlot(resources); - if (it.done()) - return nullptr; - it.setKey(key); - return it.data(); - } - template - VariantData* addMember(TAdaptedString key, ResourceManager* resources) { - ARDUINOJSON_ASSERT(!key.isNull()); - if (key.isLinked()) { - auto it = addSlot(resources); - if (!it.done()) - it.setKey(key.data()); - return it.data(); - } else { - auto storedKey = resources->saveString(key); - if (!storedKey) - return nullptr; - auto it = addSlot(resources); - if (!it.done()) - it.setKey(storedKey); - return it.data(); - } - } + template // also works with StringNode* + VariantData* addMember(TAdaptedString key, ResourceManager* resources); template VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources); template @@ -2062,119 +2026,139 @@ class ObjectData : public CollectionData { return; obj->removeMember(key, resources); } + void remove(iterator it, ResourceManager* resources) { + CollectionData::removePair(it, resources); + } + static void remove(ObjectData* obj, ObjectData::iterator it, + ResourceManager* resources) { + if (!obj) + return; + obj->remove(it, resources); + } + size_t size(const ResourceManager* resources) const { + return CollectionData::size(resources) / 2; + } + static size_t size(const ObjectData* obj, const ResourceManager* resources) { + if (!obj) + return 0; + return obj->size(resources); + } private: template iterator findKey(TAdaptedString key, const ResourceManager* resources) const; }; -enum { - VALUE_MASK = 0x7F, - OWNED_VALUE_BIT = 0x01, - VALUE_IS_NULL = 0, - VALUE_IS_RAW_STRING = 0x03, - VALUE_IS_LINKED_STRING = 0x04, - VALUE_IS_OWNED_STRING = 0x05, - VALUE_IS_BOOLEAN = 0x06, - NUMBER_BIT = 0x08, - VALUE_IS_UNSIGNED_INTEGER = 0x08, - VALUE_IS_SIGNED_INTEGER = 0x0A, - VALUE_IS_FLOAT = 0x0C, - COLLECTION_MASK = 0x60, - VALUE_IS_OBJECT = 0x20, - VALUE_IS_ARRAY = 0x40, - OWNED_KEY_BIT = 0x80 +enum class VariantTypeBits : uint8_t { + OwnedStringBit = 0x01, // 0000 0001 + NumberBit = 0x08, // 0000 1000 +#if ARDUINOJSON_USE_EXTENSIONS + ExtensionBit = 0x10, // 0001 0000 +#endif + CollectionMask = 0x60, +}; +enum class VariantType : uint8_t { + Null = 0, // 0000 0000 + RawString = 0x03, // 0000 0011 + LinkedString = 0x04, // 0000 0100 + OwnedString = 0x05, // 0000 0101 + Boolean = 0x06, // 0000 0110 + Uint32 = 0x0A, // 0000 1010 + Int32 = 0x0C, // 0000 1100 + Float = 0x0E, // 0000 1110 +#if ARDUINOJSON_USE_LONG_LONG + Uint64 = 0x1A, // 0001 1010 + Int64 = 0x1C, // 0001 1100 +#endif +#if ARDUINOJSON_USE_DOUBLE + Double = 0x1E, // 0001 1110 +#endif + Object = 0x20, + Array = 0x40, }; +inline bool operator&(VariantType type, VariantTypeBits bit) { + return (uint8_t(type) & uint8_t(bit)) != 0; +} union VariantContent { VariantContent() {} - JsonFloat asFloat; + float asFloat; bool asBoolean; - JsonUInt asUnsignedInteger; - JsonInteger asSignedInteger; + uint32_t asUint32; + int32_t asInt32; +#if ARDUINOJSON_USE_EXTENSIONS + SlotId asSlotId; +#endif ArrayData asArray; ObjectData asObject; CollectionData asCollection; const char* asLinkedString; struct StringNode* asOwnedString; }; -struct StringNode; -class VariantSlot { - VariantContent content_; - uint8_t flags_; +#if ARDUINOJSON_USE_EXTENSIONS +union VariantExtension { +# if ARDUINOJSON_USE_LONG_LONG + uint64_t asUint64; + int64_t asInt64; +# endif +# if ARDUINOJSON_USE_DOUBLE + double asDouble; +# endif +}; +#endif +template +T parseNumber(const char* s); +class VariantData { + VariantContent content_; // must be first to allow cast from array to variant + VariantType type_; SlotId next_; - const char* key_; public: static void* operator new(size_t, void* p) noexcept { return p; } static void operator delete(void*, void*) noexcept {} - VariantSlot() : flags_(0), next_(NULL_SLOT), key_(0) {} - VariantData* data() { - return reinterpret_cast(&content_); - } - const VariantData* data() const { - return reinterpret_cast(&content_); - } + VariantData() : type_(VariantType::Null), next_(NULL_SLOT) {} SlotId next() const { return next_; } void setNext(SlotId slot) { next_ = slot; } - void setKey(const char* k) { - ARDUINOJSON_ASSERT(k); - flags_ &= VALUE_MASK; - key_ = k; - } - void setKey(StringNode* k) { - ARDUINOJSON_ASSERT(k); - flags_ |= OWNED_KEY_BIT; - key_ = k->data; - } - const char* key() const { - return key_; - } - bool ownsKey() const { - return (flags_ & OWNED_KEY_BIT) != 0; - } -}; -inline VariantData* slotData(VariantSlot* slot) { - return reinterpret_cast(slot); -} -constexpr size_t sizeofArray(size_t n) { - return n * sizeof(VariantSlot); -} -constexpr size_t sizeofObject(size_t n) { - return n * sizeof(VariantSlot); -} -template -T parseNumber(const char* s); -class VariantData { - VariantContent content_; // must be first to allow cast from array to variant - uint8_t flags_; - public: - VariantData() : flags_(VALUE_IS_NULL) {} template - typename TVisitor::result_type accept(TVisitor& visit) const { - switch (type()) { - case VALUE_IS_FLOAT: + typename TVisitor::result_type accept( + TVisitor& visit, const ResourceManager* resources) const { +#if ARDUINOJSON_USE_EXTENSIONS + auto extension = getExtension(resources); +#else + (void)resources; // silence warning +#endif + switch (type_) { + case VariantType::Float: return visit.visit(content_.asFloat); - case VALUE_IS_ARRAY: +#if ARDUINOJSON_USE_DOUBLE + case VariantType::Double: + return visit.visit(extension->asDouble); +#endif + case VariantType::Array: return visit.visit(content_.asArray); - case VALUE_IS_OBJECT: + case VariantType::Object: return visit.visit(content_.asObject); - case VALUE_IS_LINKED_STRING: - return visit.visit(JsonString(content_.asLinkedString)); - case VALUE_IS_OWNED_STRING: + case VariantType::LinkedString: + return visit.visit(JsonString(content_.asLinkedString, true)); + case VariantType::OwnedString: return visit.visit(JsonString(content_.asOwnedString->data, - content_.asOwnedString->length, - JsonString::Copied)); - case VALUE_IS_RAW_STRING: + content_.asOwnedString->length)); + case VariantType::RawString: return visit.visit(RawString(content_.asOwnedString->data, content_.asOwnedString->length)); - case VALUE_IS_SIGNED_INTEGER: - return visit.visit(content_.asSignedInteger); - case VALUE_IS_UNSIGNED_INTEGER: - return visit.visit(content_.asUnsignedInteger); - case VALUE_IS_BOOLEAN: + case VariantType::Int32: + return visit.visit(static_cast(content_.asInt32)); + case VariantType::Uint32: + return visit.visit(static_cast(content_.asUint32)); +#if ARDUINOJSON_USE_LONG_LONG + case VariantType::Int64: + return visit.visit(extension->asInt64); + case VariantType::Uint64: + return visit.visit(extension->asUint64); +#endif + case VariantType::Boolean: return visit.visit(content_.asBoolean != 0); default: return visit.visit(nullptr); @@ -2182,9 +2166,10 @@ class VariantData { } template static typename TVisitor::result_type accept(const VariantData* var, + const ResourceManager* resources, TVisitor& visit) { if (var != 0) - return var->accept(visit); + return var->accept(visit, resources); else return visit.visit(nullptr); } @@ -2197,17 +2182,43 @@ class VariantData { return nullptr; return var->addElement(resources); } - bool asBoolean() const { - switch (type()) { - case VALUE_IS_BOOLEAN: + template + bool addValue(const T& value, ResourceManager* resources) { + auto array = isNull() ? &toArray() : asArray(); + return detail::ArrayData::addValue(array, value, resources); + } + template + static bool addValue(VariantData* var, const T& value, + ResourceManager* resources) { + if (!var) + return false; + return var->addValue(value, resources); + } + bool asBoolean(const ResourceManager* resources) const { +#if ARDUINOJSON_USE_EXTENSIONS + auto extension = getExtension(resources); +#else + (void)resources; // silence warning +#endif + switch (type_) { + case VariantType::Boolean: return content_.asBoolean; - case VALUE_IS_SIGNED_INTEGER: - case VALUE_IS_UNSIGNED_INTEGER: - return content_.asUnsignedInteger != 0; - case VALUE_IS_FLOAT: + case VariantType::Uint32: + case VariantType::Int32: + return content_.asUint32 != 0; + case VariantType::Float: return content_.asFloat != 0; - case VALUE_IS_NULL: +#if ARDUINOJSON_USE_DOUBLE + case VariantType::Double: + return extension->asDouble != 0; +#endif + case VariantType::Null: return false; +#if ARDUINOJSON_USE_LONG_LONG + case VariantType::Uint64: + case VariantType::Int64: + return extension->asUint64 != 0; +#endif default: return true; } @@ -2225,40 +2236,70 @@ class VariantData { return const_cast(this)->asCollection(); } template - T asFloat() const { + T asFloat(const ResourceManager* resources) const { static_assert(is_floating_point::value, "T must be a floating point"); - switch (type()) { - case VALUE_IS_BOOLEAN: +#if ARDUINOJSON_USE_EXTENSIONS + auto extension = getExtension(resources); +#else + (void)resources; // silence warning +#endif + switch (type_) { + case VariantType::Boolean: return static_cast(content_.asBoolean); - case VALUE_IS_UNSIGNED_INTEGER: - return static_cast(content_.asUnsignedInteger); - case VALUE_IS_SIGNED_INTEGER: - return static_cast(content_.asSignedInteger); - case VALUE_IS_LINKED_STRING: - case VALUE_IS_OWNED_STRING: + case VariantType::Uint32: + return static_cast(content_.asUint32); + case VariantType::Int32: + return static_cast(content_.asInt32); +#if ARDUINOJSON_USE_LONG_LONG + case VariantType::Uint64: + return static_cast(extension->asUint64); + case VariantType::Int64: + return static_cast(extension->asInt64); +#endif + case VariantType::LinkedString: + case VariantType::OwnedString: return parseNumber(content_.asOwnedString->data); - case VALUE_IS_FLOAT: + case VariantType::Float: return static_cast(content_.asFloat); +#if ARDUINOJSON_USE_DOUBLE + case VariantType::Double: + return static_cast(extension->asDouble); +#endif default: return 0; } } template - T asIntegral() const { + T asIntegral(const ResourceManager* resources) const { static_assert(is_integral::value, "T must be an integral type"); - switch (type()) { - case VALUE_IS_BOOLEAN: +#if ARDUINOJSON_USE_EXTENSIONS + auto extension = getExtension(resources); +#else + (void)resources; // silence warning +#endif + switch (type_) { + case VariantType::Boolean: return content_.asBoolean; - case VALUE_IS_UNSIGNED_INTEGER: - return convertNumber(content_.asUnsignedInteger); - case VALUE_IS_SIGNED_INTEGER: - return convertNumber(content_.asSignedInteger); - case VALUE_IS_LINKED_STRING: + case VariantType::Uint32: + return convertNumber(content_.asUint32); + case VariantType::Int32: + return convertNumber(content_.asInt32); +#if ARDUINOJSON_USE_LONG_LONG + case VariantType::Uint64: + return convertNumber(extension->asUint64); + case VariantType::Int64: + return convertNumber(extension->asInt64); +#endif + case VariantType::LinkedString: return parseNumber(content_.asLinkedString); - case VALUE_IS_OWNED_STRING: + case VariantType::OwnedString: return parseNumber(content_.asOwnedString->data); - case VALUE_IS_FLOAT: + case VariantType::Float: return convertNumber(content_.asFloat); +#if ARDUINOJSON_USE_DOUBLE + case VariantType::Double: + return convertNumber(extension->asDouble); +#endif default: return 0; } @@ -2270,25 +2311,28 @@ class VariantData { return const_cast(this)->asObject(); } JsonString asRawString() const { - switch (type()) { - case VALUE_IS_RAW_STRING: + switch (type_) { + case VariantType::RawString: return JsonString(content_.asOwnedString->data, - content_.asOwnedString->length, JsonString::Copied); + content_.asOwnedString->length); default: return JsonString(); } } JsonString asString() const { - switch (type()) { - case VALUE_IS_LINKED_STRING: - return JsonString(content_.asLinkedString, JsonString::Linked); - case VALUE_IS_OWNED_STRING: + switch (type_) { + case VariantType::LinkedString: + return JsonString(content_.asLinkedString, true); + case VariantType::OwnedString: return JsonString(content_.asOwnedString->data, - content_.asOwnedString->length, JsonString::Copied); + content_.asOwnedString->length); default: return JsonString(); } } +#if ARDUINOJSON_USE_EXTENSIONS + const VariantExtension* getExtension(const ResourceManager* resources) const; +#endif VariantData* getElement(size_t index, const ResourceManager* resources) const { return ArrayData::getElement(asArray(), index, resources); @@ -2325,30 +2369,41 @@ class VariantData { return obj->getOrAddMember(key, resources); } bool isArray() const { - return (flags_ & VALUE_IS_ARRAY) != 0; + return type_ == VariantType::Array; } bool isBoolean() const { - return type() == VALUE_IS_BOOLEAN; + return type_ == VariantType::Boolean; } bool isCollection() const { - return (flags_ & COLLECTION_MASK) != 0; + return type_ & VariantTypeBits::CollectionMask; } bool isFloat() const { - return (flags_ & NUMBER_BIT) != 0; + return type_ & VariantTypeBits::NumberBit; } template - bool isInteger() const { - switch (type()) { - case VALUE_IS_UNSIGNED_INTEGER: - return canConvertNumber(content_.asUnsignedInteger); - case VALUE_IS_SIGNED_INTEGER: - return canConvertNumber(content_.asSignedInteger); + bool isInteger(const ResourceManager* resources) const { +#if ARDUINOJSON_USE_LONG_LONG + auto extension = getExtension(resources); +#else + (void)resources; // silence warning +#endif + switch (type_) { + case VariantType::Uint32: + return canConvertNumber(content_.asUint32); + case VariantType::Int32: + return canConvertNumber(content_.asInt32); +#if ARDUINOJSON_USE_LONG_LONG + case VariantType::Uint64: + return canConvertNumber(extension->asUint64); + case VariantType::Int64: + return canConvertNumber(extension->asInt64); +#endif default: return false; } } bool isNull() const { - return type() == VALUE_IS_NULL; + return type_ == VariantType::Null; } static bool isNull(const VariantData* var) { if (!var) @@ -2356,10 +2411,11 @@ class VariantData { return var->isNull(); } bool isObject() const { - return (flags_ & VALUE_IS_OBJECT) != 0; + return type_ == VariantType::Object; } bool isString() const { - return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING; + return type_ == VariantType::LinkedString || + type_ == VariantType::OwnedString; } size_t nesting(const ResourceManager* resources) const { auto collection = asCollection(); @@ -2394,153 +2450,210 @@ class VariantData { return; var->removeMember(key, resources); } - void reset() { - flags_ = VALUE_IS_NULL; + void reset() { // TODO: remove + type_ = VariantType::Null; } void setBoolean(bool value) { - setType(VALUE_IS_BOOLEAN); + ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first + type_ = VariantType::Boolean; content_.asBoolean = value; } - void setBoolean(bool value, ResourceManager* resources) { - release(resources); - setBoolean(value); - } - void setFloat(JsonFloat value) { - setType(VALUE_IS_FLOAT); + template + enable_if_t setFloat(T value, ResourceManager*) { + ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first + type_ = VariantType::Float; content_.asFloat = value; - } - void setFloat(JsonFloat value, ResourceManager* resources) { - release(resources); - setFloat(value); + return true; } template - typename enable_if::value>::type setInteger(T value) { - setType(VALUE_IS_SIGNED_INTEGER); - content_.asSignedInteger = value; - } + enable_if_t setFloat(T value, ResourceManager*); template - typename enable_if::value>::type setInteger(T value) { - setType(VALUE_IS_UNSIGNED_INTEGER); - content_.asUnsignedInteger = static_cast(value); - } + enable_if_t::value, bool> setInteger(T value, + ResourceManager* resources); template - void setInteger(T value, ResourceManager* resources) { - release(resources); - setInteger(value); - } - void setNull() { - setType(VALUE_IS_NULL); - } - void setNull(ResourceManager* resources) { - release(resources); - setNull(); - } - static void setNull(VariantData* var, ResourceManager* resources) { - if (!var) - return; - var->setNull(resources); - } + enable_if_t::value, bool> setInteger( + T value, ResourceManager* resources); void setRawString(StringNode* s) { + ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first ARDUINOJSON_ASSERT(s); - setType(VALUE_IS_RAW_STRING); + type_ = VariantType::RawString; content_.asOwnedString = s; } template - void setRawString(SerializedValue value, ResourceManager* resources) { - release(resources); - auto dup = resources->saveString(adaptString(value.data(), value.size())); - if (dup) - setRawString(dup); - else - setNull(); - } + void setRawString(SerializedValue value, ResourceManager* resources); template static void setRawString(VariantData* var, SerializedValue value, ResourceManager* resources) { if (!var) return; + var->clear(resources); var->setRawString(value, resources); } template - void setString(TAdaptedString value, ResourceManager* resources) { - setNull(resources); - if (value.isNull()) - return; - if (value.isLinked()) { - setLinkedString(value.data()); - return; - } - auto dup = resources->saveString(value); - if (dup) - setOwnedString(dup); + bool setString(TAdaptedString value, ResourceManager* resources); + bool setString(StringNode* s, ResourceManager*) { + setOwnedString(s); + return true; } template static void setString(VariantData* var, TAdaptedString value, ResourceManager* resources) { if (!var) return; + var->clear(resources); var->setString(value, resources); } void setLinkedString(const char* s) { + ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first ARDUINOJSON_ASSERT(s); - setType(VALUE_IS_LINKED_STRING); + type_ = VariantType::LinkedString; content_.asLinkedString = s; } void setOwnedString(StringNode* s) { + ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first ARDUINOJSON_ASSERT(s); - setType(VALUE_IS_OWNED_STRING); + type_ = VariantType::OwnedString; content_.asOwnedString = s; } size_t size(const ResourceManager* resources) const { - return isCollection() ? content_.asCollection.size(resources) : 0; + if (isObject()) + return content_.asObject.size(resources); + if (isArray()) + return content_.asArray.size(resources); + return 0; } static size_t size(const VariantData* var, const ResourceManager* resources) { return var != 0 ? var->size(resources) : 0; } ArrayData& toArray() { - setType(VALUE_IS_ARRAY); + ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first + type_ = VariantType::Array; new (&content_.asArray) ArrayData(); return content_.asArray; } - ArrayData& toArray(ResourceManager* resources) { - release(resources); - return toArray(); - } static ArrayData* toArray(VariantData* var, ResourceManager* resources) { if (!var) return 0; - return &var->toArray(resources); + var->clear(resources); + return &var->toArray(); } ObjectData& toObject() { - setType(VALUE_IS_OBJECT); + ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first + type_ = VariantType::Object; new (&content_.asObject) ObjectData(); return content_.asObject; } - ObjectData& toObject(ResourceManager* resources) { - release(resources); - return toObject(); - } static ObjectData* toObject(VariantData* var, ResourceManager* resources) { if (!var) return 0; - return &var->toObject(resources); + var->clear(resources); + return &var->toObject(); } - uint8_t type() const { - return flags_ & VALUE_MASK; + VariantType type() const { + return type_; } - private: - void release(ResourceManager* resources) { - if (flags_ & OWNED_VALUE_BIT) - resources->dereferenceString(content_.asOwnedString->data); - auto collection = asCollection(); - if (collection) - collection->clear(resources); + void clear(ResourceManager* resources); + static void clear(VariantData* var, ResourceManager* resources) { + if (!var) + return; + var->clear(resources); + } +}; +class VariantData; +class VariantWithId; +class ResourceManager { + union SlotData { + VariantData variant; +#if ARDUINOJSON_USE_EXTENSIONS + VariantExtension extension; +#endif + }; + public: + constexpr static size_t slotSize = sizeof(SlotData); + ResourceManager(Allocator* allocator = DefaultAllocator::instance()) + : allocator_(allocator), overflowed_(false) {} + ~ResourceManager() { + stringPool_.clear(allocator_); + variantPools_.clear(allocator_); + } + ResourceManager(const ResourceManager&) = delete; + ResourceManager& operator=(const ResourceManager& src) = delete; + friend void swap(ResourceManager& a, ResourceManager& b) { + swap(a.stringPool_, b.stringPool_); + swap(a.variantPools_, b.variantPools_); + swap_(a.allocator_, b.allocator_); + swap_(a.overflowed_, b.overflowed_); + } + Allocator* allocator() const { + return allocator_; + } + size_t size() const { + return variantPools_.size() + stringPool_.size(); + } + bool overflowed() const { + return overflowed_; + } + Slot allocVariant(); + void freeVariant(Slot slot); + VariantData* getVariant(SlotId id) const; +#if ARDUINOJSON_USE_EXTENSIONS + Slot allocExtension(); + void freeExtension(SlotId slot); + VariantExtension* getExtension(SlotId id) const; +#endif + template + StringNode* saveString(TAdaptedString str) { + if (str.isNull()) + return 0; + auto node = stringPool_.add(str, allocator_); + if (!node) + overflowed_ = true; + return node; + } + void saveString(StringNode* node) { + stringPool_.add(node); + } + template + StringNode* getString(const TAdaptedString& str) const { + return stringPool_.get(str); + } + StringNode* createString(size_t length) { + auto node = StringNode::create(length, allocator_); + if (!node) + overflowed_ = true; + return node; + } + StringNode* resizeString(StringNode* node, size_t length) { + node = StringNode::resize(node, length, allocator_); + if (!node) + overflowed_ = true; + return node; + } + void destroyString(StringNode* node) { + StringNode::destroy(node, allocator_); + } + void dereferenceString(const char* s) { + stringPool_.dereference(s, allocator_); + } + void clear() { + variantPools_.clear(allocator_); + overflowed_ = false; + stringPool_.clear(allocator_); } - void setType(uint8_t t) { - flags_ &= OWNED_KEY_BIT; - flags_ |= t; + void shrinkToFit() { + variantPools_.shrinkToFit(allocator_); } + private: + Allocator* allocator_; + bool overflowed_; + StringPool stringPool_; + MemoryPoolList variantPools_; }; +template +struct IsString : false_type {}; +template +struct IsString::AdaptedString>> + : true_type {}; ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonArray; @@ -2552,15 +2665,15 @@ template struct VariantTo {}; template <> struct VariantTo { - typedef JsonArray type; + using type = JsonArray; }; template <> struct VariantTo { - typedef JsonObject type; + using type = JsonObject; }; template <> struct VariantTo { - typedef JsonVariant type; + using type = JsonVariant; }; class VariantAttorney { public: @@ -2598,31 +2711,31 @@ CompareResult arithmeticCompare(const T& lhs, const T& rhs) { template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, - typename enable_if::value && is_integral::value && - sizeof(T1) < sizeof(T2)>::type* = 0) { + enable_if_t::value && is_integral::value && + sizeof(T1) < sizeof(T2)>* = 0) { return arithmeticCompare(static_cast(lhs), rhs); } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, - typename enable_if::value && is_integral::value && - sizeof(T2) < sizeof(T1)>::type* = 0) { + enable_if_t::value && is_integral::value && + sizeof(T2) < sizeof(T1)>* = 0) { return arithmeticCompare(lhs, static_cast(rhs)); } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, - typename enable_if::value && is_integral::value && - is_signed::value == is_signed::value && - sizeof(T2) == sizeof(T1)>::type* = 0) { + enable_if_t::value && is_integral::value && + is_signed::value == is_signed::value && + sizeof(T2) == sizeof(T1)>* = 0) { return arithmeticCompare(lhs, static_cast(rhs)); } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, - typename enable_if::value && is_integral::value && - is_unsigned::value && is_signed::value && - sizeof(T2) == sizeof(T1)>::type* = 0) { + enable_if_t::value && is_integral::value && + is_unsigned::value && is_signed::value && + sizeof(T2) == sizeof(T1)>* = 0) { if (rhs < 0) return COMPARE_RESULT_GREATER; return arithmeticCompare(lhs, static_cast(rhs)); @@ -2630,9 +2743,9 @@ CompareResult arithmeticCompare( template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, - typename enable_if::value && is_integral::value && - is_signed::value && is_unsigned::value && - sizeof(T2) == sizeof(T1)>::type* = 0) { + enable_if_t::value && is_integral::value && + is_signed::value && is_unsigned::value && + sizeof(T2) == sizeof(T1)>* = 0) { if (lhs < 0) return COMPARE_RESULT_LESS; return arithmeticCompare(static_cast(lhs), rhs); @@ -2640,35 +2753,31 @@ CompareResult arithmeticCompare( template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, - typename enable_if::value || - is_floating_point::value>::type* = 0) { + enable_if_t::value || is_floating_point::value>* = + 0) { return arithmeticCompare(static_cast(lhs), static_cast(rhs)); } template CompareResult arithmeticCompareNegateLeft( - JsonUInt, const T2&, - typename enable_if::value>::type* = 0) { + JsonUInt, const T2&, enable_if_t::value>* = 0) { return COMPARE_RESULT_LESS; } template CompareResult arithmeticCompareNegateLeft( - JsonUInt lhs, const T2& rhs, - typename enable_if::value>::type* = 0) { + JsonUInt lhs, const T2& rhs, enable_if_t::value>* = 0) { if (rhs > 0) return COMPARE_RESULT_LESS; return arithmeticCompare(-rhs, static_cast(lhs)); } template CompareResult arithmeticCompareNegateRight( - const T1&, JsonUInt, - typename enable_if::value>::type* = 0) { + const T1&, JsonUInt, enable_if_t::value>* = 0) { return COMPARE_RESULT_GREATER; } template CompareResult arithmeticCompareNegateRight( - const T1& lhs, JsonUInt rhs, - typename enable_if::value>::type* = 0) { + const T1& lhs, JsonUInt rhs, enable_if_t::value>* = 0) { if (lhs > 0) return COMPARE_RESULT_GREATER; return arithmeticCompare(static_cast(rhs), -lhs); @@ -2687,10 +2796,9 @@ CompareResult compare(JsonVariantConst lhs, struct VariantOperatorTag {}; template struct VariantOperators : VariantOperatorTag { - template - friend - typename enable_if::value && !is_array::value, T>::type - operator|(const TVariant& variant, const T& defaultValue) { + template ::value && !is_array::value, int> = 0> + friend T operator|(const TVariant& variant, const T& defaultValue) { if (variant.template is()) return variant.template as(); else @@ -2704,119 +2812,113 @@ struct VariantOperators : VariantOperatorTag { return defaultValue; } template - friend typename enable_if::value, JsonVariantConst>::type - operator|(const TVariant& variant, T defaultValue) { + friend enable_if_t::value, JsonVariantConst> operator|( + const TVariant& variant, const T& defaultValue) { if (variant) return variant; else return defaultValue; } template - friend bool operator==(T* lhs, TVariant rhs) { + friend bool operator==(T* lhs, const TVariant& rhs) { return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; } template - friend bool operator==(const T& lhs, TVariant rhs) { + friend bool operator==(const T& lhs, const TVariant& rhs) { return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; } template - friend bool operator==(TVariant lhs, T* rhs) { + friend bool operator==(const TVariant& lhs, T* rhs) { return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; } - template - friend - typename enable_if::value, bool>::type - operator==(TVariant lhs, const T& rhs) { + template ::value, int> = 0> + friend bool operator==(const TVariant& lhs, const T& rhs) { return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; } template - friend bool operator!=(T* lhs, TVariant rhs) { + friend bool operator!=(T* lhs, const TVariant& rhs) { return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; } template - friend bool operator!=(const T& lhs, TVariant rhs) { + friend bool operator!=(const T& lhs, const TVariant& rhs) { return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; } template - friend bool operator!=(TVariant lhs, T* rhs) { + friend bool operator!=(const TVariant& lhs, T* rhs) { return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; } - template - friend - typename enable_if::value, bool>::type - operator!=(TVariant lhs, const T& rhs) { + template ::value, int> = 0> + friend bool operator!=(TVariant lhs, const T& rhs) { return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; } template - friend bool operator<(T* lhs, TVariant rhs) { + friend bool operator<(T* lhs, const TVariant& rhs) { return compare(rhs, lhs) == COMPARE_RESULT_GREATER; } template - friend bool operator<(const T& lhs, TVariant rhs) { + friend bool operator<(const T& lhs, const TVariant& rhs) { return compare(rhs, lhs) == COMPARE_RESULT_GREATER; } template - friend bool operator<(TVariant lhs, T* rhs) { + friend bool operator<(const TVariant& lhs, T* rhs) { return compare(lhs, rhs) == COMPARE_RESULT_LESS; } - template - friend - typename enable_if::value, bool>::type - operator<(TVariant lhs, const T& rhs) { + template ::value, int> = 0> + friend bool operator<(TVariant lhs, const T& rhs) { return compare(lhs, rhs) == COMPARE_RESULT_LESS; } template - friend bool operator<=(T* lhs, TVariant rhs) { + friend bool operator<=(T* lhs, const TVariant& rhs) { return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } template - friend bool operator<=(const T& lhs, TVariant rhs) { + friend bool operator<=(const T& lhs, const TVariant& rhs) { return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } template - friend bool operator<=(TVariant lhs, T* rhs) { + friend bool operator<=(const TVariant& lhs, T* rhs) { return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } - template - friend - typename enable_if::value, bool>::type - operator<=(TVariant lhs, const T& rhs) { + template ::value, int> = 0> + friend bool operator<=(TVariant lhs, const T& rhs) { return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template - friend bool operator>(T* lhs, TVariant rhs) { + friend bool operator>(T* lhs, const TVariant& rhs) { return compare(rhs, lhs) == COMPARE_RESULT_LESS; } template - friend bool operator>(const T& lhs, TVariant rhs) { + friend bool operator>(const T& lhs, const TVariant& rhs) { return compare(rhs, lhs) == COMPARE_RESULT_LESS; } template - friend bool operator>(TVariant lhs, T* rhs) { + friend bool operator>(const TVariant& lhs, T* rhs) { return compare(lhs, rhs) == COMPARE_RESULT_GREATER; } - template - friend - typename enable_if::value, bool>::type - operator>(TVariant lhs, const T& rhs) { + template ::value, int> = 0> + friend bool operator>(TVariant lhs, const T& rhs) { return compare(lhs, rhs) == COMPARE_RESULT_GREATER; } template - friend bool operator>=(T* lhs, TVariant rhs) { + friend bool operator>=(T* lhs, const TVariant& rhs) { return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template - friend bool operator>=(const T& lhs, TVariant rhs) { + friend bool operator>=(const T& lhs, const TVariant& rhs) { return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template - friend bool operator>=(TVariant lhs, T* rhs) { + friend bool operator>=(const TVariant& lhs, T* rhs) { return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } - template - friend - typename enable_if::value, bool>::type - operator>=(TVariant lhs, const T& rhs) { + template ::value, int> = 0> + friend bool operator>=(const TVariant& lhs, const T& rhs) { return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } }; @@ -2827,6 +2929,11 @@ class JsonObject; class JsonVariantConst : public detail::VariantTag, public detail::VariantOperators { friend class detail::VariantAttorney; + template + using ConversionSupported = + detail::is_same::fromJson)>::arg1_type, + JsonVariantConst>; public: JsonVariantConst() : data_(nullptr), resources_(nullptr) {} explicit JsonVariantConst(const detail::VariantData* data, @@ -2844,56 +2951,81 @@ class JsonVariantConst : public detail::VariantTag, size_t size() const { return detail::VariantData::size(data_, resources_); } - template - typename detail::enable_if::value && - !detail::is_same::value, - T>::type - as() const { + template ::value, int> = 0> + T as() const { return Converter::fromJson(*this); } - template - typename detail::enable_if::value && - !detail::is_same::value, - bool>::type - is() const { + template ::value, int> = 0> + detail::InvalidConversion as() const; + template ::value, int> = 0> + bool is() const { return Converter::checkJson(*this); } + template ::value, int> = 0> + bool is() const { + return false; + } template operator T() const { return as(); } - JsonVariantConst operator[](size_t index) const { + template ::value, int> = 0> + JsonVariantConst operator[](T index) const { return JsonVariantConst( - detail::VariantData::getElement(data_, index, resources_), resources_); + detail::VariantData::getElement(data_, size_t(index), resources_), + resources_); } - template - typename detail::enable_if::value, - JsonVariantConst>::type - operator[](const TString& key) const { + template ::value, int> = 0> + JsonVariantConst operator[](const TString& key) const { return JsonVariantConst(detail::VariantData::getMember( data_, detail::adaptString(key), resources_), resources_); } - template - typename detail::enable_if::value, - JsonVariantConst>::type - operator[](TChar* key) const { + template ::value && + !detail::is_const::value, + int> = 0> + JsonVariantConst operator[](TChar* key) const { return JsonVariantConst(detail::VariantData::getMember( data_, detail::adaptString(key), resources_), resources_); } - template - typename detail::enable_if::value, bool>::type - containsKey(const TString& key) const { + template ::value, int> = 0> + JsonVariantConst operator[](const TVariant& key) const { + if (key.template is()) + return operator[](key.template as()); + else + return operator[](key.template as()); + } + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use var[key].is() instead") + bool containsKey(const TString& key) const { return detail::VariantData::getMember(getData(), detail::adaptString(key), resources_) != 0; } - template - typename detail::enable_if::value, bool>::type - containsKey(TChar* key) const { + template ::value && + !detail::is_const::value, + int> = 0> + ARDUINOJSON_DEPRECATED("use obj[\"key\"].is() instead") + bool containsKey(TChar* key) const { return detail::VariantData::getMember(getData(), detail::adaptString(key), resources_) != 0; } + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use var[key].is() instead") + bool containsKey(const TVariant& key) const { + return containsKey(key.template as()); + } ARDUINOJSON_DEPRECATED("always returns zero") size_t memoryUsage() const { return 0; @@ -2921,7 +3053,7 @@ class VariantRefBase : public VariantTag { friend class VariantAttorney; public: void clear() const { - VariantData::setNull(getOrCreateData(), getResourceManager()); + VariantData::clear(getOrCreateData(), getResourceManager()); } bool isNull() const { return VariantData::isNull(getData()); @@ -2930,88 +3062,97 @@ class VariantRefBase : public VariantTag { return !getData(); } template - typename enable_if::value, T>::type as() - const { - return Converter::fromJson(getVariantConst()); - } - template - typename enable_if::value, T>::type as() const; - template ::value>::type> + T as() const; + template ::value, int> = 0> operator T() const { return as(); } + template ::value, int> = 0> + JsonArray to() const; + template ::value, int> = 0> + JsonObject to() const; + template ::value, int> = 0> + JsonVariant to() const; template - typename enable_if::value, JsonArray>::type to() const; - template - typename enable_if::value, JsonObject>::type to() - const; - template - typename enable_if::value, JsonVariant>::type to() - const; - template - FORCE_INLINE - typename enable_if::value, bool>::type - is() const; + FORCE_INLINE bool is() const; template - FORCE_INLINE - typename enable_if::value, bool>::type - is() const { - return Converter::checkJson(getVariantConst()); + bool set(const T& value) const { + using TypeForConverter = conditional_t::value, T, + remove_cv_t>>; + return doSet>(value); + } + template ::value, int> = 0> + bool set(T* value) const { + return doSet>(value); } - template - bool set(const T& value) const; - template - bool set(T* value) const; size_t size() const { return VariantData::size(getData(), getResourceManager()); } size_t nesting() const { return VariantData::nesting(getData(), getResourceManager()); } - template - typename enable_if::value, T>::type add() const { + template ::value, int> = 0> + T add() const { return add().template to(); } - template - typename enable_if::value, T>::type add() const; + template ::value, int> = 0> + T add() const; template bool add(const T& value) const { - return add().set(value); + return detail::VariantData::addValue(getOrCreateData(), value, + getResourceManager()); } - template + template ::value, int> = 0> bool add(T* value) const { - return add().set(value); + return detail::VariantData::addValue(getOrCreateData(), value, + getResourceManager()); } void remove(size_t index) const { VariantData::removeElement(getData(), index, getResourceManager()); } - template - typename enable_if::value>::type remove(TChar* key) const { + template ::value, int> = 0> + void remove(TChar* key) const { VariantData::removeMember(getData(), adaptString(key), getResourceManager()); } - template - typename enable_if::value>::type remove( - const TString& key) const { + template ::value, int> = 0> + void remove(const TString& key) const { VariantData::removeMember(getData(), adaptString(key), getResourceManager()); } + template ::value, int> = 0> + void remove(const TVariant& key) const { + if (key.template is()) + remove(key.template as()); + else + remove(key.template as()); + } ElementProxy operator[](size_t index) const; - template - typename enable_if::value, bool>::type containsKey( + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use obj[key].is() instead") + bool containsKey(const TString& key) const; + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use obj[\"key\"].is() instead") + bool containsKey(TChar* key) const; + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use obj[key].is() instead") + bool containsKey(const TVariant& key) const; + template ::value, int> = 0> + FORCE_INLINE MemberProxy> operator[]( const TString& key) const; - template - typename enable_if::value, bool>::type containsKey( + template < + typename TChar, + enable_if_t::value && !is_const::value, int> = 0> + FORCE_INLINE MemberProxy> operator[]( TChar* key) const; - template - FORCE_INLINE typename enable_if::value, - MemberProxy>::type - operator[](const TString& key) const; - template - FORCE_INLINE typename enable_if::value, - MemberProxy>::type - operator[](TChar* key) const; + template ::value, int> = 0> + JsonVariantConst operator[](const TVariant& key) const { + if (key.template is()) + return operator[](key.template as()); + else + return operator[](key.template as()); + } ARDUINOJSON_DEPRECATED("use add() instead") JsonVariant add() const; ARDUINOJSON_DEPRECATED("use add() instead") @@ -3058,17 +3199,41 @@ class VariantRefBase : public VariantTag { FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const { return ArduinoJson::JsonVariantConst(getData(), getResourceManager()); } + template + FORCE_INLINE enable_if_t::value, T> getVariant() + const { + return getVariantConst(); + } + template + FORCE_INLINE enable_if_t::value, T> getVariant() + const { + return getVariant(); + } + template + bool doSet(const T& value) const { + return doSet( + value, is_same::return_type, + bool>{}); + } + template + bool doSet(const T& value, false_type) const; + template + bool doSet(const T& value, true_type) const; ArduinoJson::JsonVariant getOrCreateVariant() const; }; template class ElementProxy : public VariantRefBase>, public VariantOperators> { friend class VariantAttorney; + friend class VariantRefBase>; + template + friend class MemberProxy; + template + friend class ElementProxy; public: ElementProxy(TUpstream upstream, size_t index) : upstream_(upstream), index_(index) {} - ElementProxy(const ElementProxy& src) - : upstream_(src.upstream_), index_(src.index_) {} ElementProxy& operator=(const ElementProxy& src) { this->set(src); return *this; @@ -3084,6 +3249,8 @@ class ElementProxy : public VariantRefBase>, return *this; } private: + ElementProxy(const ElementProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/ + : upstream_(src.upstream_), index_(src.index_) {} ResourceManager* getResourceManager() const { return VariantAttorney::getResourceManager(upstream_); } @@ -3135,15 +3302,10 @@ struct Converter : private detail::VariantAttorney { static JsonVariant fromJson(JsonVariant src) { return src; } - static detail::InvalidConversion fromJson( - JsonVariantConst); static bool checkJson(JsonVariant src) { auto data = getData(src); return !!data; } - static bool checkJson(JsonVariantConst) { - return false; - } }; template <> struct Converter : private detail::VariantAttorney { @@ -3230,7 +3392,7 @@ class JsonArrayConst : public detail::VariantOperators { friend class JsonArray; friend class detail::VariantAttorney; public: - typedef JsonArrayConstIterator iterator; + using iterator = JsonArrayConstIterator; iterator begin() const { if (!data_) return iterator(); @@ -3239,13 +3401,24 @@ class JsonArrayConst : public detail::VariantOperators { iterator end() const { return iterator(); } - JsonArrayConst() : data_(0) {} + JsonArrayConst() : data_(0), resources_(0) {} JsonArrayConst(const detail::ArrayData* data, const detail::ResourceManager* resources) : data_(data), resources_(resources) {} - JsonVariantConst operator[](size_t index) const { + template ::value, int> = 0> + JsonVariantConst operator[](T index) const { return JsonVariantConst( - detail::ArrayData::getElement(data_, index, resources_), resources_); + detail::ArrayData::getElement(data_, size_t(index), resources_), + resources_); + } + template ::value, int> = 0> + JsonVariantConst operator[](const TVariant& variant) const { + if (variant.template is()) + return operator[](variant.template as()); + else + return JsonVariantConst(); } operator JsonVariantConst() const { return JsonVariantConst(getData(), resources_); @@ -3295,7 +3468,7 @@ class JsonObject; class JsonArray : public detail::VariantOperators { friend class detail::VariantAttorney; public: - typedef JsonArrayIterator iterator; + using iterator = JsonArrayIterator; JsonArray() : data_(0), resources_(0) {} JsonArray(detail::ArrayData* data, detail::ResourceManager* resources) : data_(data), resources_(resources) {} @@ -3307,24 +3480,25 @@ class JsonArray : public detail::VariantOperators { operator JsonArrayConst() const { return JsonArrayConst(data_, resources_); } - template - typename detail::enable_if::value, T>::type - add() const { + template ::value, int> = 0> + T add() const { return add().to(); } - template - typename detail::enable_if::value, T>::type - add() const { + template ::value, int> = 0> + JsonVariant add() const { return JsonVariant(detail::ArrayData::addElement(data_, resources_), resources_); } template bool add(const T& value) const { - return add().set(value); + return detail::ArrayData::addValue(data_, value, resources_); } - template + template ::value, int> = 0> bool add(T* value) const { - return add().set(value); + return detail::ArrayData::addValue(data_, value, resources_); } iterator begin() const { if (!data_) @@ -3350,11 +3524,27 @@ class JsonArray : public detail::VariantOperators { void remove(size_t index) const { detail::ArrayData::removeElement(data_, index, resources_); } + template ::value, int> = 0> + void remove(const TVariant& variant) const { + if (variant.template is()) + remove(variant.template as()); + } void clear() const { detail::ArrayData::clear(data_, resources_); } - detail::ElementProxy operator[](size_t index) const { - return {*this, index}; + template ::value, int> = 0> + detail::ElementProxy operator[](T index) const { + return {*this, size_t(index)}; + } + template ::value, int> = 0> + detail::ElementProxy operator[](const TVariant& variant) const { + if (variant.template is()) + return {*this, variant.template as()}; + else + return {*this, size_t(-1)}; } operator JsonVariantConst() const { return JsonVariantConst(collectionToVariant(data_), resources_); @@ -3401,42 +3591,42 @@ class JsonArray : public detail::VariantOperators { class JsonPair { public: JsonPair(detail::ObjectData::iterator iterator, - detail::ResourceManager* resources) - : iterator_(iterator), resources_(resources) {} + detail::ResourceManager* resources) { + if (!iterator.done()) { + key_ = iterator->asString(); + iterator.next(resources); + value_ = JsonVariant(iterator.data(), resources); + } + } JsonString key() const { - if (!iterator_.done()) - return JsonString(iterator_.key(), iterator_.ownsKey() - ? JsonString::Copied - : JsonString::Linked); - else - return JsonString(); + return key_; } JsonVariant value() { - return JsonVariant(iterator_.data(), resources_); + return value_; } private: - detail::ObjectData::iterator iterator_; - detail::ResourceManager* resources_; + JsonString key_; + JsonVariant value_; }; class JsonPairConst { public: JsonPairConst(detail::ObjectData::iterator iterator, - const detail::ResourceManager* resources) - : iterator_(iterator), resources_(resources) {} + const detail::ResourceManager* resources) { + if (!iterator.done()) { + key_ = iterator->asString(); + iterator.next(resources); + value_ = JsonVariantConst(iterator.data(), resources); + } + } JsonString key() const { - if (!iterator_.done()) - return JsonString(iterator_.key(), iterator_.ownsKey() - ? JsonString::Copied - : JsonString::Linked); - else - return JsonString(); + return key_; } JsonVariantConst value() const { - return JsonVariantConst(iterator_.data(), resources_); + return value_; } private: - detail::ObjectData::iterator iterator_; - const detail::ResourceManager* resources_; + JsonString key_; + JsonVariantConst value_; }; class JsonObjectIterator { friend class JsonObject; @@ -3458,7 +3648,8 @@ class JsonObjectIterator { return iterator_ != other.iterator_; } JsonObjectIterator& operator++() { - iterator_.next(resources_); + iterator_.next(resources_); // key + iterator_.next(resources_); // value return *this; } private: @@ -3485,7 +3676,8 @@ class JsonObjectConstIterator { return iterator_ != other.iterator_; } JsonObjectConstIterator& operator++() { - iterator_.next(resources_); + iterator_.next(resources_); // key + iterator_.next(resources_); // value return *this; } private: @@ -3496,8 +3688,8 @@ class JsonObjectConst : public detail::VariantOperators { friend class JsonObject; friend class detail::VariantAttorney; public: - typedef JsonObjectConstIterator iterator; - JsonObjectConst() : data_(0) {} + using iterator = JsonObjectConstIterator; + JsonObjectConst() : data_(0), resources_(0) {} JsonObjectConst(const detail::ObjectData* data, const detail::ResourceManager* resources) : data_(data), resources_(resources) {} @@ -3524,32 +3716,49 @@ class JsonObjectConst : public detail::VariantOperators { iterator end() const { return iterator(); } - template + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use obj[key].is() instead") bool containsKey(const TString& key) const { return detail::ObjectData::getMember(data_, detail::adaptString(key), resources_) != 0; } template + ARDUINOJSON_DEPRECATED("use obj[\"key\"].is() instead") bool containsKey(TChar* key) const { return detail::ObjectData::getMember(data_, detail::adaptString(key), resources_) != 0; } - template - typename detail::enable_if::value, - JsonVariantConst>::type - operator[](const TString& key) const { + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use obj[key].is() instead") + bool containsKey(const TVariant& key) const { + return containsKey(key.template as()); + } + template ::value, int> = 0> + JsonVariantConst operator[](const TString& key) const { return JsonVariantConst(detail::ObjectData::getMember( data_, detail::adaptString(key), resources_), resources_); } - template - typename detail::enable_if::value, - JsonVariantConst>::type - operator[](TChar* key) const { + template ::value && + !detail::is_const::value, + int> = 0> + JsonVariantConst operator[](TChar* key) const { return JsonVariantConst(detail::ObjectData::getMember( data_, detail::adaptString(key), resources_), resources_); } + template ::value, int> = 0> + JsonVariantConst operator[](const TVariant& key) const { + if (key.template is()) + return operator[](key.template as()); + else + return JsonVariantConst(); + } ARDUINOJSON_DEPRECATED("always returns zero") size_t memoryUsage() const { return 0; @@ -3579,16 +3788,19 @@ inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) { } ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template +template class MemberProxy - : public VariantRefBase>, - public VariantOperators> { + : public VariantRefBase>, + public VariantOperators> { friend class VariantAttorney; + friend class VariantRefBase>; + template + friend class MemberProxy; + template + friend class ElementProxy; public: - MemberProxy(TUpstream upstream, TStringRef key) + MemberProxy(TUpstream upstream, AdaptedString key) : upstream_(upstream), key_(key) {} - MemberProxy(const MemberProxy& src) - : upstream_(src.upstream_), key_(src.key_) {} MemberProxy& operator=(const MemberProxy& src) { this->set(src); return *this; @@ -3598,30 +3810,32 @@ class MemberProxy this->set(src); return *this; } - template + template ::value, int> = 0> MemberProxy& operator=(T* src) { this->set(src); return *this; } private: + MemberProxy(const MemberProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/ + : upstream_(src.upstream_), key_(src.key_) {} ResourceManager* getResourceManager() const { return VariantAttorney::getResourceManager(upstream_); } VariantData* getData() const { return VariantData::getMember( - VariantAttorney::getData(upstream_), adaptString(key_), + VariantAttorney::getData(upstream_), key_, VariantAttorney::getResourceManager(upstream_)); } VariantData* getOrCreateData() const { auto data = VariantAttorney::getOrCreateData(upstream_); if (!data) return nullptr; - return data->getOrAddMember(adaptString(key_), + return data->getOrAddMember(key_, VariantAttorney::getResourceManager(upstream_)); } private: TUpstream upstream_; - TStringRef key_; + AdaptedString key_; }; ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE @@ -3629,7 +3843,7 @@ class JsonArray; class JsonObject : public detail::VariantOperators { friend class detail::VariantAttorney; public: - typedef JsonObjectIterator iterator; + using iterator = JsonObjectIterator; JsonObject() : data_(0), resources_(0) {} JsonObject(detail::ObjectData* data, detail::ResourceManager* resource) : data_(data), resources_(resource) {} @@ -3677,43 +3891,68 @@ class JsonObject : public detail::VariantOperators { } return true; } - template - typename detail::enable_if::value, - detail::MemberProxy>::type - operator[](const TString& key) const { - return {*this, key}; - } - template - typename detail::enable_if::value, - detail::MemberProxy>::type - operator[](TChar* key) const { - return {*this, key}; + template ::value, int> = 0> + detail::MemberProxy> operator[]( + const TString& key) const { + return {*this, detail::adaptString(key)}; + } + template ::value && + !detail::is_const::value, + int> = 0> + detail::MemberProxy> operator[]( + TChar* key) const { + return {*this, detail::adaptString(key)}; + } + template ::value, int> = 0> + detail::MemberProxy> operator[]( + const TVariant& key) const { + return {*this, detail::adaptString(key.template as())}; } FORCE_INLINE void remove(iterator it) const { detail::ObjectData::remove(data_, it.iterator_, resources_); } - template - FORCE_INLINE void remove(const TString& key) const { + template ::value, int> = 0> + void remove(const TString& key) const { detail::ObjectData::removeMember(data_, detail::adaptString(key), resources_); } + template ::value, int> = 0> + void remove(const TVariant& key) const { + if (key.template is()) + remove(key.template as()); + } template FORCE_INLINE void remove(TChar* key) const { detail::ObjectData::removeMember(data_, detail::adaptString(key), resources_); } - template - typename detail::enable_if::value, bool>::type - containsKey(const TString& key) const { + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use obj[key].is() instead") + bool containsKey(const TString& key) const { return detail::ObjectData::getMember(data_, detail::adaptString(key), resources_) != 0; } - template - typename detail::enable_if::value, bool>::type - containsKey(TChar* key) const { + template ::value && + !detail::is_const::value, + int> = 0> + ARDUINOJSON_DEPRECATED("use obj[\"key\"].is() instead") + bool containsKey(TChar* key) const { return detail::ObjectData::getMember(data_, detail::adaptString(key), resources_) != 0; } + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use obj[key].is() instead") + bool containsKey(const TVariant& key) const { + return containsKey(key.template as()); + } template ARDUINOJSON_DEPRECATED("use obj[key].to() instead") JsonArray createNestedArray(TChar* key) const { @@ -3763,16 +4002,15 @@ class JsonDocument : public detail::VariantOperators { : JsonDocument(detail::DefaultAllocator::instance()) { swap(*this, src); } - template + template ::value || + detail::is_same::value || + detail::is_same::value || + detail::is_same::value || + detail::is_same::value, + int> = 0> JsonDocument(const T& src, - Allocator* alloc = detail::DefaultAllocator::instance(), - typename detail::enable_if< - detail::is_same::value || - detail::is_same::value || - detail::is_same::value || - detail::is_same::value || - detail::is_same::value || - detail::is_same::value>::type* = 0) + Allocator* alloc = detail::DefaultAllocator::instance()) : JsonDocument(alloc) { set(src); } @@ -3826,10 +4064,15 @@ class JsonDocument : public detail::VariantOperators { bool set(const JsonDocument& src) { return to().set(src.as()); } - template - typename detail::enable_if::value, - bool>::type - set(const T& src) { + template < + typename T, + detail::enable_if_t::value, int> = 0> + bool set(const T& src) { + return to().set(src); + } + template ::value, int> = 0> + bool set(TChar* src) { return to().set(src); } template @@ -3838,78 +4081,114 @@ class JsonDocument : public detail::VariantOperators { return getVariant().template to(); } template + ARDUINOJSON_DEPRECATED("use doc[\"key\"].is() instead") bool containsKey(TChar* key) const { return data_.getMember(detail::adaptString(key), &resources_) != 0; } - template + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use doc[key].is() instead") bool containsKey(const TString& key) const { return data_.getMember(detail::adaptString(key), &resources_) != 0; } - template - typename detail::enable_if::value, - detail::MemberProxy>::type - operator[](const TString& key) { - return {*this, key}; + template ::value, int> = 0> + ARDUINOJSON_DEPRECATED("use doc[key].is() instead") + bool containsKey(const TVariant& key) const { + return containsKey(key.template as()); } - template - typename detail::enable_if::value, - detail::MemberProxy>::type - operator[](TChar* key) { - return {*this, key}; + template ::value, int> = 0> + detail::MemberProxy> operator[]( + const TString& key) { + return {*this, detail::adaptString(key)}; } - template - typename detail::enable_if::value, - JsonVariantConst>::type - operator[](const TString& key) const { + template ::value && + !detail::is_const::value, + int> = 0> + detail::MemberProxy> operator[]( + TChar* key) { + return {*this, detail::adaptString(key)}; + } + template ::value, int> = 0> + JsonVariantConst operator[](const TString& key) const { return JsonVariantConst( data_.getMember(detail::adaptString(key), &resources_), &resources_); } - template - typename detail::enable_if::value, - JsonVariantConst>::type - operator[](TChar* key) const { + template ::value && + !detail::is_const::value, + int> = 0> + JsonVariantConst operator[](TChar* key) const { return JsonVariantConst( data_.getMember(detail::adaptString(key), &resources_), &resources_); } - detail::ElementProxy operator[](size_t index) { - return {*this, index}; + template ::value, int> = 0> + detail::ElementProxy operator[](T index) { + return {*this, size_t(index)}; } JsonVariantConst operator[](size_t index) const { return JsonVariantConst(data_.getElement(index, &resources_), &resources_); } - template - typename detail::enable_if::value, T>::type - add() { + template ::value, int> = 0> + JsonVariantConst operator[](const TVariant& key) const { + if (key.template is()) + return operator[](key.template as()); + if (key.template is()) + return operator[](key.template as()); + return {}; + } + template ::value, int> = 0> + T add() { return add().to(); } - template - typename detail::enable_if::value, T>::type - add() { + template ::value, int> = 0> + JsonVariant add() { return JsonVariant(data_.addElement(&resources_), &resources_); } template bool add(const TValue& value) { - return add().set(value); + return data_.addValue(value, &resources_); } - template + template ::value, int> = 0> bool add(TChar* value) { - return add().set(value); + return data_.addValue(value, &resources_); } - void remove(size_t index) { - detail::VariantData::removeElement(getData(), index, getResourceManager()); - } - template - typename detail::enable_if::value>::type remove( - TChar* key) { + template ::value, int> = 0> + void remove(T index) { + detail::VariantData::removeElement(getData(), size_t(index), + getResourceManager()); + } + template ::value && + !detail::is_const::value, + int> = 0> + void remove(TChar* key) { detail::VariantData::removeMember(getData(), detail::adaptString(key), getResourceManager()); } - template - typename detail::enable_if::value>::type remove( - const TString& key) { + template ::value, int> = 0> + void remove(const TString& key) { detail::VariantData::removeMember(getData(), detail::adaptString(key), getResourceManager()); } + template ::value, int> = 0> + void remove(const TVariant& key) { + if (key.template is()) + remove(key.template as()); + if (key.template is()) + remove(key.template as()); + } operator JsonVariant() { return getVariant(); } @@ -3985,7 +4264,7 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template struct VariantDataVisitor { - typedef TResult result_type; + using result_type = TResult; template TResult visit(const T&) { return TResult(); @@ -3993,7 +4272,7 @@ struct VariantDataVisitor { }; template struct JsonVariantVisitor { - typedef TResult result_type; + using result_type = TResult; template TResult visit(const T&) { return TResult(); @@ -4027,14 +4306,13 @@ typename TVisitor::result_type accept(JsonVariantConst variant, return visit.visit(nullptr); auto resources = VariantAttorney::getResourceManager(variant); VisitorAdapter adapter(visit, resources); - return data->accept(adapter); + return data->accept(adapter, resources); } struct ComparerBase : JsonVariantVisitor {}; template struct Comparer; template -struct Comparer::value>::type> - : ComparerBase { +struct Comparer::value>> : ComparerBase { T rhs; // TODO: store adapted string? explicit Comparer(T value) : rhs(value) {} CompareResult visit(JsonString lhs) { @@ -4055,24 +4333,23 @@ struct Comparer::value>::type> using ComparerBase::visit; }; template -struct Comparer::value || - is_floating_point::value>::type> +struct Comparer< + T, enable_if_t::value || is_floating_point::value>> : ComparerBase { T rhs; explicit Comparer(T value) : rhs(value) {} - CompareResult visit(JsonFloat lhs) { - return arithmeticCompare(lhs, rhs); - } - CompareResult visit(JsonInteger lhs) { - return arithmeticCompare(lhs, rhs); - } - CompareResult visit(JsonUInt lhs) { + template + enable_if_t::value || is_integral::value, + CompareResult> + visit(const U& lhs) { return arithmeticCompare(lhs, rhs); } - CompareResult visit(bool lhs) { - return visit(static_cast(lhs)); + template + enable_if_t::value && !is_integral::value, + CompareResult> + visit(const U& lhs) { + return ComparerBase::visit(lhs); } - using ComparerBase::visit; }; struct NullComparer : ComparerBase { CompareResult visit(nullptr_t) { @@ -4175,8 +4452,8 @@ struct VariantComparer : ComparerBase { } }; template -struct Comparer::value>::type> +struct Comparer< + T, enable_if_t::value>> : VariantComparer { explicit Comparer(const T& value) : VariantComparer(static_cast(value)) {} @@ -4195,6 +4472,13 @@ inline ArrayData::iterator ArrayData::at( } return it; } +inline VariantData* ArrayData::addElement(ResourceManager* resources) { + auto slot = resources->allocVariant(); + if (!slot) + return nullptr; + CollectionData::appendOne(slot, resources); + return slot.ptr(); +} inline VariantData* ArrayData::getOrAddElement(size_t index, ResourceManager* resources) { auto it = createIterator(resources); @@ -4220,23 +4504,39 @@ inline VariantData* ArrayData::getElement( inline void ArrayData::removeElement(size_t index, ResourceManager* resources) { remove(at(index, resources), resources); } +template +inline bool ArrayData::addValue(const T& value, ResourceManager* resources) { + ARDUINOJSON_ASSERT(resources != nullptr); + auto slot = resources->allocVariant(); + if (!slot) + return false; + JsonVariant variant(slot.ptr(), resources); + if (!variant.set(value)) { + resources->freeVariant(slot); + return false; + } + CollectionData::appendOne(slot, resources); + return true; +} +constexpr size_t sizeofArray(size_t n) { + return n * ResourceManager::slotSize; +} ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -template -inline typename detail::enable_if::value, bool>::type -copyArray(const T& src, JsonVariant dst) { +template ::value, int> = 0> +inline bool copyArray(const T& src, JsonVariant dst) { return dst.set(src); } -template -inline typename detail::enable_if< - !detail::is_base_of::value, bool>::type -copyArray(T (&src)[N], const TDestination& dst) { +template ::value, int> = 0> +inline bool copyArray(T (&src)[N], const TDestination& dst) { return copyArray(src, N, dst); } -template -inline typename detail::enable_if< - !detail::is_base_of::value, bool>::type -copyArray(const T* src, size_t len, const TDestination& dst) { +template ::value, int> = 0> +inline bool copyArray(const T* src, size_t len, const TDestination& dst) { bool ok = true; for (size_t i = 0; i < len; i++) { ok &= copyArray(src[i], dst.template add()); @@ -4255,9 +4555,8 @@ template inline bool copyArray(const T* src, size_t len, JsonDocument& dst) { return copyArray(src, len, dst.to()); } -template -inline typename detail::enable_if::value, size_t>::type -copyArray(JsonVariantConst src, T& dst) { +template ::value, int> = 0> +inline size_t copyArray(JsonVariantConst src, T& dst) { dst = src.as(); return 1; } @@ -4283,12 +4582,12 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) { dst[len] = 0; return 1; } -template -inline typename detail::enable_if< - detail::is_array::value && - detail::is_base_of::value, - size_t>::type -copyArray(const TSource& src, T& dst) { +template < + typename TSource, typename T, + detail::enable_if_t::value && + detail::is_base_of::value, + int> = 0> +inline size_t copyArray(const TSource& src, T& dst) { return copyArray(src.template as(), dst); } ARDUINOJSON_END_PUBLIC_NAMESPACE @@ -4329,75 +4628,70 @@ inline T* addPadding(T* p) { size_t address = addPadding(reinterpret_cast(p)); return reinterpret_cast(address); } -inline CollectionIterator::CollectionIterator(VariantSlot* slot, SlotId slotId) +inline CollectionIterator::CollectionIterator(VariantData* slot, SlotId slotId) : slot_(slot), currentId_(slotId) { nextId_ = slot_ ? slot_->next() : NULL_SLOT; } -inline const char* CollectionIterator::key() const { - ARDUINOJSON_ASSERT(slot_ != nullptr); - return slot_->key(); -} -inline void CollectionIterator::setKey(const char* s) { - ARDUINOJSON_ASSERT(slot_ != nullptr); - ARDUINOJSON_ASSERT(s != nullptr); - return slot_->setKey(s); -} -inline void CollectionIterator::setKey(StringNode* s) { - ARDUINOJSON_ASSERT(slot_ != nullptr); - ARDUINOJSON_ASSERT(s != nullptr); - return slot_->setKey(s); -} -inline bool CollectionIterator::ownsKey() const { - ARDUINOJSON_ASSERT(slot_ != nullptr); - return slot_->ownsKey(); -} inline void CollectionIterator::next(const ResourceManager* resources) { ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT); - slot_ = resources->getSlot(nextId_); + slot_ = resources->getVariant(nextId_); currentId_ = nextId_; if (slot_) nextId_ = slot_->next(); } -inline CollectionData::iterator CollectionData::addSlot( - ResourceManager* resources) { - auto slot = resources->allocSlot(); - if (!slot) - return {}; +inline CollectionData::iterator CollectionData::createIterator( + const ResourceManager* resources) const { + return iterator(resources->getVariant(head_), head_); +} +inline void CollectionData::appendOne(Slot slot, + const ResourceManager* resources) { if (tail_ != NULL_SLOT) { - auto tail = resources->getSlot(tail_); + auto tail = resources->getVariant(tail_); tail->setNext(slot.id()); tail_ = slot.id(); } else { head_ = slot.id(); tail_ = slot.id(); } - return iterator(slot, slot.id()); +} +inline void CollectionData::appendPair(Slot key, + Slot value, + const ResourceManager* resources) { + key->setNext(value.id()); + if (tail_ != NULL_SLOT) { + auto tail = resources->getVariant(tail_); + tail->setNext(key.id()); + tail_ = value.id(); + } else { + head_ = key.id(); + tail_ = value.id(); + } } inline void CollectionData::clear(ResourceManager* resources) { auto next = head_; while (next != NULL_SLOT) { auto currId = next; - auto slot = resources->getSlot(next); + auto slot = resources->getVariant(next); next = slot->next(); - releaseSlot(SlotWithId(slot, currId), resources); + resources->freeVariant({slot, currId}); } head_ = NULL_SLOT; tail_ = NULL_SLOT; } -inline SlotWithId CollectionData::getPreviousSlot( - VariantSlot* target, const ResourceManager* resources) const { - auto prev = SlotWithId(); +inline Slot CollectionData::getPreviousSlot( + VariantData* target, const ResourceManager* resources) const { + auto prev = Slot(); auto currentId = head_; while (currentId != NULL_SLOT) { - auto currentSlot = resources->getSlot(currentId); + auto currentSlot = resources->getVariant(currentId); if (currentSlot == target) - return prev; - prev = SlotWithId(currentSlot, currentId); + break; + prev = Slot(currentSlot, currentId); currentId = currentSlot->next(); } - return SlotWithId(); + return prev; } -inline void CollectionData::remove(iterator it, ResourceManager* resources) { +inline void CollectionData::removeOne(iterator it, ResourceManager* resources) { if (it.done()) return; auto curr = it.slot_; @@ -4409,7 +4703,18 @@ inline void CollectionData::remove(iterator it, ResourceManager* resources) { head_ = next; if (next == NULL_SLOT) tail_ = prev.id(); - releaseSlot({it.slot_, it.currentId_}, resources); + resources->freeVariant({it.slot_, it.currentId_}); +} +inline void CollectionData::removePair(ObjectData::iterator it, + ResourceManager* resources) { + if (it.done()) + return; + auto keySlot = it.slot_; + auto valueId = it.nextId_; + auto valueSlot = resources->getVariant(valueId); + keySlot->setNext(valueSlot->next()); + resources->freeVariant({valueSlot, valueId}); + removeOne(it, resources); } inline size_t CollectionData::nesting(const ResourceManager* resources) const { size_t maxChildNesting = 0; @@ -4426,82 +4731,53 @@ inline size_t CollectionData::size(const ResourceManager* resources) const { count++; return count; } -inline void CollectionData::releaseSlot(SlotWithId slot, - ResourceManager* resources) { - if (slot->ownsKey()) - resources->dereferenceString(slot->key()); - slot->data()->setNull(resources); - resources->freeSlot(slot); -} -inline void VariantPool::create(SlotCount cap, Allocator* allocator) { - ARDUINOJSON_ASSERT(cap > 0); - slots_ = - reinterpret_cast(allocator->allocate(slotsToBytes(cap))); - capacity_ = slots_ ? cap : 0; - usage_ = 0; -} -inline void VariantPool::destroy(Allocator* allocator) { - if (slots_) - allocator->deallocate(slots_); - slots_ = nullptr; - capacity_ = 0; - usage_ = 0; -} -inline void VariantPool::shrinkToFit(Allocator* allocator) { - auto newSlots = reinterpret_cast( - allocator->reallocate(slots_, slotsToBytes(usage_))); - if (newSlots) { - slots_ = newSlots; - capacity_ = usage_; - } -} -inline SlotWithId VariantPool::allocSlot() { - if (!slots_) - return {}; - if (usage_ >= capacity_) +inline Slot ResourceManager::allocVariant() { + auto p = variantPools_.allocSlot(allocator_); + if (!p) { + overflowed_ = true; return {}; - auto index = usage_++; - auto slot = &slots_[index]; - return {new (slot) VariantSlot, SlotId(index)}; -} -inline VariantSlot* VariantPool::getSlot(SlotId id) const { - ARDUINOJSON_ASSERT(id < usage_); - return &slots_[id]; -} -inline SlotCount VariantPool::usage() const { - return usage_; + } + return {new (&p->variant) VariantData, p.id()}; } -inline void VariantPool::clear() { - usage_ = 0; +inline void ResourceManager::freeVariant(Slot variant) { + variant->clear(this); + variantPools_.freeSlot({alias_cast(variant.ptr()), variant.id()}); } -inline SlotCount VariantPool::bytesToSlots(size_t n) { - return static_cast(n / sizeof(VariantSlot)); +inline VariantData* ResourceManager::getVariant(SlotId id) const { + return reinterpret_cast(variantPools_.getSlot(id)); } -inline size_t VariantPool::slotsToBytes(SlotCount n) { - return n * sizeof(VariantSlot); +#if ARDUINOJSON_USE_EXTENSIONS +inline Slot ResourceManager::allocExtension() { + auto p = variantPools_.allocSlot(allocator_); + if (!p) { + overflowed_ = true; + return {}; + } + return {&p->extension, p.id()}; } -inline SlotWithId VariantPoolList::allocFromFreeList() { - ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT); - auto id = freeList_; - auto slot = getSlot(freeList_); - freeList_ = slot->next(); - return {new (slot) VariantSlot, id}; +inline void ResourceManager::freeExtension(SlotId id) { + auto p = getExtension(id); + variantPools_.freeSlot({reinterpret_cast(p), id}); } -inline void VariantPoolList::freeSlot(SlotWithId slot) { - slot->setNext(freeList_); - freeList_ = slot.id(); +inline VariantExtension* ResourceManager::getExtension(SlotId id) const { + return &variantPools_.getSlot(id)->extension; } +#endif template inline VariantData* ObjectData::getMember( TAdaptedString key, const ResourceManager* resources) const { - return findKey(key, resources).data(); + auto it = findKey(key, resources); + if (it.done()) + return nullptr; + it.next(resources); + return it.data(); } template VariantData* ObjectData::getOrAddMember(TAdaptedString key, ResourceManager* resources) { - auto it = findKey(key, resources); - if (!it.done()) - return it.data(); + auto data = getMember(key, resources); + if (data) + return data; return addMember(key, resources); } template @@ -4509,9 +4785,11 @@ inline ObjectData::iterator ObjectData::findKey( TAdaptedString key, const ResourceManager* resources) const { if (key.isNull()) return iterator(); + bool isKey = true; for (auto it = createIterator(resources); !it.done(); it.next(resources)) { - if (stringEquals(key, adaptString(it.key()))) + if (isKey && stringEquals(key, adaptString(it->asString()))) return it; + isKey = !isKey; } return iterator(); } @@ -4520,6 +4798,23 @@ inline void ObjectData::removeMember(TAdaptedString key, ResourceManager* resources) { remove(findKey(key, resources), resources); } +template +inline VariantData* ObjectData::addMember(TAdaptedString key, + ResourceManager* resources) { + auto keySlot = resources->allocVariant(); + if (!keySlot) + return nullptr; + auto valueSlot = resources->allocVariant(); + if (!valueSlot) + return nullptr; + if (!keySlot->setString(key, resources)) + return nullptr; + CollectionData::appendPair(keySlot, valueSlot, resources); + return valueSlot.ptr(); +} +constexpr size_t sizeofObject(size_t n) { + return 2 * n * ResourceManager::slotSize; +} class EscapeSequence { public: static char escapeChar(char c) { @@ -4540,68 +4835,72 @@ class EscapeSequence { } } private: - static const char* escapeTable(bool excludeSolidus) { - return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0]; + static const char* escapeTable(bool isSerializing) { + return &"//''\"\"\\\\b\bf\fn\nr\rt\t"[isSerializing ? 4 : 0]; } }; -template struct FloatParts { uint32_t integral; uint32_t decimal; int16_t exponent; int8_t decimalPlaces; - FloatParts(TFloat value) { - uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000; - decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6; - exponent = normalize(value); - integral = uint32_t(value); - for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) { - maxDecimalPart /= 10; - decimalPlaces--; - } - TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart); - decimal = uint32_t(remainder); - remainder = remainder - TFloat(decimal); - decimal += uint32_t(remainder * 2); - if (decimal >= maxDecimalPart) { - decimal = 0; - integral++; - if (exponent && integral >= 10) { - exponent++; - integral = 1; +}; +template +inline int16_t normalize(TFloat& value) { + using traits = FloatTraits; + int16_t powersOf10 = 0; + int8_t index = sizeof(TFloat) == 8 ? 8 : 5; + int bit = 1 << index; + if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value >= traits::positiveBinaryPowersOfTen()[index]) { + value *= traits::negativeBinaryPowersOfTen()[index]; + powersOf10 = int16_t(powersOf10 + bit); } - } - while (decimal % 10 == 0 && decimalPlaces > 0) { - decimal /= 10; - decimalPlaces--; + bit >>= 1; } } - static int16_t normalize(TFloat& value) { - typedef FloatTraits traits; - int16_t powersOf10 = 0; - int8_t index = sizeof(TFloat) == 8 ? 8 : 5; - int bit = 1 << index; - if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { - for (; index >= 0; index--) { - if (value >= traits::positiveBinaryPowersOfTen()[index]) { - value *= traits::negativeBinaryPowersOfTen()[index]; - powersOf10 = int16_t(powersOf10 + bit); - } - bit >>= 1; + if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value < traits::negativeBinaryPowersOfTen()[index] * 10) { + value *= traits::positiveBinaryPowersOfTen()[index]; + powersOf10 = int16_t(powersOf10 - bit); } + bit >>= 1; } - if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { - for (; index >= 0; index--) { - if (value < traits::negativeBinaryPowersOfTen()[index] * 10) { - value *= traits::positiveBinaryPowersOfTen()[index]; - powersOf10 = int16_t(powersOf10 - bit); - } - bit >>= 1; - } + } + return powersOf10; +} +constexpr uint32_t pow10(int exponent) { + return (exponent == 0) ? 1 : 10 * pow10(exponent - 1); +} +inline FloatParts decomposeFloat(JsonFloat value, int8_t decimalPlaces) { + uint32_t maxDecimalPart = pow10(decimalPlaces); + int16_t exponent = normalize(value); + uint32_t integral = uint32_t(value); + for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) { + maxDecimalPart /= 10; + decimalPlaces--; + } + JsonFloat remainder = + (value - JsonFloat(integral)) * JsonFloat(maxDecimalPart); + uint32_t decimal = uint32_t(remainder); + remainder = remainder - JsonFloat(decimal); + decimal += uint32_t(remainder * 2); + if (decimal >= maxDecimalPart) { + decimal = 0; + integral++; + if (exponent && integral >= 10) { + exponent++; + integral = 1; } - return powersOf10; } -}; + while (decimal % 10 == 0 && decimalPlaces > 0) { + decimal /= 10; + decimalPlaces--; + } + return {integral, decimal, exponent, decimalPlaces}; +} template class CountingDecorator { public: @@ -4660,6 +4959,9 @@ class TextFormatter { } template void writeFloat(T value) { + writeFloat(JsonFloat(value), sizeof(T) >= 8 ? 9 : 6); + } + void writeFloat(JsonFloat value, int8_t decimalPlaces) { if (isnan(value)) return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null"); #if ARDUINOJSON_ENABLE_INFINITY @@ -4677,7 +4979,7 @@ class TextFormatter { value = -value; } #endif - FloatParts parts(value); + auto parts = decomposeFloat(value, decimalPlaces); writeInteger(parts.integral); if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces); @@ -4687,8 +4989,8 @@ class TextFormatter { } } template - typename enable_if::value>::type writeInteger(T value) { - typedef typename make_unsigned::type unsigned_type; + enable_if_t::value> writeInteger(T value) { + using unsigned_type = make_unsigned_t; unsigned_type unsigned_value; if (value < 0) { writeRaw('-'); @@ -4699,7 +5001,7 @@ class TextFormatter { writeInteger(unsigned_value); } template - typename enable_if::value>::type writeInteger(T value) { + enable_if_t::value> writeInteger(T value) { char buffer[22]; char* end = buffer + sizeof(buffer); char* begin = end; @@ -4752,9 +5054,10 @@ class DummyWriter { template