diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 8d192afd..33a00e95 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -2,16 +2,15 @@ #ifdef STELLANTIS_ECMP_BATTERY #include // For std::min and std::max #include "../datalayer/datalayer.h" +#include "../datalayer/datalayer_extended.h" //For More Battery Info page #include "../devboard/utils/events.h" #include "ECMP-BATTERY.h" /* TODO: This integration is still ongoing. Here is what still needs to be done in order to use this battery type -- Find battery voltage -- Find/estimate charge/discharge limits -- Find temperature - Figure out contactor closing - Which CAN messages need to be sent towards the battery? +- Handle 54/70kWh cellcounting properly */ /* Do not change code below unless you are sure what you are doing */ @@ -27,6 +26,13 @@ CAN_frame ECMP_XXX = {.FD = false, static uint16_t battery_voltage = 37000; static uint16_t battery_soc = 0; static int16_t battery_current = 0; +static uint8_t battery_MainConnectorState = 0; +static bool battery_RelayOpenRequest = false; +static uint16_t battery_AllowedMaxChargeCurrent = 0; +static uint16_t battery_AllowedMaxDischargeCurrent = 0; +static uint16_t battery_insulationResistanceKOhm = 0; +static int16_t battery_highestTemperature = 0; +static int16_t battery_lowestTemperature = 0; static uint16_t cellvoltages[108]; void update_values_battery() { @@ -35,20 +41,20 @@ void update_values_battery() { datalayer.battery.status.soh_pptt; - datalayer.battery.status.voltage_dV = (battery_voltage / 10); + datalayer.battery.status.voltage_dV = battery_voltage * 10; datalayer.battery.status.current_dA = battery_current * 10; datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - datalayer.battery.status.max_charge_power_W; + datalayer.battery.status.max_charge_power_W = battery_AllowedMaxChargeCurrent * battery_voltage; - datalayer.battery.status.max_discharge_power_W; + datalayer.battery.status.max_discharge_power_W = battery_AllowedMaxDischargeCurrent * battery_voltage; - datalayer.battery.status.temperature_min_dC; + datalayer.battery.status.temperature_min_dC = battery_lowestTemperature * 10; - datalayer.battery.status.temperature_max_dC; + datalayer.battery.status.temperature_max_dC = battery_highestTemperature * 10; // Initialize min and max, lets find which cells are min and max! uint16_t min_cell_mv_value = std::numeric_limits::max(); @@ -69,29 +75,46 @@ void update_values_battery() { datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value; datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value; + + // Update extended datalayer (More Battery Info page) + datalayer_extended.stellantisECMP.MainConnectorState = battery_MainConnectorState; + datalayer_extended.stellantisECMP.InsulationResistance = battery_insulationResistanceKOhm; } 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 0x125: + case 0x125: //Common battery_soc = (rx_frame.data.u8[0] << 2) | (rx_frame.data.u8[1] >> 6); // Byte1, bit 7 length 10 (0x3FE when abnormal) (0-1000 ppt) + battery_MainConnectorState = ((rx_frame.data.u8[2] & 0x30) >> + 4); //Byte2 , bit 4, length 2 ((00 contactors open, 01 precharged, 11 invalid)) + battery_voltage = + (rx_frame.data.u8[3] << 1) | (rx_frame.data.u8[4] >> 7); //Byte 4, bit 7, length 9 (0x1FE if invalid) battery_current = (((rx_frame.data.u8[4] & 0x7F) << 5) | (rx_frame.data.u8[5] >> 3)) - 600; // Byte5, Bit 3 length 12 (0xFFE when abnormal) (-600 to 600 , offset -600) + //battery_RelayOpenRequest = // Byte 5, bit 6, length 1 (0 no request, 1 battery requests contactor opening) + //Stellantis doc seems wrong, could Byte5 be misspelled as Byte2? Bit will otherwise collide with battery_current break; - case 0x127: + case 0x127: //DFM specific + battery_AllowedMaxChargeCurrent = + (rx_frame.data.u8[0] << 2) | + ((rx_frame.data.u8[1] & 0xC0) >> 6); //Byte 1, bit 7, length 10 (0-600A) [0x3FF if invalid] + battery_AllowedMaxDischargeCurrent = + ((rx_frame.data.u8[2] & 0x3F) << 4) | + (rx_frame.data.u8[3] >> 4); //Byte 2, bit 5, length 10 (0-600A) [0x3FF if invalid] break; - case 0x129: + case 0x129: //PSA specific break; case 0x31B: break; - case 0x358: + case 0x358: //Common + battery_highestTemperature = rx_frame.data.u8[6] - 40; + battery_lowestTemperature = rx_frame.data.u8[7] - 40; break; case 0x359: break; case 0x361: - battery_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; //TODO, not confirmed break; case 0x362: break; @@ -101,7 +124,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { break; case 0x594: break; - case 0x6D0: + case 0x6D0: //Common + battery_insulationResistanceKOhm = + (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; //Byte 2, bit 7, length 16 (0-60000 kOhm) break; case 0x6D1: break; @@ -298,9 +323,8 @@ void transmit_can_battery(unsigned long currentMillis) { } void setup_battery(void) { // Performs one time setup at startup -#ifdef DEBUG_VIA_USB - Serial.println("ECMP battery selected"); -#endif + strncpy(datalayer.system.info.battery_protocol, "Stellantis ECMP battery", 63); + datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.max_design_voltage_dV = 4546; // 454.6V, charging over this is not possible datalayer.battery.info.min_design_voltage_dV = 3210; // 321.0V, under this, discharging further is disabled diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index dcba9e2c..519e183c 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -290,6 +290,11 @@ typedef struct { uint64_t cumulative_energy_in_regen = 0; } DATALAYER_INFO_CMFAEV; +typedef struct { + uint8_t MainConnectorState = 0; + uint16_t InsulationResistance = 0; +} DATALAYER_INFO_ECMP; + typedef struct { uint8_t total_cell_count = 0; int16_t battery_12V = 0; @@ -775,6 +780,7 @@ class DataLayerExtended { DATALAYER_INFO_BYDATTO3 bydAtto3; DATALAYER_INFO_CELLPOWER cellpower; DATALAYER_INFO_CMFAEV CMFAEV; + DATALAYER_INFO_ECMP stellantisECMP; DATALAYER_INFO_KIAHYUNDAI64 KiaHyundai64; DATALAYER_INFO_TESLA tesla; DATALAYER_INFO_NISSAN_LEAF nissanleaf; diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index d9d42971..cc0e55bb 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -456,6 +456,19 @@ String advanced_battery_processor(const String& var) { "

Cumulative energy regen: " + String(datalayer_extended.CMFAEV.cumulative_energy_in_regen) + "Wh

"; #endif //CMFA_EV_BATTERY +#ifdef STELLANTIS_ECMP_BATTERY + content += "

Main Connector State: "; + if (datalayer_extended.stellantisECMP.MainConnectorState == 0) { + content += "Contactors open

"; + } else if (datalayer_extended.stellantisECMP.MainConnectorState == 0x01) { + content += "Precharged"; + } else { + content += "Invalid"; + } + content += + "

Insulation Resistance: " + String(datalayer_extended.stellantisECMP.InsulationResistance) + "kOhm

"; +#endif //STELLANTIS_ECMP_BATTERY + #ifdef KIA_HYUNDAI_64_BATTERY content += "

Cells: " + String(datalayer_extended.KiaHyundai64.total_cell_count) + "S

"; content += "

12V voltage: " + String(datalayer_extended.KiaHyundai64.battery_12V / 10.0, 1) + "

"; @@ -1487,7 +1500,8 @@ String advanced_battery_processor(const String& var) { !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(KIA_HYUNDAI_64_BATTERY) && !defined(CMFA_EV_BATTERY) //Only the listed types have extra info + !defined(KIA_HYUNDAI_64_BATTERY) && !defined(CMFA_EV_BATTERY) && \ + !defined(STELLANTIS_ECMP_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif