From 6773faa3f5bfc297a9b1bcb13615dd9713625fd8 Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:31:47 +0100 Subject: [PATCH 01/14] Add files via upload --- Software/src/battery/BATTERIES.h | 8 +- .../src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp | 665 ++++++++++++++++++ .../src/battery/VOLVO-SPA-HYBRID-BATTERY.h | 16 + 3 files changed, 685 insertions(+), 4 deletions(-) create mode 100644 Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp create mode 100644 Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 81a3ab40..5720629d 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -42,10 +42,6 @@ void setup_can_shunt(); #include "FOXESS-BATTERY.h" #endif -#ifdef ORION_BMS -#include "ORION-BMS.h" -#endif - #ifdef SONO_BATTERY #include "SONO-BATTERY.h" #endif @@ -135,6 +131,10 @@ void setup_can_shunt(); #include "VOLVO-SPA-BATTERY.h" #endif +#ifdef VOLVO_SPA_HYBRID_BATTERY +#include "VOLVO-SPA-HYBRID-BATTERY.h" +#endif + #ifdef SERIAL_LINK_RECEIVER #include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h" #endif diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp new file mode 100644 index 00000000..e4712fb1 --- /dev/null +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp @@ -0,0 +1,665 @@ +#include "../include.h" +#ifdef VOLVO_SPA_HYBRID_BATTERY +#include "../datalayer/datalayer.h" +#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage +#include "../devboard/utils/events.h" +#include "VOLVO-SPA-HYBRID-BATTERY.h" + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send +static unsigned long previousMillis1s = 0; // will store last time a 1s CAN Message was send +static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send + +static float BATT_U = 0; //0x3A +static float MAX_U = 0; //0x3A +static float MIN_U = 0; //0x3A +static float BATT_I = 0; //0x3A +static int32_t CHARGE_ENERGY = 0; //0x1A1 +static uint8_t BATT_ERR_INDICATION = 0; //0x413 +static float BATT_T_MAX = 0; //0x413 +static float BATT_T_MIN = 0; //0x413 +static float BATT_T_AVG = 0; //0x413 +static uint16_t SOC_BMS = 0; //0X37D +static uint16_t SOC_CALC = 0; +static uint16_t CELL_U_MAX = 3700; //0x37D +static uint16_t CELL_U_MIN = 3700; //0x37D +static uint8_t CELL_ID_U_MAX = 0; //0x37D +static uint16_t HvBattPwrLimDchaSoft = 0; //0x369 +static uint16_t HvBattPwrLimDcha1 = 0; //0x175 +//static uint16_t HvBattPwrLimDchaSlowAgi = 0; //0x177 +//static uint16_t HvBattPwrLimChrgSlowAgi = 0; //0x177 +//static uint8_t batteryModuleNumber = 0x10; // First battery module +static uint8_t battery_request_idx = 0; +static uint8_t rxConsecutiveFrames = 0; +static uint16_t min_max_voltage[2]; //contains cell min[0] and max[1] values in mV +static uint8_t cellcounter = 0; +static uint32_t remaining_capacity = 0; +static uint16_t cell_voltages[102]; //array with all the cellvoltages +static bool startedUp = false; +static uint8_t DTC_reset_counter = 0; + +CAN_frame VOLVO_536 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x536, + //.data = {0x00, 0x40, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Network manage frame + .data = {0x00, 0x40, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}; //Network manage frame + +CAN_frame VOLVO_140_CLOSE = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x140, + .data = {0x00, 0x02, 0x00, 0xB7, 0xFF, 0x03, 0xFF, 0x82}}; //Close contactors message + +CAN_frame VOLVO_140_OPEN = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x140, + .data = {0x00, 0x02, 0x00, 0x9E, 0xFF, 0x03, 0xFF, 0x82}}; //Open contactor message + +CAN_frame VOLVO_372 = { + .FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x372, + .data = {0x00, 0xA6, 0x07, 0x14, 0x04, 0x00, 0x80, 0x00}}; //Ambient Temp -->>VERIFY this data content!!!<<-- +CAN_frame VOLVO_CELL_U_Req = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x735, + .data = {0x03, 0x22, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00}}; //Cell voltage request frame // changed +CAN_frame VOLVO_FlowControl = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x735, + .data = {0x30, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Flowcontrol +CAN_frame VOLVO_SOH_Req = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x735, + .data = {0x03, 0x22, 0x49, 0x6D, 0x00, 0x00, 0x00, 0x00}}; //Battery SOH request frame +CAN_frame VOLVO_BECMsupplyVoltage_Req = { + .FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x735, + .data = {0x03, 0x22, 0xF4, 0x42, 0x00, 0x00, 0x00, 0x00}}; //BECM supply voltage request frame +CAN_frame VOLVO_DTC_Erase = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7FF, + .data = {0x04, 0x14, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}}; //Global DTC erase +CAN_frame VOLVO_BECM_ECUreset = { + .FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x735, + .data = {0x02, 0x11, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00}}; //BECM ECU reset command (reboot/powercycle BECM) +CAN_frame VOLVO_DTCreadout = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7FF, + .data = {0x02, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Global DTC readout + +void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter + uint8_t cnt = 0; + + // Update webserver datalayer + datalayer_extended.VolvoHybrid.soc_bms = SOC_BMS; + datalayer_extended.VolvoHybrid.soc_calc = SOC_CALC; + datalayer_extended.VolvoHybrid.soc_rescaled = datalayer.battery.status.reported_soc; + datalayer_extended.VolvoHybrid.soh_bms = datalayer.battery.status.soh_pptt; + + datalayer_extended.VolvoHybrid.BECMBatteryVoltage = BATT_U; + datalayer_extended.VolvoHybrid.BECMBatteryCurrent = BATT_I; + datalayer_extended.VolvoHybrid.BECMUDynMaxLim = MAX_U; + datalayer_extended.VolvoHybrid.BECMUDynMinLim = MIN_U; + + datalayer_extended.VolvoHybrid.HvBattPwrLimDcha1 = HvBattPwrLimDcha1; + datalayer_extended.VolvoHybrid.HvBattPwrLimDchaSoft = HvBattPwrLimDchaSoft; + //datalayer_extended.VolvoHybrid.HvBattPwrLimDchaSlowAgi = HvBattPwrLimDchaSlowAgi; + //datalayer_extended.VolvoHybrid.HvBattPwrLimChrgSlowAgi = HvBattPwrLimChrgSlowAgi; + + // Update requests from webserver datalayer + if (datalayer_extended.VolvoHybrid.UserRequestDTCreset) { + transmit_can_frame(&VOLVO_DTC_Erase, can_config.battery); //Send global DTC erase command + datalayer_extended.VolvoHybrid.UserRequestDTCreset = false; + } + if (datalayer_extended.VolvoHybrid.UserRequestBECMecuReset) { + transmit_can_frame(&VOLVO_BECM_ECUreset, can_config.battery); //Send BECM ecu reset command + datalayer_extended.VolvoHybrid.UserRequestBECMecuReset = false; + } + if (datalayer_extended.VolvoHybrid.UserRequestDTCreadout) { + transmit_can_frame(&VOLVO_DTCreadout, can_config.battery); //Send DTC readout command + datalayer_extended.VolvoHybrid.UserRequestDTCreadout = false; + } + + remaining_capacity = (18830 - CHARGE_ENERGY); + + //datalayer.battery.status.real_soc = SOC_BMS; // Use BMS reported SOC, havent figured out how to get the BMS to calibrate empty/full yet + SOC_CALC = remaining_capacity / 19; // Use calculated SOC based on remaining_capacity + + datalayer.battery.status.real_soc = SOC_CALC * 10; + + if (BATT_U > MAX_U) // Protect if overcharged + { + datalayer.battery.status.real_soc = 10000; + } else if (BATT_U < MIN_U) //Protect if undercharged + { + datalayer.battery.status.real_soc = 0; + } + + datalayer.battery.status.voltage_dV = BATT_U * 10; + datalayer.battery.status.current_dA = BATT_I * 10; + datalayer.battery.status.remaining_capacity_Wh = remaining_capacity; + + datalayer.battery.status.max_discharge_power_W = 6600; //default power on charge connector + datalayer.battery.status.max_charge_power_W = 6600; //default power on charge connector + datalayer.battery.status.temperature_min_dC = BATT_T_MIN; + datalayer.battery.status.temperature_max_dC = BATT_T_MAX; + + datalayer.battery.status.cell_max_voltage_mV = CELL_U_MAX; // Use min/max reported from BMS + datalayer.battery.status.cell_min_voltage_mV = CELL_U_MIN; + + //Map all cell voltages to the global array + for (int i = 0; i < 102; ++i) { + datalayer.battery.status.cell_voltages_mV[i] = cell_voltages[i]; + } + +#ifdef DEBUG_LOG + logging.print("BMS reported SOC%: "); + logging.println(SOC_BMS); + logging.print("Calculated SOC%: "); + logging.println(SOC_CALC); + logging.print("Rescaled SOC%: "); + logging.println(datalayer.battery.status.reported_soc / 100); + logging.print("Battery current: "); + logging.println(BATT_I); + logging.print("Battery voltage: "); + logging.println(BATT_U); + logging.print("Battery maximum voltage limit: "); + logging.println(MAX_U); + logging.print("Battery minimum voltage limit: "); + logging.println(MIN_U); + logging.print("Remaining Energy: "); + logging.println(remaining_capacity); + logging.print("Discharge limit: "); + logging.println(HvBattPwrLimDchaSoft); + logging.print("Battery Error Indication: "); + logging.println(BATT_ERR_INDICATION); + logging.print("Maximum battery temperature: "); + logging.println(BATT_T_MAX / 10); + logging.print("Minimum battery temperature: "); + logging.println(BATT_T_MIN / 10); + logging.print("Average battery temperature: "); + logging.println(BATT_T_AVG / 10); + logging.print("BMS Highest cell voltage: "); + logging.println(CELL_U_MAX); + logging.print("BMS Lowest cell voltage: "); + logging.println(CELL_U_MIN); + logging.print("BMS Highest cell nr: "); + logging.println(CELL_ID_U_MAX); + logging.print("Highest cell voltage: "); + logging.println(min_max_voltage[1]); + logging.print("Lowest cell voltage: "); + logging.println(min_max_voltage[0]); + logging.print("Cell voltage,"); + while (cnt < 102) { + logging.print(cell_voltages[cnt++]); + logging.print(","); + } + logging.println(";"); +#endif +} + +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + switch (rx_frame.ID) { + case 0x3A: + if ((rx_frame.data.u8[6] & 0x80) == 0x80) + BATT_I = (0 - ((((rx_frame.data.u8[6] & 0x7F) * 256.0 + rx_frame.data.u8[7]) * 0.1) - 1638)); + else { + BATT_I = 0; +#ifdef DEBUG_LOG + logging.println("BATT_I not valid"); +#endif + } + + if ((rx_frame.data.u8[2] & 0x08) == 0x08) + MAX_U = (((rx_frame.data.u8[2] & 0x07) * 256.0 + rx_frame.data.u8[3]) * 0.25); + else { + //MAX_U = 0; + //logging.println("MAX_U not valid"); // Value toggles between true/false from BMS + } + + if ((rx_frame.data.u8[4] & 0x08) == 0x08) + MIN_U = (((rx_frame.data.u8[4] & 0x07) * 256.0 + rx_frame.data.u8[5]) * 0.25); + else { + //MIN_U = 0; + //logging.println("MIN_U not valid"); // Value toggles between true/false from BMS + } + + if ((rx_frame.data.u8[0] & 0x08) == 0x08) + BATT_U = (((rx_frame.data.u8[0] & 0x07) * 256.0 + rx_frame.data.u8[1]) * 0.25); + else { + BATT_U = 0; +#ifdef DEBUG_LOG + logging.println("BATT_U not valid"); +#endif + } + + if ((rx_frame.data.u8[0] & 0x40) == 0x40) + datalayer_extended.VolvoHybrid.HVSysRlySts = ((rx_frame.data.u8[0] & 0x30) >> 4); + else + datalayer_extended.VolvoHybrid.HVSysRlySts = 0xFF; + + if ((rx_frame.data.u8[2] & 0x40) == 0x40) + datalayer_extended.VolvoHybrid.HVSysDCRlySts1 = ((rx_frame.data.u8[2] & 0x30) >> 4); + else + datalayer_extended.VolvoHybrid.HVSysDCRlySts1 = 0xFF; + if ((rx_frame.data.u8[2] & 0x80) == 0x80) + datalayer_extended.VolvoHybrid.HVSysDCRlySts2 = ((rx_frame.data.u8[4] & 0x30) >> 4); + else + datalayer_extended.VolvoHybrid.HVSysDCRlySts2 = 0xFF; + if ((rx_frame.data.u8[0] & 0x80) == 0x80) + datalayer_extended.VolvoHybrid.HVSysIsoRMonrSts = ((rx_frame.data.u8[4] & 0xC0) >> 6); + else + datalayer_extended.VolvoHybrid.HVSysIsoRMonrSts = 0xFF; + + break; + case 0x1A1: + if ((rx_frame.data.u8[4] & 0x10) == 0x10) + CHARGE_ENERGY = ((((rx_frame.data.u8[4] & 0x0F) * 256.0 + rx_frame.data.u8[5]) * 50) - 500); + else { + CHARGE_ENERGY = 0; + set_event(EVENT_KWH_PLAUSIBILITY_ERROR, CHARGE_ENERGY); + } + break; + case 0x413: + if ((rx_frame.data.u8[0] & 0x80) == 0x80) + BATT_ERR_INDICATION = ((rx_frame.data.u8[0] & 0x40) >> 6); + else { + BATT_ERR_INDICATION = 0; +#ifdef DEBUG_LOG + logging.println("BATT_ERR_INDICATION not valid"); +#endif + } + if ((rx_frame.data.u8[0] & 0x20) == 0x20) { + BATT_T_MAX = ((rx_frame.data.u8[2] & 0x1F) * 256.0 + rx_frame.data.u8[3]); + BATT_T_MIN = ((rx_frame.data.u8[4] & 0x1F) * 256.0 + rx_frame.data.u8[5]); + BATT_T_AVG = ((rx_frame.data.u8[0] & 0x1F) * 256.0 + rx_frame.data.u8[1]); + } else { + BATT_T_MAX = 0; + BATT_T_MIN = 0; + BATT_T_AVG = 0; +#ifdef DEBUG_LOG + logging.println("BATT_T not valid"); +#endif + } + break; + case 0x369: + if ((rx_frame.data.u8[0] & 0x80) == 0x80) { + HvBattPwrLimDchaSoft = (((rx_frame.data.u8[6] & 0x03) * 256 + rx_frame.data.u8[6]) >> 2); + } else { + HvBattPwrLimDchaSoft = 0; +#ifdef DEBUG_LOG + logging.println("HvBattPwrLimDchaSoft not valid"); +#endif + } + break; + case 0x175: + if ((rx_frame.data.u8[4] & 0x80) == 0x80) { + HvBattPwrLimDcha1 = (((rx_frame.data.u8[2] & 0x07) * 256 + rx_frame.data.u8[3]) >> 2); + } else { + HvBattPwrLimDcha1 = 0; + } + break; + case 0x177: + if ((rx_frame.data.u8[4] & 0x08) == 0x08) { + //HvBattPwrLimDchaSlowAgi = (((rx_frame.data.u8[4] & 0x07) * 256 + rx_frame.data.u8[5]) >> 2); + ; + } else { + //HvBattPwrLimDchaSlowAgi = 0; + ; + } + if ((rx_frame.data.u8[2] & 0x08) == 0x08) { + //HvBattPwrLimChrgSlowAgi = (((rx_frame.data.u8[2] & 0x07) * 256 + rx_frame.data.u8[3]) >> 2); + ; + } else { + //HvBattPwrLimChrgSlowAgi = 0; + ; + } + break; + case 0x37D: + if ((rx_frame.data.u8[0] & 0x40) == 0x40) { + SOC_BMS = ((rx_frame.data.u8[6] & 0x03) * 256 + rx_frame.data.u8[7]); + } else { + SOC_BMS = 0; +#ifdef DEBUG_LOG + logging.println("SOC_BMS not valid"); +#endif + } + + if ((rx_frame.data.u8[0] & 0x04) == 0x04) + //CELL_U_MAX = ((rx_frame.data.u8[2] & 0x01) * 256 + rx_frame.data.u8[3]); + ; + else { + //CELL_U_MAX = 0; + ; +#ifdef DEBUG_LOG + logging.println("CELL_U_MAX not valid"); +#endif + } + + if ((rx_frame.data.u8[0] & 0x02) == 0x02) + //CELL_U_MIN = ((rx_frame.data.u8[0] & 0x01) * 256.0 + rx_frame.data.u8[1]); + ; + else { + //CELL_U_MIN = 0; + ; +#ifdef DEBUG_LOG + logging.println("CELL_U_MIN not valid"); +#endif + } + + if ((rx_frame.data.u8[0] & 0x08) == 0x08) + //CELL_ID_U_MAX = ((rx_frame.data.u8[4] & 0x01) * 256.0 + rx_frame.data.u8[5]); + ; + else { + //CELL_ID_U_MAX = 0; + ; +#ifdef DEBUG_LOG + logging.println("CELL_ID_U_MAX not valid"); +#endif + } + break; + case 0x635: // Diag request response + if ((rx_frame.data.u8[0] == 0x07) && (rx_frame.data.u8[1] == 0x62) && (rx_frame.data.u8[2] == 0x49) && + (rx_frame.data.u8[3] == 0x6D)) // SOH response frame + { + datalayer.battery.status.soh_pptt = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + transmit_can_frame(&VOLVO_BECMsupplyVoltage_Req, can_config.battery); //Send BECM supply voltage req + } else if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x62) && (rx_frame.data.u8[2] == 0xF4) && + (rx_frame.data.u8[3] == 0x42)) // BECM module voltage supply + { + datalayer_extended.VolvoHybrid.BECMsupplyVoltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + } else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[2] == 0x62) && + (rx_frame.data.u8[3] == 0x48) && (rx_frame.data.u8[4] == 0x06)) // First response frame of cell voltages //changed + { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + rxConsecutiveFrames = 1; + } else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[2] == 0x59) && + (rx_frame.data.u8[3] == 0x03)) // First response frame for DTC with more than one code + { + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x21) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x22) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x23) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x24) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x25) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x26) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x27) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x28) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x29) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2A) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2B) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2C) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2D) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2E) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2F) && (rxConsecutiveFrames == 1)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + rxConsecutiveFrames = 2; + } else if ((rx_frame.data.u8[0] == 0x20) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x21) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x22) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x23) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x24) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x25) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x26) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x27) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x28) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x29) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2A) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2B) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2C) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]; + cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + } else if ((rx_frame.data.u8[0] == 0x2D) && (rxConsecutiveFrames == 2)) { + cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + //cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + //transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control + + if (false) // Run until last pack is read + { + //VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++; + //transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for next module + ; + } else { + min_max_voltage[0] = 9999; + min_max_voltage[1] = 0; + for (cellcounter = 0; cellcounter < 102; cellcounter++) { + if (min_max_voltage[0] > cell_voltages[cellcounter]) + min_max_voltage[0] = cell_voltages[cellcounter]; + if (min_max_voltage[1] < cell_voltages[cellcounter]) + min_max_voltage[1] = cell_voltages[cellcounter]; + CELL_ID_U_MAX = cellcounter; + } + CELL_U_MAX = min_max_voltage[1]; + CELL_U_MIN = min_max_voltage[0]; + + transmit_can_frame(&VOLVO_SOH_Req, can_config.battery); //Send SOH read request + } + rxConsecutiveFrames = 0; + } + break; + default: + break; + } +} + +void readCellVoltages() { + battery_request_idx = 0; + //batteryModuleNumber = 0x10; + rxConsecutiveFrames = 0; + //VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++; + transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module +} + +void transmit_can_battery() { + unsigned long currentMillis = millis(); + // Send 100ms CAN Message + if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { + // Check if sending of CAN messages has been delayed too much. + if ((currentMillis - previousMillis100 >= INTERVAL_100_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis100)); + } else { + clear_event(EVENT_CAN_OVERRUN); + } + previousMillis100 = currentMillis; + + transmit_can_frame(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive + transmit_can_frame(&VOLVO_372, can_config.battery); //Send 0x372 ECMAmbientTempCalculated + + if ((datalayer.battery.status.bms_status == ACTIVE) && startedUp) { + datalayer.system.status.battery_allows_contactor_closing = true; + //transmit_can_frame(&VOLVO_140_CLOSE, can_config.battery); //Send 0x140 Close contactors message + } else { //datalayer.battery.status.bms_status == FAULT , OR inverter requested opening contactors, OR system not started yet + datalayer.system.status.battery_allows_contactor_closing = false; + //transmit_can_frame(&VOLVO_140_OPEN, can_config.battery); //Send 0x140 Open contactors message + } + } + if (currentMillis - previousMillis1s >= INTERVAL_1_S) { + previousMillis1s = currentMillis; + + if (!startedUp) { + transmit_can_frame(&VOLVO_DTC_Erase, can_config.battery); //Erase any DTCs preventing startup + DTC_reset_counter++; + if (DTC_reset_counter > 1) { // Performed twice before starting + startedUp = true; + } + } + } + if (currentMillis - previousMillis60s >= INTERVAL_60_S) { + previousMillis60s = currentMillis; + if (true) { + readCellVoltages(); +#ifdef DEBUG_LOG + logging.println("Requesting cell voltages"); +#endif + } + } +} + +void setup_battery(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, "Volvo 18.83kWh battery", 63); //changed + datalayer.system.info.battery_protocol[63] = '\0'; + datalayer.battery.info.number_of_cells = 102; //was 108, changed + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; +} +#endif diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h new file mode 100644 index 00000000..1e392705 --- /dev/null +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h @@ -0,0 +1,16 @@ +#ifndef VOLVO_SPA_HYBRID_BATTERY_H +#define VOLVO_SPA_HYBRID_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED +#define MAX_PACK_VOLTAGE_DV 4294 //5000 = 500.0V +#define MIN_PACK_VOLTAGE_DV 2754 +#define MAX_CELL_DEVIATION_MV 250 +#define MAX_CELL_VOLTAGE_MV 4210 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value + +void setup_battery(void); +void transmit_can_frame(CAN_frame* tx_frame, int interface); + +#endif From a4466f4665ab5fcbe89b15279092a16093cfbe9e Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:34:09 +0100 Subject: [PATCH 02/14] Add files via upload --- Software/Software.ino | 2 +- Software/USER_SETTINGS.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index 19890bc0..b1927ed9 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -46,7 +46,7 @@ #endif // WIFI // The current software version, shown on webserver -const char* version_number = "8.7.dev"; +const char* version_number = "8.6.0"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 0baa8ae2..a9b39586 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -25,7 +25,6 @@ //#define MEB_BATTERY //#define MG_5_BATTERY //#define NISSAN_LEAF_BATTERY -//#define ORION_BMS //#define PYLON_BATTERY //#define DALY_BMS //#define RJXZS_BMS @@ -40,6 +39,7 @@ //#define TESLA_MODEL_3Y_BATTERY //#define TESLA_MODEL_SX_BATTERY //#define VOLVO_SPA_BATTERY +#define VOLVO_SPA_HYBRID_BATTERY //#define TEST_FAKE_BATTERY //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires CAN_ADDON setup) //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) @@ -48,7 +48,7 @@ //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 -//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU +#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define FERROAMP_CAN //Enable this line to emulate a "Pylon 4x96V Force H2" over CAN Bus //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus //#define GROWATT_HV_CAN //Enable this line to emulate a "Growatt High Voltage v1.10 battery" over CAN bus @@ -66,7 +66,7 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -//#define HW_LILYGO +#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT @@ -94,10 +94,10 @@ //#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery //#define LFP_CHEMISTRY //Tesla specific setting, enable this line to startup in LFP mode //#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting -//#define LOG_TO_SD //Enable this line to log diagnostic data to SD card (WARNING, raises CPU load, do not use for production) -//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card (WARNING, raises CPU load, do not use for production) +//#define LOG_TO_SD //Enable this line to log diagnostic data to SD card +//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) +#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) //#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) /* CAN options */ From bdc297048a99862b4f10c4d5080eac6378aa5e4e Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:35:15 +0100 Subject: [PATCH 03/14] Add files via upload --- Software/src/datalayer/datalayer_extended.h | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index ee2da57e..fcb4b04a 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -643,6 +643,36 @@ typedef struct { } DATALAYER_INFO_VOLVO_POLESTAR; +typedef struct { + uint16_t soc_bms = 0; + uint16_t soc_calc = 0; + uint16_t soc_rescaled = 0; + uint16_t soh_bms = 0; + uint16_t BECMsupplyVoltage = 0; + + uint16_t BECMBatteryVoltage = 0; + uint16_t BECMBatteryCurrent = 0; + uint16_t BECMUDynMaxLim = 0; + uint16_t BECMUDynMinLim = 0; + + uint16_t HvBattPwrLimDcha1 = 0; + uint16_t HvBattPwrLimDchaSoft = 0; + //uint16_t HvBattPwrLimDchaSlowAgi = 0; + //uint16_t HvBattPwrLimChrgSlowAgi = 0; + + uint8_t HVSysRlySts = 0; + uint8_t HVSysDCRlySts1 = 0; + uint8_t HVSysDCRlySts2 = 0; + uint8_t HVSysIsoRMonrSts = 0; + /** User requesting DTC reset via WebUI*/ + bool UserRequestDTCreset = false; + /** User requesting DTC readout via WebUI*/ + bool UserRequestDTCreadout = false; + /** User requesting BECM reset via WebUI*/ + bool UserRequestBECMecuReset = false; + +} DATALAYER_INFO_VOLVO_HYBRID; + typedef struct { /** uint16_t */ /** Values WIP*/ @@ -702,6 +732,7 @@ class DataLayerExtended { DATALAYER_INFO_NISSAN_LEAF nissanleaf; DATALAYER_INFO_MEB meb; DATALAYER_INFO_VOLVO_POLESTAR VolvoPolestar; + DATALAYER_INFO_VOLVO_HYBRID VolvoHybrid; DATALAYER_INFO_ZOE_PH2 zoePH2; }; From 09e5436cea0debd954346e614ed08a80b8b346ed Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:35:58 +0100 Subject: [PATCH 04/14] Add files via upload --- .../webserver/advanced_battery_html.cpp | 93 ++++++++++++++++++- Software/src/devboard/webserver/webserver.cpp | 27 ++++++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 19baf62c..239511ad 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -1321,10 +1321,101 @@ String advanced_battery_processor(const String& var) { content += ""; #endif // VOLVO_SPA_BATTERY +#ifdef VOLVO_SPA_HYBRID_BATTERY + content += "

BECM reported SOC: " + String(datalayer_extended.VolvoHybrid.soc_bms) + "

"; + content += "

Calculated SOC: " + String(datalayer_extended.VolvoHybrid.soc_calc) + "

"; + content += "

Rescaled SOC: " + String(datalayer_extended.VolvoHybrid.soc_rescaled / 10) + "

"; + content += "

BECM reported SOH: " + String(datalayer_extended.VolvoHybrid.soh_bms) + "

"; + content += "

BECM supply voltage: " + String(datalayer_extended.VolvoHybrid.BECMsupplyVoltage) + " mV

"; + + content += "

HV voltage: " + String(datalayer_extended.VolvoHybrid.BECMBatteryVoltage) + " V

"; + content += "

HV current: " + String(datalayer_extended.VolvoHybrid.BECMBatteryCurrent) + " A

"; + content += "

Dynamic max voltage: " + String(datalayer_extended.VolvoHybrid.BECMUDynMaxLim) + " V

"; + content += "

Dynamic min voltage: " + String(datalayer_extended.VolvoHybrid.BECMUDynMinLim) + " V

"; + + content += + "

Discharge power limit 1: " + String(datalayer_extended.VolvoHybrid.HvBattPwrLimDcha1) + " kW

"; + content += + "

Discharge soft power limit: " + String(datalayer_extended.VolvoHybrid.HvBattPwrLimDchaSoft) + " kW

"; + + content += "

HV system relay status: "; + switch (datalayer_extended.VolvoHybrid.HVSysRlySts) { + case 0: + content += String("Open"); + break; + case 1: + content += String("Closed"); + break; + case 2: + content += String("KeepStatus"); + break; + case 3: + content += String("OpenAndRequestActiveDischarge"); + break; + default: + content += String("Not valid"); + } + content += "

HV system relay status 1: "; + switch (datalayer_extended.VolvoHybrid.HVSysDCRlySts1) { + case 0: + content += String("Open"); + break; + case 1: + content += String("Closed"); + break; + case 2: + content += String("KeepStatus"); + break; + case 3: + content += String("Fault"); + break; + default: + content += String("Not valid"); + } + content += "

HV system relay status 2: "; + switch (datalayer_extended.VolvoHybrid.HVSysDCRlySts2) { + case 0: + content += String("Open"); + break; + case 1: + content += String("Closed"); + break; + case 2: + content += String("KeepStatus"); + break; + case 3: + content += String("Fault"); + break; + default: + content += String("Not valid"); + } + content += "

HV system isolation resistance monitoring status: "; + switch (datalayer_extended.VolvoHybrid.HVSysIsoRMonrSts) { + case 0: + content += String("Not valid 1"); + break; + case 1: + content += String("False"); + break; + case 2: + content += String("True"); + break; + case 3: + content += String("Not valid 2"); + break; + default: + content += String("Not valid"); + } + + content += "


"; + content += "
"; + content += ""; +#endif // VOLVO_SPA_HYBRID_BATTERY + #if !defined(BMW_PHEV_BATTERY) && !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_BATTERY) && \ !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ - !defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && \ + !defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \ !defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 7bdb686c..64efbdd5 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -430,6 +430,33 @@ void init_webserver() { request->send(200, "text/plain", "Updated successfully"); }); + // Route for erasing DTC on Volvo hybrid batteries + server.on("/volvoEraseDTC", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + datalayer_extended.VolvoHybrid.UserRequestDTCreset = true; + request->send(200, "text/plain", "Updated successfully"); + }); + + // Route for reading DTC on Volvo hybrid batteries + server.on("/volvoReadDTC", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + datalayer_extended.VolvoHybrid.UserRequestDTCreadout = true; + request->send(200, "text/plain", "Updated successfully"); + }); + + // Route for performing ECU reset on Volvo hybrid batteries + server.on("/volvoBECMecuReset", HTTP_GET, [](AsyncWebServerRequest* request) { + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + datalayer_extended.VolvoHybrid.UserRequestBECMecuReset = true; + request->send(200, "text/plain", "Updated successfully"); + }); + #ifdef TEST_FAKE_BATTERY // Route for editing FakeBatteryVoltage server.on("/updateFakeBatteryVoltage", HTTP_GET, [](AsyncWebServerRequest* request) { From 6f49cda6e251040e7ccafe53d61c58f2e55e8835 Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:37:00 +0100 Subject: [PATCH 05/14] Add files via upload From a2f73e8db4dd2c0cdea3dbea7f682c386b8f8c9c Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 17:06:44 +0100 Subject: [PATCH 06/14] Update Software.ino --- Software/Software.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index b1927ed9..19890bc0 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -46,7 +46,7 @@ #endif // WIFI // The current software version, shown on webserver -const char* version_number = "8.6.0"; +const char* version_number = "8.7.dev"; // Interval settings uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers From 2ca41c680d4d64bf55e29b2e2c6065d8bd818c9d Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 17:07:21 +0100 Subject: [PATCH 07/14] Update USER_SETTINGS.h --- Software/USER_SETTINGS.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index a9b39586..1971da44 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -25,6 +25,7 @@ //#define MEB_BATTERY //#define MG_5_BATTERY //#define NISSAN_LEAF_BATTERY +//#define ORION_BMS //#define PYLON_BATTERY //#define DALY_BMS //#define RJXZS_BMS @@ -39,7 +40,7 @@ //#define TESLA_MODEL_3Y_BATTERY //#define TESLA_MODEL_SX_BATTERY //#define VOLVO_SPA_BATTERY -#define VOLVO_SPA_HYBRID_BATTERY +//#define VOLVO_SPA_HYBRID_BATTERY //#define TEST_FAKE_BATTERY //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires CAN_ADDON setup) //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) From 0b2d9a990d052d5e06811fc8b65e9cf15cd16992 Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 17:08:17 +0100 Subject: [PATCH 08/14] Update USER_SETTINGS.h --- Software/USER_SETTINGS.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 1971da44..4cf14818 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -95,10 +95,10 @@ //#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery //#define LFP_CHEMISTRY //Tesla specific setting, enable this line to startup in LFP mode //#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting -//#define LOG_TO_SD //Enable this line to log diagnostic data to SD card +//#define LOG_TO_SD //Enable this line to log diagnostic data to SD card (WARNING, raises CPU load, do not use for production) //#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) +//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) //#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) /* CAN options */ From bd86b26fac82dee55095b9b4a81846acb0a9a413 Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 17:55:16 +0100 Subject: [PATCH 09/14] Update USER_SETTINGS.h --- Software/USER_SETTINGS.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 4cf14818..7cd95b4b 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -49,7 +49,7 @@ //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 -#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU +//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define FERROAMP_CAN //Enable this line to emulate a "Pylon 4x96V Force H2" over CAN Bus //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus //#define GROWATT_HV_CAN //Enable this line to emulate a "Growatt High Voltage v1.10 battery" over CAN bus @@ -67,7 +67,7 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -#define HW_LILYGO +//#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT From f4bde1169e898b24053b0b3bc3abb32d5329b7fa Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 17:56:20 +0100 Subject: [PATCH 10/14] Update USER_SETTINGS.h --- 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 7cd95b4b..55228f27 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -96,7 +96,7 @@ //#define LFP_CHEMISTRY //Tesla specific setting, enable this line to startup in LFP mode //#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting //#define LOG_TO_SD //Enable this line to log diagnostic data to SD card (WARNING, raises CPU load, do not use for production) -//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card +//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card (WARNING, raises CPU load, do not use for production) //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) //#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) //#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) From 38ab9b06fae240bff33947ebbf8107ef2bd299cb Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 17:57:19 +0100 Subject: [PATCH 11/14] Update BATTERIES.h --- Software/src/battery/BATTERIES.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 5720629d..01134f91 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -42,6 +42,10 @@ void setup_can_shunt(); #include "FOXESS-BATTERY.h" #endif +#ifdef ORION_BMS +#include "ORION-BMS.h" +#endif + #ifdef SONO_BATTERY #include "SONO-BATTERY.h" #endif From 9468c0d0d235e415186535cc333293151af00c1a Mon Sep 17 00:00:00 2001 From: nmainil <100416302+nmainil@users.noreply.github.com> Date: Sun, 23 Feb 2025 17:59:38 +0100 Subject: [PATCH 12/14] Update VOLVO-SPA-HYBRID-BATTERY.cpp --- Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp index e4712fb1..aa742507 100644 --- a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp @@ -653,7 +653,7 @@ void transmit_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Volvo 18.83kWh battery", 63); //changed + strncpy(datalayer.system.info.battery_protocol, "Volvo PHEV battery", 63); //changed datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 102; //was 108, changed datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; From 84ef08b50b9863c767a1ff23cca81458a087cefc Mon Sep 17 00:00:00 2001 From: Nicolas MAINIL Date: Mon, 24 Feb 2025 08:44:38 +0100 Subject: [PATCH 13/14] Changes from pre-commit --- .../src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp | 65 ++++++++++--------- .../webserver/advanced_battery_html.cpp | 5 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp index aa742507..475c3552 100644 --- a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp @@ -21,11 +21,11 @@ static float BATT_T_MIN = 0; //0x413 static float BATT_T_AVG = 0; //0x413 static uint16_t SOC_BMS = 0; //0X37D static uint16_t SOC_CALC = 0; -static uint16_t CELL_U_MAX = 3700; //0x37D -static uint16_t CELL_U_MIN = 3700; //0x37D -static uint8_t CELL_ID_U_MAX = 0; //0x37D -static uint16_t HvBattPwrLimDchaSoft = 0; //0x369 -static uint16_t HvBattPwrLimDcha1 = 0; //0x175 +static uint16_t CELL_U_MAX = 3700; //0x37D +static uint16_t CELL_U_MIN = 3700; //0x37D +static uint8_t CELL_ID_U_MAX = 0; //0x37D +static uint16_t HvBattPwrLimDchaSoft = 0; //0x369 +static uint16_t HvBattPwrLimDcha1 = 0; //0x175 //static uint16_t HvBattPwrLimDchaSlowAgi = 0; //0x177 //static uint16_t HvBattPwrLimChrgSlowAgi = 0; //0x177 //static uint8_t batteryModuleNumber = 0x10; // First battery module @@ -63,11 +63,12 @@ CAN_frame VOLVO_372 = { .DLC = 8, .ID = 0x372, .data = {0x00, 0xA6, 0x07, 0x14, 0x04, 0x00, 0x80, 0x00}}; //Ambient Temp -->>VERIFY this data content!!!<<-- -CAN_frame VOLVO_CELL_U_Req = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x735, - .data = {0x03, 0x22, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00}}; //Cell voltage request frame // changed +CAN_frame VOLVO_CELL_U_Req = { + .FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x735, + .data = {0x03, 0x22, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00}}; //Cell voltage request frame // changed CAN_frame VOLVO_FlowControl = {.FD = false, .ext_ID = false, .DLC = 8, @@ -383,8 +384,8 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { (rx_frame.data.u8[3] == 0x42)) // BECM module voltage supply { datalayer_extended.VolvoHybrid.BECMsupplyVoltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); - } else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[2] == 0x62) && - (rx_frame.data.u8[3] == 0x48) && (rx_frame.data.u8[4] == 0x06)) // First response frame of cell voltages //changed + } else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[2] == 0x62) && (rx_frame.data.u8[3] == 0x48) && + (rx_frame.data.u8[4] == 0x06)) // First response frame of cell voltages //changed { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); @@ -398,7 +399,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x22) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -410,7 +411,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x24) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -422,7 +423,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x26) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -434,7 +435,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x28) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -446,7 +447,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x2A) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -458,7 +459,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x2C) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -470,7 +471,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x2E) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -482,7 +483,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control rxConsecutiveFrames = 2; } else if ((rx_frame.data.u8[0] == 0x20) && (rxConsecutiveFrames == 2)) { @@ -495,7 +496,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x22) && (rxConsecutiveFrames == 2)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -507,7 +508,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x24) && (rxConsecutiveFrames == 2)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -519,7 +520,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x26) && (rxConsecutiveFrames == 2)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -531,7 +532,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x28) && (rxConsecutiveFrames == 2)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -543,7 +544,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x2A) && (rxConsecutiveFrames == 2)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -555,7 +556,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control } else if ((rx_frame.data.u8[0] == 0x2C) && (rxConsecutiveFrames == 2)) { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); @@ -567,10 +568,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; - //cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + //cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; //transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control - + if (false) // Run until last pack is read { //VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++; @@ -584,7 +585,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { min_max_voltage[0] = cell_voltages[cellcounter]; if (min_max_voltage[1] < cell_voltages[cellcounter]) min_max_voltage[1] = cell_voltages[cellcounter]; - CELL_ID_U_MAX = cellcounter; + CELL_ID_U_MAX = cellcounter; } CELL_U_MAX = min_max_voltage[1]; CELL_U_MIN = min_max_voltage[0]; @@ -652,10 +653,10 @@ void transmit_can_battery() { } } -void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Volvo PHEV battery", 63); //changed +void setup_battery(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, "Volvo PHEV battery", 63); //changed datalayer.system.info.battery_protocol[63] = '\0'; - datalayer.battery.info.number_of_cells = 102; //was 108, changed + datalayer.battery.info.number_of_cells = 102; //was 108, changed 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/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 239511ad..10421fef 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -1333,8 +1333,7 @@ String advanced_battery_processor(const String& var) { content += "

Dynamic max voltage: " + String(datalayer_extended.VolvoHybrid.BECMUDynMaxLim) + " V

"; content += "

Dynamic min voltage: " + String(datalayer_extended.VolvoHybrid.BECMUDynMinLim) + " V

"; - content += - "

Discharge power limit 1: " + String(datalayer_extended.VolvoHybrid.HvBattPwrLimDcha1) + " kW

"; + content += "

Discharge power limit 1: " + String(datalayer_extended.VolvoHybrid.HvBattPwrLimDcha1) + " kW

"; content += "

Discharge soft power limit: " + String(datalayer_extended.VolvoHybrid.HvBattPwrLimDchaSoft) + " kW

"; @@ -1415,7 +1414,7 @@ String advanced_battery_processor(const String& var) { #if !defined(BMW_PHEV_BATTERY) && !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_BATTERY) && \ !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ - !defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \ + !defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \ !defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif From 85ace280ed5313f71fe7c0dad65e2ded500dee31 Mon Sep 17 00:00:00 2001 From: Nicolas MAINIL Date: Mon, 24 Feb 2025 08:52:25 +0100 Subject: [PATCH 14/14] Corrected typo --- Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp index 475c3552..233af5ca 100644 --- a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp @@ -583,9 +583,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { for (cellcounter = 0; cellcounter < 102; cellcounter++) { if (min_max_voltage[0] > cell_voltages[cellcounter]) min_max_voltage[0] = cell_voltages[cellcounter]; - if (min_max_voltage[1] < cell_voltages[cellcounter]) + if (min_max_voltage[1] < cell_voltages[cellcounter]) { min_max_voltage[1] = cell_voltages[cellcounter]; - CELL_ID_U_MAX = cellcounter; + CELL_ID_U_MAX = cellcounter; + } } CELL_U_MAX = min_max_voltage[1]; CELL_U_MIN = min_max_voltage[0];