From 09e366df958d89de68bfebb387ab898cc7ebeba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 16 Sep 2024 22:02:27 +0300 Subject: [PATCH 01/36] Add SOC candidates to USB printout --- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 22 ++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index d36e4166..7dab03cc 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -26,6 +26,8 @@ static int16_t highest_temperature = 0; static int16_t calc_min_temperature = 0; static int16_t calc_max_temperature = 0; +static uint16_t highprecision_SOC = 0; +static uint16_t lowprecision_SOC = 0; static uint16_t BMS_SOC = 0; static uint16_t BMS_voltage = 0; static int16_t BMS_current = 0; @@ -129,6 +131,14 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.temperature_min_dC = calc_min_temperature * 10; // Add decimals datalayer.battery.status.temperature_max_dC = calc_max_temperature * 10; + //TODO: Remove once confirmed which work + Serial.print("Polled: "); + Serial.println(BMS_SOC); + Serial.print("Highprec: "); + Serial.println(highprecision_SOC); + Serial.print("Lowprec: "); + Serial.println(lowprecision_SOC); + #ifdef DEBUG_VIA_USB #endif @@ -209,16 +219,18 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x444: //9E,01,88,13,64,64,98,65 //9A,01,B6,13,64,64,98,3B //407.5V 18deg //9B,01,B8,13,64,64,98,38 //408.5V 14deg + //lowprecision_SOC = ??? break; case 0x445: //00,98,FF,FF,63,20,4E,98 - Static, values never changes between logs break; case 0x446: //2C,D4,0C,4D,21,DC,0C,9D - 0,1,7th frame varies a lot break; - case 0x447: // Seems to contain more temperatures, highest and lowest? - //06,38,01,3B,E0,03,39,69 - //06,36,02,36,E0,03,36,72, - lowest_temperature = (rx_frame.data.u8[1] - 40); //Best guess for now - highest_temperature = (rx_frame.data.u8[3] - 40); //Best guess for now + case 0x447: // Seems to contain more temperatures, highest and lowest? + //06,38,01,3B,E0,03,39,69 + //06,36,02,36,E0,03,36,72, + highprecision_SOC = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]; // 03 E0 = 992 = 99.2% + lowest_temperature = (rx_frame.data.u8[1] - 40); //Best guess for now + highest_temperature = (rx_frame.data.u8[3] - 40); //Best guess for now break; case 0x47B: //01,FF,FF,FF,FF,FF,FF,FF - Static, values never changes between logs break; From 198e9ff945f6829fd35c23a859e2c50a329e739e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 17 Sep 2024 12:00:04 +0300 Subject: [PATCH 02/36] Add way to not use estimated SOC --- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 18 +++++++----------- Software/src/battery/BYD-ATTO-3-BATTERY.h | 2 ++ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 7dab03cc..a753d261 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -93,10 +93,14 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.voltage_dV = BMS_voltage * 10; } - //datalayer.battery.status.real_soc = BMS_SOC * 100; //TODO: This is not yet found! - // We instead estimate the SOC% based on the battery voltage - // This is a very bad solution, and as soon as an usable SOC% value has been found on CAN, we should switch to that! +#ifdef USE_ESTIMATED_SOC + // When the battery is crashed hard, it locks itself and SOC becomes unavailable. + // We instead estimate the SOC% based on the battery voltage. + // This is a bad solution, you wont be able to use 100% of the battery datalayer.battery.status.real_soc = estimateSOC(datalayer.battery.status.voltage_dV); +#else // Pack is not crashed, we can use periodically transmitted SOC + datalayer.battery.status.real_soc = highprecision_SOC * 10; +#endif datalayer.battery.status.current_dA = -BMS_current; @@ -131,14 +135,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.temperature_min_dC = calc_min_temperature * 10; // Add decimals datalayer.battery.status.temperature_max_dC = calc_max_temperature * 10; - //TODO: Remove once confirmed which work - Serial.print("Polled: "); - Serial.println(BMS_SOC); - Serial.print("Highprec: "); - Serial.println(highprecision_SOC); - Serial.print("Lowprec: "); - Serial.println(lowprecision_SOC); - #ifdef DEBUG_VIA_USB #endif diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.h b/Software/src/battery/BYD-ATTO-3-BATTERY.h index 550975d5..5f4a7d71 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.h +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.h @@ -5,6 +5,8 @@ #define BATTERY_SELECTED #define MAX_CELL_DEVIATION_MV 150 +#define USE_ESTIMATED_SOC // If enabled, SOC is estimated from pack voltage. Useful for locked packs. \ + // Uncomment this if you know your BMS is unlocked and able to send SOC% void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); From 774c544bca3093c47cb78b56f4932fab7ced9edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 29 Oct 2024 20:38:24 +0200 Subject: [PATCH 03/36] Add contactor opening incase of FAULT --- Software/src/battery/TESLA-BATTERY.cpp | 33 ++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index a35751d9..3eac62cc 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -22,7 +22,7 @@ CAN_frame TESLA_221_2 = { .DLC = 8, .ID = 0x221, .data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive - +static uint16_t sendContactorClosingMessagesStill = 300; static uint32_t battery_total_discharge = 0; static uint32_t battery_total_charge = 0; static uint16_t battery_volts = 0; // V @@ -1003,7 +1003,7 @@ unsigned long lastSend118 = 0; int index_1CF = 0; int index_118 = 0; -#endif +#endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) void send_can_battery() { /*From bielec: My fist 221 message, to close the contactors is 0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96 and then, @@ -1014,13 +1014,13 @@ the first, for a few cycles, then stop all messages which causes the contactor unsigned long currentMillis = millis(); #if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) - if (datalayer.system.status.inverter_allows_contactor_closing) { + if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { if (currentMillis - lastSend1CF >= 10) { transmit_can(&can_msg_1CF[index_1CF], can_config.battery); #ifdef DOUBLE_BATTERY transmit_can(&can_msg_1CF[index_1CF], can_config.battery_double); -#endif +#endif // DOUBLE_BATTERY index_1CF = (index_1CF + 1) % 8; lastSend1CF = currentMillis; @@ -1030,7 +1030,7 @@ the first, for a few cycles, then stop all messages which causes the contactor transmit_can(&can_msg_118[index_118], can_config.battery); #ifdef DOUBLE_BATTERY transmit_can(&can_msg_1CF[index_1CF], can_config.battery_double); -#endif +#endif //DOUBLE_BATTERY index_118 = (index_118 + 1) % 16; lastSend118 = currentMillis; @@ -1039,7 +1039,7 @@ the first, for a few cycles, then stop all messages which causes the contactor index_1CF = 0; index_118 = 0; } -#endif +#endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) //Send 30ms message if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { @@ -1051,15 +1051,26 @@ the first, for a few cycles, then stop all messages which causes the contactor } previousMillis30 = currentMillis; - if (datalayer.system.status.inverter_allows_contactor_closing) { + if ((datalayer.system.status.inverter_allows_contactor_closing == true) && + (datalayer.battery.status.bms_status != FAULT)) { + sendContactorClosingMessagesStill = 300; transmit_can(&TESLA_221_1, can_config.battery); transmit_can(&TESLA_221_2, can_config.battery); #ifdef DOUBLE_BATTERY if (datalayer.system.status.battery2_allows_contactor_closing) { - transmit_can(&TESLA_221_1, can_config.battery_double); // CAN2 connected to battery 2 + transmit_can(&TESLA_221_1, can_config.battery_double); transmit_can(&TESLA_221_2, can_config.battery_double); } +#endif //DOUBLE_BATTERY + } else { // Faulted state, or inverter blocks contactor closing + if (sendContactorClosingMessagesStill > 0) { + transmit_can(&TESLA_221_1, can_config.battery); + sendContactorClosingMessagesStill--; + +#ifdef DOUBLE_BATTERY + transmit_can(&TESLA_221_1, can_config.battery_double); #endif //DOUBLE_BATTERY + } } } } @@ -1091,7 +1102,8 @@ void printFaultCodesIfActive() { } if (datalayer.system.status.inverter_allows_contactor_closing == false) { Serial.println( - "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter OR " + "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter " + "OR " "disable the inverter protocol to proceed with contactor closing"); } // Check each symbol and print debug information if its value is 1 @@ -1166,7 +1178,8 @@ void printFaultCodesIfActive_battery2() { } if (datalayer.system.status.inverter_allows_contactor_closing == false) { Serial.println( - "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter OR " + "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter " + "OR " "disable the inverter protocol to proceed with contactor closing"); } // Check each symbol and print debug information if its value is 1 From 16fc2fb4f17378e2f207db255f9ca167f6aace26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 3 Nov 2024 13:31:56 +0200 Subject: [PATCH 04/36] Add degradation data reset for LEAF --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 306 +++++++++++++++++- Software/src/battery/NISSAN-LEAF-BATTERY.h | 8 + Software/src/datalayer/datalayer_extended.h | 12 + .../webserver/advanced_battery_html.cpp | 13 + Software/src/devboard/webserver/webserver.cpp | 10 + 5 files changed, 348 insertions(+), 1 deletion(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 67bb21f9..7c48fe37 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -174,6 +174,18 @@ static int16_t battery2_temp_polled_max = 0; static int16_t battery2_temp_polled_min = 0; #endif // DOUBLE_BATTERY +// Clear SOH values +static uint8_t stateMachineClearSOH = 0xFF; +static uint32_t incomingChallenge = 0xFFFFFFFF; +static uint8_t solvedChallenge[8]; +static bool challengeFailed = false; + +CAN_frame LEAF_CLEAR_SOH = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x79B, + .data = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; + void print_with_units(char* header, int value, char* units) { Serial.print(header); Serial.print(value); @@ -337,6 +349,18 @@ void update_values_battery() { /* This function maps all the values fetched via datalayer_extended.nissanleaf.HeatingStop = battery_Heating_Stop; datalayer_extended.nissanleaf.HeatingStart = battery_Heating_Start; datalayer_extended.nissanleaf.HeaterSendRequest = battery_Batt_Heater_Mail_Send_Request; + datalayer_extended.nissanleaf.CryptoChallenge = incomingChallenge; + datalayer_extended.nissanleaf.SolvedChallengeMSB = + ((solvedChallenge[7] << 24) | (solvedChallenge[6] << 16) | (solvedChallenge[5] << 8) | solvedChallenge[4]); + datalayer_extended.nissanleaf.SolvedChallengeLSB = + ((solvedChallenge[3] << 24) | (solvedChallenge[2] << 16) | (solvedChallenge[1] << 8) | solvedChallenge[0]); + + // Update requests from webserver datalayer + if (datalayer_extended.nissanleaf.UserRequestSOHreset) { + Serial.println("REQUEST FROM WEBSERVER"); + stateMachineClearSOH = 0; //Start the statemachine + datalayer_extended.nissanleaf.UserRequestSOHreset = false; + } /*Finally print out values to serial if configured to do so*/ #ifdef DEBUG_VIA_USB @@ -610,7 +634,7 @@ void receive_can_battery2(CAN_frame rx_frame) { } } - if (stop_battery_query) { //Leafspy is active, stop our own polling + if (stop_battery_query) { //Leafspy/Service request is active, stop our own polling break; } @@ -847,6 +871,34 @@ void receive_can_battery(CAN_frame rx_frame) { hold_off_with_polling_10seconds = 10; //Polling is paused for 100s break; case 0x7BB: + + // This section checks if we are doing a SOH reset towards BMS + if (stateMachineClearSOH < 255) { + //Intercept the messages based on state machine + if (rx_frame.data.u8[0] == 0x06) { // Incoming challenge data! + incomingChallenge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[4] << 16) | (rx_frame.data.u8[5] << 8) | + rx_frame.data.u8[6]); + } + //Error checking + if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F)) { + challengeFailed = true; + Serial.print("Challenge solving failed"); + } + // All CAN messages recieved from BMS will be logged via serial during development of this function + Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D + Serial.print(" "); + Serial.print(rx_frame.ID, HEX); + Serial.print(" "); + Serial.print(rx_frame.DLC); + Serial.print(" "); + for (int i = 0; i < rx_frame.DLC; ++i) { + Serial.print(rx_frame.data.u8[i], HEX); + Serial.print(" "); + } + Serial.println(""); + 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]; @@ -1127,6 +1179,10 @@ void send_can_battery() { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; + if (stateMachineClearSOH < 255) { // Enter the ClearSOH statemachine only if we request it + clearSOH(); + } + //When battery requests heating pack status change, ack this if (battery_Batt_Heater_Mail_Send_Request) { LEAF_50B.data.u8[6] = 0x20; //Batt_Heater_Mail_Send_OK @@ -1230,6 +1286,254 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature) { //This function feels horrib return static_cast(1094 + (309 - temperature) * 2.5714285714285715); } +void clearSOH(void) { + + stop_battery_query = true; + hold_off_with_polling_10seconds = 10; // Active battery polling is paused for 100 seconds + + switch (stateMachineClearSOH) { + case 0: // Wait until polling actually stops + stateMachineClearSOH = 1; + break; + case 1: // Set CAN_PROCESS_FLAG to 0xC0 + LEAF_CLEAR_SOH.data.u8[0] = 0x02; + LEAF_CLEAR_SOH.data.u8[1] = 0x10; + LEAF_CLEAR_SOH.data.u8[2] = 0xC0; + LEAF_CLEAR_SOH.data.u8[3] = 0x00; + LEAF_CLEAR_SOH.data.u8[4] = 0x00; + LEAF_CLEAR_SOH.data.u8[5] = 0x00; + LEAF_CLEAR_SOH.data.u8[6] = 0x00; + LEAF_CLEAR_SOH.data.u8[7] = 0x00; + transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + // BMS should reply 02 50 C0 FF FF FF FF FF + stateMachineClearSOH = 2; + break; + case 2: // Set something ? + LEAF_CLEAR_SOH.data.u8[0] = 0x02; + LEAF_CLEAR_SOH.data.u8[1] = 0x3E; + LEAF_CLEAR_SOH.data.u8[2] = 0x01; + LEAF_CLEAR_SOH.data.u8[3] = 0x00; + LEAF_CLEAR_SOH.data.u8[4] = 0x00; + LEAF_CLEAR_SOH.data.u8[5] = 0x00; + LEAF_CLEAR_SOH.data.u8[6] = 0x00; + LEAF_CLEAR_SOH.data.u8[7] = 0x00; + transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + // BMS should reply 7E FF FF FF FF FF FF + stateMachineClearSOH = 3; + break; + case 3: // Request challenge to solve + LEAF_CLEAR_SOH.data.u8[0] = 0x02; + LEAF_CLEAR_SOH.data.u8[1] = 0x27; + LEAF_CLEAR_SOH.data.u8[2] = 0x65; + LEAF_CLEAR_SOH.data.u8[3] = 0x00; + LEAF_CLEAR_SOH.data.u8[4] = 0x00; + LEAF_CLEAR_SOH.data.u8[5] = 0x00; + LEAF_CLEAR_SOH.data.u8[6] = 0x00; + LEAF_CLEAR_SOH.data.u8[7] = 0x00; + transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + stateMachineClearSOH = 4; + break; + case 4: // Send back decoded challenge data + decodeChallengeData(incomingChallenge, solvedChallenge); + LEAF_CLEAR_SOH.data.u8[0] = 0x10; + LEAF_CLEAR_SOH.data.u8[1] = 0x0A; + LEAF_CLEAR_SOH.data.u8[2] = 0x27; + LEAF_CLEAR_SOH.data.u8[3] = 0x66; + LEAF_CLEAR_SOH.data.u8[4] = 0x77; + LEAF_CLEAR_SOH.data.u8[5] = solvedChallenge[0]; + LEAF_CLEAR_SOH.data.u8[6] = solvedChallenge[1]; + LEAF_CLEAR_SOH.data.u8[7] = solvedChallenge[2]; + transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + // BMS should reply 7BB 8 30 01 00 FF FF FF FF FF // Proceed with more data (PID ACK) + stateMachineClearSOH = 5; + break; + case 5: // Reply with even more decoded challenge data + LEAF_CLEAR_SOH.data.u8[0] = solvedChallenge[3]; + LEAF_CLEAR_SOH.data.u8[1] = solvedChallenge[4]; + LEAF_CLEAR_SOH.data.u8[2] = solvedChallenge[5]; + LEAF_CLEAR_SOH.data.u8[3] = solvedChallenge[6]; + LEAF_CLEAR_SOH.data.u8[4] = solvedChallenge[7]; + LEAF_CLEAR_SOH.data.u8[5] = 0x00; + LEAF_CLEAR_SOH.data.u8[6] = 0x00; + LEAF_CLEAR_SOH.data.u8[7] = 0x00; + transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + // BMS should reply 02 67 66 FF FF FF FF FF // Thank you for the data + stateMachineClearSOH = 6; + break; + case 6: // Check if solved data was OK + LEAF_CLEAR_SOH.data.u8[0] = 0x03; + LEAF_CLEAR_SOH.data.u8[1] = 0x31; + LEAF_CLEAR_SOH.data.u8[2] = 0x03; + LEAF_CLEAR_SOH.data.u8[3] = 0x00; + LEAF_CLEAR_SOH.data.u8[4] = 0x00; + LEAF_CLEAR_SOH.data.u8[5] = 0x00; + LEAF_CLEAR_SOH.data.u8[6] = 0x00; + LEAF_CLEAR_SOH.data.u8[7] = 0x00; + transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + //7BB 8 03 71 03 01 FF FF FF FF // If all is well, BMS replies with 03 71 03 01. + //Incase you sent wrong challenge, you get 03 7f 31 12 + stateMachineClearSOH = 7; + break; + case 7: // Reset SOH% request + LEAF_CLEAR_SOH.data.u8[0] = 0x03; + LEAF_CLEAR_SOH.data.u8[1] = 0x31; + LEAF_CLEAR_SOH.data.u8[2] = 0x03; + LEAF_CLEAR_SOH.data.u8[3] = 0x01; + LEAF_CLEAR_SOH.data.u8[4] = 0x00; + LEAF_CLEAR_SOH.data.u8[5] = 0x00; + LEAF_CLEAR_SOH.data.u8[6] = 0x00; + LEAF_CLEAR_SOH.data.u8[7] = 0x00; + transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + //7BB 8 03 71 03 02 FF FF FF FF // 03 71 03 02 means that BMS accepted command. + //7BB 03 7f 31 12 means your challenge was wrong, so command ignored + stateMachineClearSOH = 8; + break; + case 8: // Please proceed with resetting SOH + LEAF_CLEAR_SOH.data.u8[0] = 0x02; + LEAF_CLEAR_SOH.data.u8[1] = 0x10; + LEAF_CLEAR_SOH.data.u8[2] = 0x81; + LEAF_CLEAR_SOH.data.u8[3] = 0x00; + LEAF_CLEAR_SOH.data.u8[4] = 0x00; + LEAF_CLEAR_SOH.data.u8[5] = 0x00; + LEAF_CLEAR_SOH.data.u8[6] = 0x00; + LEAF_CLEAR_SOH.data.u8[7] = 0x00; + transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + // 7BB 8 02 50 81 FF FF FF FF FF // SOH reset OK + stateMachineClearSOH = 255; + break; + default: + break; + } +} + +uint32_t CyclicXorHash16Bit(uint32_t param_1, uint32_t param_2) { + bool bVar1; + uint32_t uVar2; + uint32_t uVar3; + uint32_t uVar4; + uint32_t uVar5; + uint32_t uVar6; + uint32_t uVar7; + uint32_t uVar8; + uint32_t uVar9; + uint32_t uVar10; + uint32_t uVar11; + uint32_t iVar12; + + param_1 = param_1 & 0xffff; + param_2 = param_2 & 0xffff; + uVar10 = 0xffff; + iVar12 = 2; + do { + uVar2 = param_2; + if ((param_1 & 1) == 1) { + uVar2 = param_1 >> 1; + } + uVar3 = param_2; + if ((param_1 >> 1 & 1) == 1) { + uVar3 = param_1 >> 2; + } + uVar4 = param_2; + if ((param_1 >> 2 & 1) == 1) { + uVar4 = param_1 >> 3; + } + uVar5 = param_2; + if ((param_1 >> 3 & 1) == 1) { + uVar5 = param_1 >> 4; + } + uVar6 = param_2; + if ((param_1 >> 4 & 1) == 1) { + uVar6 = param_1 >> 5; + } + uVar7 = param_2; + if ((param_1 >> 5 & 1) == 1) { + uVar7 = param_1 >> 6; + } + uVar11 = param_1 >> 7; + uVar8 = param_2; + if ((param_1 >> 6 & 1) == 1) { + uVar8 = uVar11; + } + param_1 = param_1 >> 8; + uVar9 = param_2; + if ((uVar11 & 1) == 1) { + uVar9 = param_1; + } + uVar10 = + (((((((((((((((uVar10 & 0x7fff) << 1 ^ uVar2) & 0x7fff) << 1 ^ uVar3) & 0x7fff) << 1 ^ uVar4) & 0x7fff) << 1 ^ + uVar5) & + 0x7fff) + << 1 ^ + uVar6) & + 0x7fff) + << 1 ^ + uVar7) & + 0x7fff) + << 1 ^ + uVar8) & + 0x7fff) + << 1 ^ + uVar9; + bVar1 = iVar12 != 1; + iVar12 = iVar12 + -1; + } while (bVar1); + return uVar10; +} + +uint32_t ComputeMaskedXorProduct(uint32_t param_1, uint32_t param_2, uint32_t param_3) { + return (param_3 ^ 0x780 | param_2 ^ 0x116) * ((param_1 & 0xffff) >> 8 ^ param_1 & 0xff) & 0xffff; +} + +short ShortMaskedSumAndProduct(short param_1, short param_2) { + unsigned short uVar1; + + uVar1 = param_2 + param_1 * 0x5ba & 0xff; + return (uVar1 + param_1) * (uVar1 + param_2); +} + +uint32_t MaskedBitwiseRotateMultiply(uint32_t param_1, uint32_t param_2) { + uint32_t uVar1; + + param_1 = param_1 & 0xffff; + param_2 = param_2 & 0xffff; + uVar1 = param_2 & (param_1 | 0x5ba) & 0xf; + return ((uint32_t)param_1 >> uVar1 | param_1 << (0x10 - uVar1 & 0x1f)) * + (param_2 << uVar1 | (uint32_t)param_2 >> (0x10 - uVar1 & 0x1f)) & + 0xffff; +} + +uint32_t CryptAlgo(uint32_t param_1, uint32_t param_2, uint32_t param_3) { + uint32_t uVar1; + uint32_t uVar2; + uint32_t iVar3; + uint32_t iVar4; + + uVar1 = MaskedBitwiseRotateMultiply(param_2, param_3); + uVar2 = ShortMaskedSumAndProduct(param_2, param_3); + uVar1 = ComputeMaskedXorProduct(param_1, uVar1, uVar2); + uVar2 = ComputeMaskedXorProduct(param_1, uVar2, uVar1); + iVar3 = CyclicXorHash16Bit(uVar1, 0xffc4); + iVar4 = CyclicXorHash16Bit(uVar2, 0xffc4); + return iVar4 + iVar3 * 0x10000; +} + +void decodeChallengeData(uint32_t incomingChallenge, unsigned char* solvedChallenge) { + uint32_t uVar1; + uint32_t uVar2; + + uVar1 = CryptAlgo(0x609, 0xDD2, incomingChallenge >> 0x10); + uVar2 = CryptAlgo(incomingChallenge & 0xffff, incomingChallenge >> 0x10, 0x609); + *solvedChallenge = (unsigned char)uVar1; + solvedChallenge[1] = (unsigned char)uVar2; + solvedChallenge[2] = (unsigned char)((uint32_t)uVar2 >> 8); + solvedChallenge[3] = (unsigned char)((uint32_t)uVar1 >> 8); + solvedChallenge[4] = (unsigned char)((uint32_t)uVar2 >> 16); + solvedChallenge[5] = (unsigned char)((uint32_t)uVar1 >> 16); + solvedChallenge[6] = (unsigned char)((uint32_t)uVar2 >> 24); + solvedChallenge[7] = (unsigned char)((uint32_t)uVar1 >> 24); + return; +} + void setup_battery(void) { // Performs one time setup at startup #ifdef DEBUG_VIA_USB Serial.println("Nissan LEAF battery selected"); diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.h b/Software/src/battery/NISSAN-LEAF-BATTERY.h index 89ff4443..2d29c0d7 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.h +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.h @@ -14,5 +14,13 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature); bool is_message_corrupt(CAN_frame rx_frame); void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); +void clearSOH(void); +//Cryptographic functions +void decodeChallengeData(uint32_t incomingChallenge, unsigned char* solvedChallenge); +uint32_t CyclicXorHash16Bit(uint32_t param_1, uint32_t param_2); +uint32_t ComputeMaskedXorProduct(uint32_t param_1, uint32_t param_2, uint32_t param_3); +short ShortMaskedSumAndProduct(short param_1, short param_2); +uint32_t MaskedBitwiseRotateMultiply(uint32_t param_1, uint32_t param_2); +uint32_t CryptAlgo(uint32_t param_1, uint32_t param_2, uint32_t param_3); #endif diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index e1ed206c..fb4df944 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -198,6 +198,18 @@ typedef struct { /** bool */ /** Heat request sent*/ bool HeaterSendRequest = false; + /** bool */ + /** User requesting SOH reset via WebUI*/ + bool UserRequestSOHreset = false; + /** uint32_t */ + /** Cryptographic challenge to be solved */ + uint32_t CryptoChallenge = 0; + /** uint32_t */ + /** Solution for crypto challenge, MSBs */ + uint32_t SolvedChallengeMSB = 0; + /** uint32_t */ + /** Solution for crypto challenge, LSBs */ + uint32_t SolvedChallengeLSB = 0; } DATALAYER_INFO_NISSAN_LEAF; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 9718f61e..40b86f01 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -292,6 +292,10 @@ String advanced_battery_processor(const String& var) { content += "

Heating stopped: " + String(datalayer_extended.nissanleaf.HeatingStop) + "

"; content += "

Heating started: " + String(datalayer_extended.nissanleaf.HeatingStart) + "

"; content += "

Heating requested: " + String(datalayer_extended.nissanleaf.HeaterSendRequest) + "

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

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

"; + content += "

SolvedChallenge: " + String(datalayer_extended.nissanleaf.SolvedChallengeMSB) + + String(datalayer_extended.nissanleaf.SolvedChallengeLSB) + "

"; #endif #if !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ @@ -302,6 +306,15 @@ String advanced_battery_processor(const String& var) { content += ""; content += ""; return content; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 52568271..63cd2571 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -1,6 +1,7 @@ #include "webserver.h" #include #include "../../datalayer/datalayer.h" +#include "../../datalayer/datalayer_extended.h" #include "../../lib/bblanchon-ArduinoJson/ArduinoJson.h" #include "../utils/events.h" #include "../utils/led_handler.h" @@ -231,6 +232,15 @@ void init_webserver() { } }); + // 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)) { + return request->requestAuthentication(); + } + datalayer_extended.nissanleaf.UserRequestSOHreset = true; + request->send(200, "text/plain", "Updated successfully"); + }); + #ifdef TEST_FAKE_BATTERY // Route for editing FakeBatteryVoltage server.on("/updateFakeBatteryVoltage", HTTP_GET, [](AsyncWebServerRequest* request) { From a2deca0f20ade19e79ce9170c4ae079d4b63dbb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 3 Nov 2024 19:36:52 +0200 Subject: [PATCH 05/36] Added info to webserver incase challenge failed --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 3 ++- Software/src/datalayer/datalayer_extended.h | 3 +++ Software/src/devboard/webserver/advanced_battery_html.cpp | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 7c48fe37..5c39dfd9 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -354,6 +354,7 @@ void update_values_battery() { /* This function maps all the values fetched via ((solvedChallenge[7] << 24) | (solvedChallenge[6] << 16) | (solvedChallenge[5] << 8) | solvedChallenge[4]); datalayer_extended.nissanleaf.SolvedChallengeLSB = ((solvedChallenge[3] << 24) | (solvedChallenge[2] << 16) | (solvedChallenge[1] << 8) | solvedChallenge[0]); + datalayer_extended.nissanleaf.challengeFailed = challengeFailed; // Update requests from webserver datalayer if (datalayer_extended.nissanleaf.UserRequestSOHreset) { @@ -1287,7 +1288,7 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature) { //This function feels horrib } void clearSOH(void) { - + challengeFailed = false; stop_battery_query = true; hold_off_with_polling_10seconds = 10; // Active battery polling is paused for 100 seconds diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index fb4df944..626cd8db 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -201,6 +201,9 @@ typedef struct { /** bool */ /** User requesting SOH reset via WebUI*/ bool UserRequestSOHreset = false; + /** bool */ + /** True if the crypto challenge response from BMS is signalling a failed attempt*/ + bool challengeFailed = false; /** uint32_t */ /** Cryptographic challenge to be solved */ uint32_t CryptoChallenge = 0; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 40b86f01..d15654b8 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -296,6 +296,7 @@ String advanced_battery_processor(const String& var) { content += "

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

"; content += "

SolvedChallenge: " + String(datalayer_extended.nissanleaf.SolvedChallengeMSB) + String(datalayer_extended.nissanleaf.SolvedChallengeLSB) + "

"; + content += "

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

"; #endif #if !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ From 3a9426dcf25c75f211fbd51ee3496fd4bf49f6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 3 Nov 2024 20:03:11 +0200 Subject: [PATCH 06/36] chage from 66 to 65 PID --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 5c39dfd9..dd0822d7 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1325,7 +1325,7 @@ void clearSOH(void) { case 3: // Request challenge to solve LEAF_CLEAR_SOH.data.u8[0] = 0x02; LEAF_CLEAR_SOH.data.u8[1] = 0x27; - LEAF_CLEAR_SOH.data.u8[2] = 0x65; + LEAF_CLEAR_SOH.data.u8[2] = 0x65; // 0x66 on 24kWh? LEAF_CLEAR_SOH.data.u8[3] = 0x00; LEAF_CLEAR_SOH.data.u8[4] = 0x00; LEAF_CLEAR_SOH.data.u8[5] = 0x00; @@ -1339,7 +1339,7 @@ void clearSOH(void) { LEAF_CLEAR_SOH.data.u8[0] = 0x10; LEAF_CLEAR_SOH.data.u8[1] = 0x0A; LEAF_CLEAR_SOH.data.u8[2] = 0x27; - LEAF_CLEAR_SOH.data.u8[3] = 0x66; + LEAF_CLEAR_SOH.data.u8[3] = 0x65; // 0x66 on 24kWh? LEAF_CLEAR_SOH.data.u8[4] = 0x77; LEAF_CLEAR_SOH.data.u8[5] = solvedChallenge[0]; LEAF_CLEAR_SOH.data.u8[6] = solvedChallenge[1]; From 362a57b6dc88d819f2cd78873309d7dcb19c0129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 3 Nov 2024 22:22:59 +0200 Subject: [PATCH 07/36] Added logging for CAN sending --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index dd0822d7..76bf7e13 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1288,12 +1288,12 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature) { //This function feels horrib } void clearSOH(void) { - challengeFailed = false; stop_battery_query = true; hold_off_with_polling_10seconds = 10; // Active battery polling is paused for 100 seconds switch (stateMachineClearSOH) { case 0: // Wait until polling actually stops + challengeFailed = false; stateMachineClearSOH = 1; break; case 1: // Set CAN_PROCESS_FLAG to 0xC0 @@ -1325,7 +1325,7 @@ void clearSOH(void) { case 3: // Request challenge to solve LEAF_CLEAR_SOH.data.u8[0] = 0x02; LEAF_CLEAR_SOH.data.u8[1] = 0x27; - LEAF_CLEAR_SOH.data.u8[2] = 0x65; // 0x66 on 24kWh? + LEAF_CLEAR_SOH.data.u8[2] = 0x65; LEAF_CLEAR_SOH.data.u8[3] = 0x00; LEAF_CLEAR_SOH.data.u8[4] = 0x00; LEAF_CLEAR_SOH.data.u8[5] = 0x00; @@ -1339,7 +1339,7 @@ void clearSOH(void) { LEAF_CLEAR_SOH.data.u8[0] = 0x10; LEAF_CLEAR_SOH.data.u8[1] = 0x0A; LEAF_CLEAR_SOH.data.u8[2] = 0x27; - LEAF_CLEAR_SOH.data.u8[3] = 0x65; // 0x66 on 24kWh? + LEAF_CLEAR_SOH.data.u8[3] = 0x66; LEAF_CLEAR_SOH.data.u8[4] = 0x77; LEAF_CLEAR_SOH.data.u8[5] = solvedChallenge[0]; LEAF_CLEAR_SOH.data.u8[6] = solvedChallenge[1]; @@ -1405,6 +1405,18 @@ void clearSOH(void) { default: break; } + // All CAN messages semt will be logged via serial during development of this function + Serial.print(millis()); // Example printout, time, ID, length, data: 7553 7B9 8 FF C0 B9 EA 0 0 2 5D + Serial.print(" "); + Serial.print(LEAF_CLEAR_SOH.ID, HEX); + Serial.print(" "); + Serial.print(LEAF_CLEAR_SOH.DLC); + Serial.print(" "); + for (int i = 0; i < LEAF_CLEAR_SOH.DLC; ++i) { + Serial.print(LEAF_CLEAR_SOH.data.u8[i], HEX); + Serial.print(" "); + } + Serial.println(""); } uint32_t CyclicXorHash16Bit(uint32_t param_1, uint32_t param_2) { From 9051293c43887253f7f8fec256e9bc7460c7864a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 6 Nov 2024 15:57:20 +0200 Subject: [PATCH 08/36] Update BYD FW to 3.29 --- Software/src/inverter/BYD-CAN.cpp | 14 +++++++------- Software/src/inverter/BYD-CAN.h | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index 82527469..a2cf2d44 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -15,13 +15,13 @@ static uint8_t char5_151 = 0; static uint8_t char6_151 = 0; static uint8_t char7_151 = 0; -CAN_frame BYD_250 = { - .FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x250, - .data = {0x03, 0x16, 0x00, 0x66, (uint8_t)((BATTERY_WH_MAX / 100) >> 8), (uint8_t)(BATTERY_WH_MAX / 100), 0x02, - 0x09}}; //3.16 FW , Capacity kWh byte4&5 (example 24kWh = 240) +CAN_frame BYD_250 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x250, + .data = {FW_MAJOR_VERSION, FW_MINOR_VERSION, 0x00, 0x66, (uint8_t)((BATTERY_WH_MAX / 100) >> 8), + (uint8_t)(BATTERY_WH_MAX / 100), 0x02, + 0x09}}; //0-1 FW version , Capacity kWh byte4&5 (example 24kWh = 240) CAN_frame BYD_290 = {.FD = false, .ext_ID = false, .DLC = 8, diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index 198f10bb..6a45317b 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -3,6 +3,8 @@ #include "../include.h" #define CAN_INVERTER_SELECTED +#define FW_MAJOR_VERSION 0x03 +#define FW_MINOR_VERSION 0x29 void send_intial_data(); void transmit_can(CAN_frame* tx_frame, int interface); From e293d5dcce9145a6650080fee82870b046fe6e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 8 Nov 2024 10:11:31 +0200 Subject: [PATCH 09/36] Add initial HAL for v0.1 3LB --- Software/USER_SETTINGS.h | 1 + Software/src/devboard/hal/hal.h | 4 +- Software/src/devboard/hal/hw_3LB.h | 106 ++++++++++++++++++ Software/src/devboard/webserver/webserver.cpp | 3 + 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 Software/src/devboard/hal/hw_3LB.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 242c1264..8085999f 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -49,6 +49,7 @@ /* Select hardware used for Battery-Emulator */ #define HW_LILYGO //#define HW_STARK +//#define HW_3LB /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) diff --git a/Software/src/devboard/hal/hal.h b/Software/src/devboard/hal/hal.h index 5e904d89..dc3240ce 100644 --- a/Software/src/devboard/hal/hal.h +++ b/Software/src/devboard/hal/hal.h @@ -7,8 +7,8 @@ #include "hw_lilygo.h" #elif defined(HW_STARK) #include "hw_stark.h" -#elif defined(HW_SJB_V1) -#include "hw_sjb_v1.h" +#elif defined(HW_3LB) +#include "hw_3LB.h" #endif #endif diff --git a/Software/src/devboard/hal/hw_3LB.h b/Software/src/devboard/hal/hw_3LB.h new file mode 100644 index 00000000..137d83f3 --- /dev/null +++ b/Software/src/devboard/hal/hw_3LB.h @@ -0,0 +1,106 @@ +#ifndef __HW_3LB_H__ +#define __HW_3LB_H__ + +// Board boot-up time +#define BOOTUP_TIME 1000 // Time in ms it takes before system is considered fully started up + +// Core assignment +#define CORE_FUNCTION_CORE 1 +#define MODBUS_CORE 0 +#define WIFI_CORE 0 + +// RS485 +//#define PIN_5V_EN 16 +//#define RS485_EN_PIN 17 // 17 /RE +#define RS485_TX_PIN 1 // 21 +#define RS485_RX_PIN 3 // 22 +//#define RS485_SE_PIN 19 // 22 /SHDN + +// CAN settings. CAN_2 is not defined as it can be either MCP2515 or MCP2517, defined by the user settings +#define CAN_1_TYPE ESP32CAN + +// CAN1 PIN mappings, do not change these unless you are adding on extra hardware to the PCB +#define CAN_TX_PIN GPIO_NUM_27 +#define CAN_RX_PIN GPIO_NUM_26 +//#define CAN_SE_PIN 23 + +// CAN2 defines below + +// DUAL_CAN defines +#define MCP2515_SCK 12 // SCK input of MCP2515 +#define MCP2515_MOSI 5 // SDI input of MCP2515 +#define MCP2515_MISO 34 // SDO output of MCP2515 | Pin 34 is input only, without pullup/down resistors +#define MCP2515_CS 18 // CS input of MCP2515 +#define MCP2515_INT 35 // INT output of MCP2515 | | Pin 35 is input only, without pullup/down resistors + +// CAN_FD defines +#define MCP2517_SCK 17 // SCK input of MCP2517 +#define MCP2517_SDI 23 // SDI input of MCP2517 +#define MCP2517_SDO 39 // SDO output of MCP2517 +#define MCP2517_CS 21 // CS input of MCP2517 //21 or 22 +#define MCP2517_INT 34 // INT output of MCP2517 //34 or 35 + +// CHAdeMO support pin dependencies +#define CHADEMO_PIN_2 12 +#define CHADEMO_PIN_10 5 +#define CHADEMO_PIN_7 34 +#define CHADEMO_PIN_4 35 +#define CHADEMO_LOCK 18 + +// Contactor handling +#define POSITIVE_CONTACTOR_PIN 32 +#define NEGATIVE_CONTACTOR_PIN 33 +#define PRECHARGE_PIN 25 + +#define 2ND_POSITIVE_CONTACTOR_PIN 13 +#define 2ND_NEGATIVE_CONTACTOR_PIN 16 +#define 2ND_PRECHARGE_PIN 18 + +// SMA CAN contactor pins +#define INVERTER_CONTACTOR_ENABLE_PIN 36 + +// SD card +//#define SD_MISO_PIN 2 +//#define SD_MOSI_PIN 15 +//#define SD_SCLK_PIN 14 +//#define SD_CS_PIN 13 + +// LED +#define LED_PIN 4 +#define LED_MAX_BRIGHTNESS 40 + +// Equipment stop pin +#define EQUIPMENT_STOP_PIN 35 + +/* ----- Error checks below, don't change (can't be moved to separate file) ----- */ +#ifndef HW_CONFIGURED +#define HW_CONFIGURED +#else +#error Multiple HW defined! Please select a single HW +#endif + +#ifdef CHADEMO_BATTERY +#ifdef DUAL_CAN +#error CHADEMO and DUAL_CAN cannot coexist due to overlapping GPIO pin usage +#endif +#endif + +#ifdef EQUIPMENT_STOP_BUTTON +#ifdef DUAL_CAN +#error EQUIPMENT_STOP_BUTTON and DUAL_CAN cannot coexist due to overlapping GPIO pin usage +#endif +#ifdef CAN_FD +#error EQUIPMENT_STOP_BUTTON and CAN_FD cannot coexist due to overlapping GPIO pin usage +#endif +#ifdef CHADEMO_BATTERY +#error EQUIPMENT_STOP_BUTTON and CHADEMO_BATTERY cannot coexist due to overlapping GPIO pin usage +#endif +#endif + +#ifdef BMW_I3_BATTERY +#ifdef CONTACTOR_CONTROL +#error GPIO PIN 25 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL +#endif +#endif + +#endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 3f6bfbf5..cf33bbf0 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -415,6 +415,9 @@ String get_firmware_info_processor(const String& var) { #ifdef HW_STARK doc["hardware"] = "Stark CMR Module"; #endif // HW_STARK +#ifdef HW_3LB + doc["hardware"] = "3LB board"; +#endif // HW_STARK doc["firmware"] = String(version_number); serializeJson(doc, content); From 271621f99763764c0db7364c9f27b487bc35f68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 8 Nov 2024 13:31:24 +0200 Subject: [PATCH 10/36] Revise bit placement in challenge reply --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 76bf7e13..10b34363 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -877,6 +877,7 @@ void receive_can_battery(CAN_frame rx_frame) { if (stateMachineClearSOH < 255) { //Intercept the messages based on state machine if (rx_frame.data.u8[0] == 0x06) { // Incoming challenge data! + // BMS should reply with (challenge) 06 67 65 (02 DD 86 43) FF incomingChallenge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[4] << 16) | (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); } @@ -1332,6 +1333,7 @@ void clearSOH(void) { LEAF_CLEAR_SOH.data.u8[6] = 0x00; LEAF_CLEAR_SOH.data.u8[7] = 0x00; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + // BMS should reply with (challenge) 06 67 65 (02 DD 86 43) FF stateMachineClearSOH = 4; break; case 4: // Send back decoded challenge data @@ -1340,16 +1342,16 @@ void clearSOH(void) { LEAF_CLEAR_SOH.data.u8[1] = 0x0A; LEAF_CLEAR_SOH.data.u8[2] = 0x27; LEAF_CLEAR_SOH.data.u8[3] = 0x66; - LEAF_CLEAR_SOH.data.u8[4] = 0x77; - LEAF_CLEAR_SOH.data.u8[5] = solvedChallenge[0]; - LEAF_CLEAR_SOH.data.u8[6] = solvedChallenge[1]; - LEAF_CLEAR_SOH.data.u8[7] = solvedChallenge[2]; + LEAF_CLEAR_SOH.data.u8[4] = solvedChallenge[0]; + LEAF_CLEAR_SOH.data.u8[5] = solvedChallenge[1]; + LEAF_CLEAR_SOH.data.u8[6] = solvedChallenge[2]; + LEAF_CLEAR_SOH.data.u8[7] = solvedChallenge[3]; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 7BB 8 30 01 00 FF FF FF FF FF // Proceed with more data (PID ACK) stateMachineClearSOH = 5; break; case 5: // Reply with even more decoded challenge data - LEAF_CLEAR_SOH.data.u8[0] = solvedChallenge[3]; + LEAF_CLEAR_SOH.data.u8[0] = 0x21; LEAF_CLEAR_SOH.data.u8[1] = solvedChallenge[4]; LEAF_CLEAR_SOH.data.u8[2] = solvedChallenge[5]; LEAF_CLEAR_SOH.data.u8[3] = solvedChallenge[6]; From c2e92aee029d9081bb9935260b5fbcf1730a5aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 8 Nov 2024 21:25:32 +0200 Subject: [PATCH 11/36] Clean up code --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 94 +++----------------- 1 file changed, 13 insertions(+), 81 deletions(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 10b34363..d5e78809 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1298,108 +1298,54 @@ void clearSOH(void) { stateMachineClearSOH = 1; break; case 1: // Set CAN_PROCESS_FLAG to 0xC0 - LEAF_CLEAR_SOH.data.u8[0] = 0x02; - LEAF_CLEAR_SOH.data.u8[1] = 0x10; - LEAF_CLEAR_SOH.data.u8[2] = 0xC0; - LEAF_CLEAR_SOH.data.u8[3] = 0x00; - LEAF_CLEAR_SOH.data.u8[4] = 0x00; - LEAF_CLEAR_SOH.data.u8[5] = 0x00; - LEAF_CLEAR_SOH.data.u8[6] = 0x00; - LEAF_CLEAR_SOH.data.u8[7] = 0x00; + LEAF_CLEAR_SOH.data = {0x02, 0x10, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00}; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 02 50 C0 FF FF FF FF FF stateMachineClearSOH = 2; break; case 2: // Set something ? - LEAF_CLEAR_SOH.data.u8[0] = 0x02; - LEAF_CLEAR_SOH.data.u8[1] = 0x3E; - LEAF_CLEAR_SOH.data.u8[2] = 0x01; - LEAF_CLEAR_SOH.data.u8[3] = 0x00; - LEAF_CLEAR_SOH.data.u8[4] = 0x00; - LEAF_CLEAR_SOH.data.u8[5] = 0x00; - LEAF_CLEAR_SOH.data.u8[6] = 0x00; - LEAF_CLEAR_SOH.data.u8[7] = 0x00; + LEAF_CLEAR_SOH.data = {0x02, 0x3E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 7E FF FF FF FF FF FF stateMachineClearSOH = 3; break; case 3: // Request challenge to solve - LEAF_CLEAR_SOH.data.u8[0] = 0x02; - LEAF_CLEAR_SOH.data.u8[1] = 0x27; - LEAF_CLEAR_SOH.data.u8[2] = 0x65; - LEAF_CLEAR_SOH.data.u8[3] = 0x00; - LEAF_CLEAR_SOH.data.u8[4] = 0x00; - LEAF_CLEAR_SOH.data.u8[5] = 0x00; - LEAF_CLEAR_SOH.data.u8[6] = 0x00; - LEAF_CLEAR_SOH.data.u8[7] = 0x00; + LEAF_CLEAR_SOH.data = {0x02, 0x27, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00}; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply with (challenge) 06 67 65 (02 DD 86 43) FF stateMachineClearSOH = 4; break; case 4: // Send back decoded challenge data decodeChallengeData(incomingChallenge, solvedChallenge); - LEAF_CLEAR_SOH.data.u8[0] = 0x10; - LEAF_CLEAR_SOH.data.u8[1] = 0x0A; - LEAF_CLEAR_SOH.data.u8[2] = 0x27; - LEAF_CLEAR_SOH.data.u8[3] = 0x66; - LEAF_CLEAR_SOH.data.u8[4] = solvedChallenge[0]; - LEAF_CLEAR_SOH.data.u8[5] = solvedChallenge[1]; - LEAF_CLEAR_SOH.data.u8[6] = solvedChallenge[2]; - LEAF_CLEAR_SOH.data.u8[7] = solvedChallenge[3]; + LEAF_CLEAR_SOH.data = { + 0x10, 0x0A, 0x27, 0x66, solvedChallenge[0], solvedChallenge[1], solvedChallenge[2], solvedChallenge[3]}; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 7BB 8 30 01 00 FF FF FF FF FF // Proceed with more data (PID ACK) stateMachineClearSOH = 5; break; case 5: // Reply with even more decoded challenge data - LEAF_CLEAR_SOH.data.u8[0] = 0x21; - LEAF_CLEAR_SOH.data.u8[1] = solvedChallenge[4]; - LEAF_CLEAR_SOH.data.u8[2] = solvedChallenge[5]; - LEAF_CLEAR_SOH.data.u8[3] = solvedChallenge[6]; - LEAF_CLEAR_SOH.data.u8[4] = solvedChallenge[7]; - LEAF_CLEAR_SOH.data.u8[5] = 0x00; - LEAF_CLEAR_SOH.data.u8[6] = 0x00; - LEAF_CLEAR_SOH.data.u8[7] = 0x00; + LEAF_CLEAR_SOH.data = { + 0x21, solvedChallenge[4], solvedChallenge[5], solvedChallenge[6], solvedChallenge[7], 0x00, 0x00, 0x00}; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 02 67 66 FF FF FF FF FF // Thank you for the data stateMachineClearSOH = 6; break; case 6: // Check if solved data was OK - LEAF_CLEAR_SOH.data.u8[0] = 0x03; - LEAF_CLEAR_SOH.data.u8[1] = 0x31; - LEAF_CLEAR_SOH.data.u8[2] = 0x03; - LEAF_CLEAR_SOH.data.u8[3] = 0x00; - LEAF_CLEAR_SOH.data.u8[4] = 0x00; - LEAF_CLEAR_SOH.data.u8[5] = 0x00; - LEAF_CLEAR_SOH.data.u8[6] = 0x00; - LEAF_CLEAR_SOH.data.u8[7] = 0x00; + LEAF_CLEAR_SOH.data = {0x03, 0x31, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); //7BB 8 03 71 03 01 FF FF FF FF // If all is well, BMS replies with 03 71 03 01. //Incase you sent wrong challenge, you get 03 7f 31 12 stateMachineClearSOH = 7; break; case 7: // Reset SOH% request - LEAF_CLEAR_SOH.data.u8[0] = 0x03; - LEAF_CLEAR_SOH.data.u8[1] = 0x31; - LEAF_CLEAR_SOH.data.u8[2] = 0x03; - LEAF_CLEAR_SOH.data.u8[3] = 0x01; - LEAF_CLEAR_SOH.data.u8[4] = 0x00; - LEAF_CLEAR_SOH.data.u8[5] = 0x00; - LEAF_CLEAR_SOH.data.u8[6] = 0x00; - LEAF_CLEAR_SOH.data.u8[7] = 0x00; + LEAF_CLEAR_SOH.data = {0x03, 0x31, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00}; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); //7BB 8 03 71 03 02 FF FF FF FF // 03 71 03 02 means that BMS accepted command. //7BB 03 7f 31 12 means your challenge was wrong, so command ignored stateMachineClearSOH = 8; break; case 8: // Please proceed with resetting SOH - LEAF_CLEAR_SOH.data.u8[0] = 0x02; - LEAF_CLEAR_SOH.data.u8[1] = 0x10; - LEAF_CLEAR_SOH.data.u8[2] = 0x81; - LEAF_CLEAR_SOH.data.u8[3] = 0x00; - LEAF_CLEAR_SOH.data.u8[4] = 0x00; - LEAF_CLEAR_SOH.data.u8[5] = 0x00; - LEAF_CLEAR_SOH.data.u8[6] = 0x00; - LEAF_CLEAR_SOH.data.u8[7] = 0x00; + LEAF_CLEAR_SOH.data = {0x02, 0x10, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00}; transmit_can(&LEAF_CLEAR_SOH, can_config.battery); // 7BB 8 02 50 81 FF FF FF FF FF // SOH reset OK stateMachineClearSOH = 255; @@ -1423,17 +1369,7 @@ void clearSOH(void) { uint32_t CyclicXorHash16Bit(uint32_t param_1, uint32_t param_2) { bool bVar1; - uint32_t uVar2; - uint32_t uVar3; - uint32_t uVar4; - uint32_t uVar5; - uint32_t uVar6; - uint32_t uVar7; - uint32_t uVar8; - uint32_t uVar9; - uint32_t uVar10; - uint32_t uVar11; - uint32_t iVar12; + uint32_t uVar2, uVar3, uVar4, uVar5, uVar6, uVar7, uVar8, uVar9, uVar10, uVar11, iVar12; param_1 = param_1 & 0xffff; param_2 = param_2 & 0xffff; @@ -1518,10 +1454,7 @@ uint32_t MaskedBitwiseRotateMultiply(uint32_t param_1, uint32_t param_2) { } uint32_t CryptAlgo(uint32_t param_1, uint32_t param_2, uint32_t param_3) { - uint32_t uVar1; - uint32_t uVar2; - uint32_t iVar3; - uint32_t iVar4; + uint32_t uVar1, uVar2, iVar3, iVar4; uVar1 = MaskedBitwiseRotateMultiply(param_2, param_3); uVar2 = ShortMaskedSumAndProduct(param_2, param_3); @@ -1533,8 +1466,7 @@ uint32_t CryptAlgo(uint32_t param_1, uint32_t param_2, uint32_t param_3) { } void decodeChallengeData(uint32_t incomingChallenge, unsigned char* solvedChallenge) { - uint32_t uVar1; - uint32_t uVar2; + uint32_t uVar1, uVar2; uVar1 = CryptAlgo(0x609, 0xDD2, incomingChallenge >> 0x10); uVar2 = CryptAlgo(incomingChallenge & 0xffff, incomingChallenge >> 0x10, 0x609); From 710a7339d881c28498fe0adc8ad09336c78ea6cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 8 Nov 2024 22:56:53 +0200 Subject: [PATCH 12/36] Add charge/discharge current to datalayer --- Software/Software.ino | 22 +++++++- Software/src/datalayer/datalayer.h | 8 ++- Software/src/devboard/safety/safety.cpp | 8 +++ Software/src/devboard/webserver/webserver.cpp | 8 +++ Software/src/inverter/AFORE-CAN.cpp | 33 ++--------- Software/src/inverter/BYD-CAN.cpp | 36 ++---------- Software/src/inverter/BYD-SMA.cpp | 35 ++---------- Software/src/inverter/FOXESS-CAN.cpp | 56 ++----------------- Software/src/inverter/PYLON-CAN.cpp | 54 ++++++------------ Software/src/inverter/PYLON-LV-CAN.cpp | 28 ++++------ Software/src/inverter/SMA-CAN.cpp | 33 ++--------- Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 33 ++--------- Software/src/inverter/SOFAR-CAN.cpp | 8 +-- Software/src/inverter/SOLAX-CAN.cpp | 54 ++---------------- 14 files changed, 104 insertions(+), 312 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 588f28cf..adc771e1 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -293,7 +293,7 @@ void core_loop(void* task_time_us) { #ifdef DOUBLE_BATTERY update_values_battery2(); #endif - update_scaled_values(); // Check if real or calculated SOC% value should be sent + update_calculated_values(); #ifndef SERIAL_LINK_RECEIVER update_machineryprotection(); // Check safeties (Not on serial link reciever board) #endif @@ -837,7 +837,23 @@ void handle_contactors() { #endif // CONTACTOR_CONTROL } -void update_scaled_values() { +void update_calculated_values() { + /* Calculate allowed charge/discharge currents*/ + if (datalayer.battery.status.voltage_dV > 10) { + // Only update value when we have voltage available to avoid div0. TODO: This should be based on nominal voltage + datalayer.battery.status.max_charge_current_dA = + ((datalayer.battery.status.max_charge_power_W * 100) / datalayer.battery.status.voltage_dV); + datalayer.battery.status.max_discharge_current_dA = + ((datalayer.battery.status.max_discharge_power_W * 100) / datalayer.battery.status.voltage_dV); + } + /* Restrict values from user settings if needed*/ + if (datalayer.battery.status.max_charge_current_dA > datalayer.battery.info.max_charge_amp_dA) { + datalayer.battery.status.max_charge_current_dA = datalayer.battery.info.max_charge_amp_dA; + } + if (datalayer.battery.status.max_discharge_current_dA > datalayer.battery.info.max_discharge_amp_dA) { + datalayer.battery.status.max_discharge_current_dA = datalayer.battery.info.max_discharge_amp_dA; + } + if (datalayer.battery.settings.soc_scaling_active) { /** SOC Scaling * @@ -896,7 +912,7 @@ void update_scaled_values() { } #endif - } else { // No SOC window wanted. Set scaled to same as real. + } else { // soc_scaling_active == false. No SOC window wanted. Set scaled to same as real. datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc; datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh; #ifdef DOUBLE_BATTERY diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index d0b6e840..b4967f4b 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -49,10 +49,14 @@ typedef struct { */ uint32_t reported_remaining_capacity_Wh; - /** Maximum allowed battery discharge power in Watts */ + /** Maximum allowed battery discharge power in Watts. Set by battery */ uint32_t max_discharge_power_W = 0; - /** Maximum allowed battery charge power in Watts */ + /** Maximum allowed battery charge power in Watts. Set by battery */ uint32_t max_charge_power_W = 0; + /** Maximum allowed battery discharge current in dA. Calculated based on allowed W and Voltage */ + uint16_t max_discharge_current_dA = 0; + /** Maximum allowed battery charge current in dA. Calculated based on allowed W and Voltage */ + uint16_t max_charge_current_dA = 0; /** int16_t */ /** Maximum temperature currently measured in the pack, in d°C. 150 = 15.0 °C */ diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp index f2023f41..ee72af88 100644 --- a/Software/src/devboard/safety/safety.cpp +++ b/Software/src/devboard/safety/safety.cpp @@ -229,6 +229,14 @@ void update_machineryprotection() { } #endif // DOUBLE_BATTERY + + //Safeties verified, Zero charge/discharge ampere values incase any safety wrote the W to 0 + if (datalayer.battery.status.max_discharge_power_W == 0) { + datalayer.battery.status.max_discharge_current_dA = 0; + } + if (datalayer.battery.status.max_charge_power_W == 0) { + datalayer.battery.status.max_charge_current_dA = 0; + } } //battery pause status begin diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index d42bac4b..4a1554f3 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -652,6 +652,10 @@ String processor(const String& var) { float powerFloat = static_cast(datalayer.battery.status.active_power_W); // Convert to float float tempMaxFloat = static_cast(datalayer.battery.status.temperature_max_dC) / 10.0; // Convert to float float tempMinFloat = static_cast(datalayer.battery.status.temperature_min_dC) / 10.0; // Convert to float + float maxCurrentChargeFloat = + static_cast(datalayer.battery.status.max_charge_current_dA) / 10.0; // Convert to float + float maxCurrentDischargeFloat = + static_cast(datalayer.battery.status.max_discharge_current_dA) / 10.0; // Convert to float uint16_t cell_delta_mv = datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV; @@ -669,9 +673,13 @@ String processor(const String& var) { if (emulator_pause_status == NORMAL) { content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1); content += formatPowerValue("Max charge power", datalayer.battery.status.max_charge_power_W, "", 1); + content += "

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

"; + content += "

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

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

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

"; + content += "

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

"; } content += "

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

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

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

"; - content += - "

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

"; + content += "

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

"; content += "

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

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

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

"; content += "

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

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

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

"; - content += "

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

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

"; content += "

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

"; #if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER From 0b278034d419f3e73a3b788ee027c79925621882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 22:25:10 +0200 Subject: [PATCH 27/36] Remove compilation error, runtime event catches egmp CAN-FD --- Software/Software.ino | 25 +++++-------------- Software/src/include.h | 6 ----- .../SERIAL-LINK-TRANSMITTER-INVERTER.h | 2 ++ 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 303442a8..957d4537 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -70,13 +70,11 @@ volatile bool send_ok = 0; static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT); static ACAN2515_Buffer16 gBuffer; -#endif +#endif //DUAL_CAN #ifdef CAN_FD #include "src/lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); -#else -typedef char CANFDMessage; -#endif +#endif //CAN_FD // ModbusRTU parameters #ifdef MODBUS_INVERTER_SELECTED @@ -172,11 +170,10 @@ void setup() { init_rs485(); init_serialDataLink(); - - init_inverter(); - - init_battery(); - +#if defined(CAN_INVERTER_SELECTED) || defined(MODBUS_INVERTER_SELECTED) + setup_inverter(); +#endif + setup_battery(); #ifdef EQUIPMENT_STOP_BUTTON init_equipment_stop_button(); #endif @@ -554,16 +551,6 @@ void init_rs485() { #endif } -void init_inverter() { - // Inform user what inverter is used and perform setup - setup_inverter(); -} - -void init_battery() { - // Inform user what battery is used and perform setup - setup_battery(); -} - #ifdef EQUIPMENT_STOP_BUTTON void monitor_equipment_stop_button() { diff --git a/Software/src/include.h b/Software/src/include.h index 83f2290d..b29345e6 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -45,10 +45,4 @@ #error No battery selected! Choose one from the USER_SETTINGS.h file #endif -#ifdef KIA_E_GMP_BATTERY -#ifndef CAN_FD -#error KIA HYUNDAI EGMP BATTERIES CANNOT BE USED WITHOUT CAN FD -#endif -#endif - #endif diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h index 1637e6bd..487ca103 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h @@ -1,6 +1,8 @@ #ifndef SERIAL_LINK_TRANSMITTER_INVERTER_H #define SERIAL_LINK_TRANSMITTER_INVERTER_H +#define MODBUS_INVERTER_SELECTED + #include #include "../include.h" #include "../lib/mackelec-SerialDataLink/SerialDataLink.h" From a537b7ff1b9060b69a95169381265788c03392d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 22:33:35 +0200 Subject: [PATCH 28/36] Fix compilation issue for seriallink --- .../src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp | 10 ++-------- .../src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h | 2 -- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp index aa0a7ec4..a61ea7dc 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp @@ -128,6 +128,8 @@ void manageSerialLinkTransmitter() { static unsigned long updateDataTime = 0; if (currentTime - updateDataTime > INTERVAL_1_S) { + strncpy(datalayer.system.info.inverter_protocol, "Serial link to another LilyGo board", 63); + datalayer.system.info.inverter_protocol[63] = '\0'; updateDataTime = currentTime; dataLinkTransmit.updateData(0, datalayer.battery.status.real_soc); dataLinkTransmit.updateData(1, datalayer.battery.status.soh_pptt); @@ -159,10 +161,6 @@ void printSendingValues() { Serial.print(datalayer.battery.status.soh_pptt); Serial.print(" Voltage: "); Serial.print(datalayer.battery.status.voltage_dV); - void setup_inverter(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Serial link to another LilyGo board", 63); - datalayer.system.info.inverter_protocol[63] = '\0'; - } Serial.print(" Current: "); Serial.print(datalayer.battery.status.current_dA); Serial.print(" Capacity: "); @@ -194,8 +192,4 @@ void printSendingValues() { Serial.println(""); } -void setup_inverter(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Serial link to another LilyGo board", 63); - datalayer.system.info.inverter_protocol[63] = '\0'; -} #endif diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h index 487ca103..1637e6bd 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.h @@ -1,8 +1,6 @@ #ifndef SERIAL_LINK_TRANSMITTER_INVERTER_H #define SERIAL_LINK_TRANSMITTER_INVERTER_H -#define MODBUS_INVERTER_SELECTED - #include #include "../include.h" #include "../lib/mackelec-SerialDataLink/SerialDataLink.h" From 5d9105d9a85dd6c36f874b770b2c7e725fc21bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Thu, 14 Nov 2024 22:54:19 +0200 Subject: [PATCH 29/36] Add more BYD inverter mappings --- Software/src/inverter/BYD-CAN.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index ae0bb560..58dc00e4 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -76,6 +76,8 @@ static uint8_t inverter_name[7] = {0}; static int16_t temperature_average = 0; static uint16_t inverter_voltage = 0; static uint16_t inverter_SOC = 0; +static int16_t inverter_current = 0; +static int16_t inverter_temperature = 0; static uint16_t remaining_capacity_ah = 0; static uint16_t fully_charged_capacity_ah = 0; static long inverter_timestamp = 0; @@ -165,6 +167,8 @@ void receive_can_inverter(CAN_frame rx_frame) { case 0x091: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; inverter_voltage = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]) * 0.1; + inverter_current = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]) * 0.1; + inverter_temperature = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 0.1; break; case 0x0D1: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; From 115e7db33fe69fa4c1400dad3fbee592681e764b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Fri, 15 Nov 2024 22:58:36 +0200 Subject: [PATCH 30/36] Revise commands from testing round --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 74 ++++++------------- Software/src/battery/NISSAN-LEAF-BATTERY.h | 10 +-- .../webserver/advanced_battery_html.cpp | 2 +- 3 files changed, 30 insertions(+), 56 deletions(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index d5e78809..06f976a0 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -884,20 +884,7 @@ void receive_can_battery(CAN_frame rx_frame) { //Error checking if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F)) { challengeFailed = true; - Serial.print("Challenge solving failed"); } - // All CAN messages recieved from BMS will be logged via serial during development of this function - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); - for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); - } - Serial.println(""); break; } @@ -1353,23 +1340,11 @@ void clearSOH(void) { default: break; } - // All CAN messages semt will be logged via serial during development of this function - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 7B9 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(LEAF_CLEAR_SOH.ID, HEX); - Serial.print(" "); - Serial.print(LEAF_CLEAR_SOH.DLC); - Serial.print(" "); - for (int i = 0; i < LEAF_CLEAR_SOH.DLC; ++i) { - Serial.print(LEAF_CLEAR_SOH.data.u8[i], HEX); - Serial.print(" "); - } - Serial.println(""); } -uint32_t CyclicXorHash16Bit(uint32_t param_1, uint32_t param_2) { +unsigned int CyclicXorHash16Bit(unsigned int param_1, unsigned int param_2) { bool bVar1; - uint32_t uVar2, uVar3, uVar4, uVar5, uVar6, uVar7, uVar8, uVar9, uVar10, uVar11, iVar12; + unsigned int uVar2, uVar3, uVar4, uVar5, uVar6, uVar7, uVar8, uVar9, uVar10, uVar11, iVar12; param_1 = param_1 & 0xffff; param_2 = param_2 & 0xffff; @@ -1430,54 +1405,53 @@ uint32_t CyclicXorHash16Bit(uint32_t param_1, uint32_t param_2) { } while (bVar1); return uVar10; } - -uint32_t ComputeMaskedXorProduct(uint32_t param_1, uint32_t param_2, uint32_t param_3) { - return (param_3 ^ 0x780 | param_2 ^ 0x116) * ((param_1 & 0xffff) >> 8 ^ param_1 & 0xff) & 0xffff; +unsigned int ComputeMaskedXorProduct(unsigned int param_1, unsigned int param_2, unsigned int param_3) { + return (param_3 ^ 0x7F88 | param_2 ^ 0x8FE7) * ((param_1 & 0xffff) >> 8 ^ param_1 & 0xff) & 0xffff; } short ShortMaskedSumAndProduct(short param_1, short param_2) { unsigned short uVar1; - uVar1 = param_2 + param_1 * 0x5ba & 0xff; + uVar1 = param_2 + param_1 * 0x0006 & 0xff; return (uVar1 + param_1) * (uVar1 + param_2); } -uint32_t MaskedBitwiseRotateMultiply(uint32_t param_1, uint32_t param_2) { - uint32_t uVar1; +unsigned int MaskedBitwiseRotateMultiply(unsigned int param_1, unsigned int param_2) { + unsigned int uVar1; param_1 = param_1 & 0xffff; param_2 = param_2 & 0xffff; - uVar1 = param_2 & (param_1 | 0x5ba) & 0xf; - return ((uint32_t)param_1 >> uVar1 | param_1 << (0x10 - uVar1 & 0x1f)) * - (param_2 << uVar1 | (uint32_t)param_2 >> (0x10 - uVar1 & 0x1f)) & + uVar1 = param_2 & (param_1 | 0x0006) & 0xf; + return ((unsigned int)param_1 >> uVar1 | param_1 << (0x10 - uVar1 & 0x1f)) * + (param_2 << uVar1 | (unsigned int)param_2 >> (0x10 - uVar1 & 0x1f)) & 0xffff; } -uint32_t CryptAlgo(uint32_t param_1, uint32_t param_2, uint32_t param_3) { - uint32_t uVar1, uVar2, iVar3, iVar4; +unsigned int CryptAlgo(unsigned int param_1, unsigned int param_2, unsigned int param_3) { + unsigned int uVar1, uVar2, iVar3, iVar4; uVar1 = MaskedBitwiseRotateMultiply(param_2, param_3); uVar2 = ShortMaskedSumAndProduct(param_2, param_3); uVar1 = ComputeMaskedXorProduct(param_1, uVar1, uVar2); uVar2 = ComputeMaskedXorProduct(param_1, uVar2, uVar1); - iVar3 = CyclicXorHash16Bit(uVar1, 0xffc4); - iVar4 = CyclicXorHash16Bit(uVar2, 0xffc4); + iVar3 = CyclicXorHash16Bit(uVar1, 0x8421); + iVar4 = CyclicXorHash16Bit(uVar2, 0x8421); return iVar4 + iVar3 * 0x10000; } -void decodeChallengeData(uint32_t incomingChallenge, unsigned char* solvedChallenge) { - uint32_t uVar1, uVar2; +void decodeChallengeData(unsigned int incomingChallenge, unsigned char* solvedChallenge) { + unsigned int uVar1, uVar2; - uVar1 = CryptAlgo(0x609, 0xDD2, incomingChallenge >> 0x10); - uVar2 = CryptAlgo(incomingChallenge & 0xffff, incomingChallenge >> 0x10, 0x609); + uVar1 = CryptAlgo(0x54e9, 0x3afd, incomingChallenge >> 0x10); + uVar2 = CryptAlgo(incomingChallenge & 0xffff, incomingChallenge >> 0x10, 0x54e9); *solvedChallenge = (unsigned char)uVar1; solvedChallenge[1] = (unsigned char)uVar2; - solvedChallenge[2] = (unsigned char)((uint32_t)uVar2 >> 8); - solvedChallenge[3] = (unsigned char)((uint32_t)uVar1 >> 8); - solvedChallenge[4] = (unsigned char)((uint32_t)uVar2 >> 16); - solvedChallenge[5] = (unsigned char)((uint32_t)uVar1 >> 16); - solvedChallenge[6] = (unsigned char)((uint32_t)uVar2 >> 24); - solvedChallenge[7] = (unsigned char)((uint32_t)uVar1 >> 24); + solvedChallenge[2] = (unsigned char)((unsigned int)uVar2 >> 8); + solvedChallenge[3] = (unsigned char)((unsigned int)uVar1 >> 8); + solvedChallenge[4] = (unsigned char)((unsigned int)uVar2 >> 0x10); + solvedChallenge[5] = (unsigned char)((unsigned int)uVar1 >> 0x10); + solvedChallenge[6] = (unsigned char)((unsigned int)uVar2 >> 0x18); + solvedChallenge[7] = (unsigned char)((unsigned int)uVar1 >> 0x18); return; } diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.h b/Software/src/battery/NISSAN-LEAF-BATTERY.h index 2d29c0d7..245f0f39 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.h +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.h @@ -16,11 +16,11 @@ void setup_battery(void); void transmit_can(CAN_frame* tx_frame, int interface); void clearSOH(void); //Cryptographic functions -void decodeChallengeData(uint32_t incomingChallenge, unsigned char* solvedChallenge); -uint32_t CyclicXorHash16Bit(uint32_t param_1, uint32_t param_2); -uint32_t ComputeMaskedXorProduct(uint32_t param_1, uint32_t param_2, uint32_t param_3); +void decodeChallengeData(unsigned int SeedInput, unsigned char* Crypt_Output_Buffer); +unsigned int CyclicXorHash16Bit(unsigned int param_1, unsigned int param_2); +unsigned int ComputeMaskedXorProduct(unsigned int param_1, unsigned int param_2, unsigned int param_3); short ShortMaskedSumAndProduct(short param_1, short param_2); -uint32_t MaskedBitwiseRotateMultiply(uint32_t param_1, uint32_t param_2); -uint32_t CryptAlgo(uint32_t param_1, uint32_t param_2, uint32_t param_3); +unsigned int MaskedBitwiseRotateMultiply(unsigned int param_1, unsigned int param_2); +unsigned int CryptAlgo(unsigned int param_1, unsigned int param_2, unsigned int param_3); #endif diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 00202d3e..f734230a 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -356,7 +356,7 @@ String advanced_battery_processor(const String& var) { content += "