mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-05 19:42:08 +02:00
Merge branch 'main' of https://github.com/laughingguffly/Battery-Emulator into feature/bms_reset_at_with_ntp
This commit is contained in:
commit
7203f652cc
19 changed files with 1121 additions and 350 deletions
|
@ -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
|
||||
|
@ -131,6 +135,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
|
||||
|
|
|
@ -36,6 +36,9 @@ static int16_t BMS_highest_cell_temperature = 0;
|
|||
static int16_t BMS_average_cell_temperature = 0;
|
||||
static uint16_t BMS_lowest_cell_voltage_mV = 3300;
|
||||
static uint16_t BMS_highest_cell_voltage_mV = 3300;
|
||||
static uint8_t battery_frame_index = 0;
|
||||
#define NOF_CELLS 126
|
||||
static uint16_t battery_cellvoltages[NOF_CELLS] = {0};
|
||||
#ifdef DOUBLE_BATTERY
|
||||
static int16_t battery2_temperature_ambient = 0;
|
||||
static int16_t battery2_daughterboard_temperatures[10];
|
||||
|
@ -52,6 +55,8 @@ static int16_t BMS2_highest_cell_temperature = 0;
|
|||
static int16_t BMS2_average_cell_temperature = 0;
|
||||
static uint16_t BMS2_lowest_cell_voltage_mV = 3300;
|
||||
static uint16_t BMS2_highest_cell_voltage_mV = 3300;
|
||||
static uint8_t battery2_frame_index = 0;
|
||||
static uint16_t battery2_cellvoltages[NOF_CELLS] = {0};
|
||||
#endif //DOUBLE_BATTERY
|
||||
#define POLL_FOR_BATTERY_SOC 0x05
|
||||
#define POLL_FOR_BATTERY_VOLTAGE 0x08
|
||||
|
@ -135,6 +140,9 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
|
||||
datalayer.battery.status.cell_min_voltage_mV = BMS_lowest_cell_voltage_mV;
|
||||
|
||||
//Map all cell voltages to the global array
|
||||
memcpy(datalayer.battery.status.cell_voltages_mV, battery_cellvoltages, NOF_CELLS * sizeof(uint16_t));
|
||||
|
||||
#ifdef SKIP_TEMPERATURE_SENSOR_NUMBER
|
||||
// Initialize min and max variables for temperature calculation
|
||||
battery_calc_min_temperature = battery_daughterboard_temperatures[0];
|
||||
|
@ -253,6 +261,15 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
|||
break;
|
||||
case 0x43D:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_frame_index = rx_frame.data.u8[0];
|
||||
|
||||
if (battery_frame_index < (NOF_CELLS / 3)) {
|
||||
uint8_t base_index = battery_frame_index * 3;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
battery_cellvoltages[base_index + i] =
|
||||
(((rx_frame.data.u8[2 * (i + 1)] & 0x0F) << 8) | rx_frame.data.u8[2 * i + 1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x444:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
|
@ -479,6 +496,9 @@ void update_values_battery2() { //This function maps all the values fetched via
|
|||
datalayer.battery2.status.temperature_min_dC = BMS2_lowest_cell_temperature * 10; // Add decimals
|
||||
|
||||
datalayer.battery2.status.temperature_max_dC = BMS2_highest_cell_temperature * 10;
|
||||
|
||||
//Map all cell voltages to the global array
|
||||
memcpy(datalayer.battery2.status.cell_voltages_mV, battery2_cellvoltages, NOF_CELLS * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
||||
|
@ -547,6 +567,14 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
|||
break;
|
||||
case 0x43D:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery2_frame_index = rx_frame.data.u8[0];
|
||||
if (battery2_frame_index < (NOF_CELLS / 3)) {
|
||||
uint8_t base2_index = battery2_frame_index * 3;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
battery2_cellvoltages[base2_index + i] =
|
||||
(((rx_frame.data.u8[2 * (i + 1)] & 0x0F) << 8) | rx_frame.data.u8[2 * i + 1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x444:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
|
|
151
Software/src/battery/ORION-BMS.cpp
Normal file
151
Software/src/battery/ORION-BMS.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
#include "../include.h"
|
||||
#ifdef ORION_BMS
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "ORION-BMS.h"
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
static uint16_t cellvoltages[MAX_AMOUNT_CELLS]; //array with all the cellvoltages
|
||||
static uint16_t Maximum_Cell_Voltage = 3700;
|
||||
static uint16_t Minimum_Cell_Voltage = 3700;
|
||||
static uint16_t Pack_Health = 99;
|
||||
static int16_t Pack_Current = 0;
|
||||
static int16_t Average_Temperature = 0;
|
||||
static uint16_t Pack_Summed_Voltage = 0;
|
||||
static int16_t Average_Current = 0;
|
||||
static uint16_t High_Temperature = 0;
|
||||
static uint16_t Pack_SOC_ppt = 0;
|
||||
static uint16_t Pack_CCL = 0; //Charge current limit (A)
|
||||
static uint16_t Pack_DCL = 0; //Discharge current limit (A)
|
||||
static uint16_t Maximum_Pack_Voltage = 0;
|
||||
static uint16_t Minimum_Pack_Voltage = 0;
|
||||
static uint16_t CellID = 0;
|
||||
static uint16_t CellVoltage = 0;
|
||||
static uint16_t CellResistance = 0;
|
||||
static uint16_t CellOpenVoltage = 0;
|
||||
static uint16_t Checksum = 0;
|
||||
static uint16_t CellBalancing = 0;
|
||||
static uint8_t amount_of_detected_cells = 0;
|
||||
|
||||
void findMinMaxCellvoltages(const uint16_t arr[], size_t size, uint16_t& Minimum_Cell_Voltage,
|
||||
uint16_t& Maximum_Cell_Voltage) {
|
||||
Minimum_Cell_Voltage = std::numeric_limits<uint16_t>::max();
|
||||
Maximum_Cell_Voltage = 0;
|
||||
bool foundValidValue = false;
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (arr[i] != 0) { // Skip zero values
|
||||
if (arr[i] < Minimum_Cell_Voltage)
|
||||
Minimum_Cell_Voltage = arr[i];
|
||||
if (arr[i] > Maximum_Cell_Voltage)
|
||||
Maximum_Cell_Voltage = arr[i];
|
||||
foundValidValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If all values were zero, set min and max to 3700
|
||||
if (!foundValidValue) {
|
||||
Minimum_Cell_Voltage = 3700;
|
||||
Maximum_Cell_Voltage = 3700;
|
||||
}
|
||||
}
|
||||
|
||||
void update_values_battery() {
|
||||
|
||||
datalayer.battery.status.real_soc = Pack_SOC_ppt * 10;
|
||||
|
||||
datalayer.battery.status.soh_pptt = Pack_Health * 100;
|
||||
|
||||
datalayer.battery.status.voltage_dV = (Pack_Summed_Voltage / 10);
|
||||
|
||||
datalayer.battery.status.current_dA = Average_Current;
|
||||
|
||||
datalayer.battery.status.max_charge_power_W = (Pack_CCL * datalayer.battery.status.voltage_dV) / 100;
|
||||
|
||||
datalayer.battery.status.max_discharge_power_W = (Pack_DCL * datalayer.battery.status.voltage_dV) / 100;
|
||||
|
||||
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
||||
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
|
||||
|
||||
datalayer.battery.status.temperature_min_dC = (High_Temperature - 10);
|
||||
|
||||
datalayer.battery.status.temperature_max_dC = High_Temperature;
|
||||
|
||||
//Map all cell voltages to the global array
|
||||
memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages, MAX_AMOUNT_CELLS * sizeof(uint16_t));
|
||||
|
||||
//Find min and max cellvoltage from the array
|
||||
findMinMaxCellvoltages(cellvoltages, MAX_AMOUNT_CELLS, Minimum_Cell_Voltage, Maximum_Cell_Voltage);
|
||||
|
||||
datalayer.battery.status.cell_max_voltage_mV = Maximum_Cell_Voltage;
|
||||
|
||||
datalayer.battery.status.cell_min_voltage_mV = Minimum_Cell_Voltage;
|
||||
|
||||
//If user did not configure amount of cells correctly in the header file, update the value
|
||||
if ((amount_of_detected_cells > NUMBER_OF_CELLS) && (amount_of_detected_cells < MAX_AMOUNT_CELLS)) {
|
||||
datalayer.battery.info.number_of_cells = amount_of_detected_cells;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||
switch (rx_frame.ID) {
|
||||
case 0x356:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
Pack_Summed_Voltage = (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0];
|
||||
Average_Current = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2];
|
||||
High_Temperature = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case 0x351:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
Maximum_Pack_Voltage = (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0];
|
||||
Pack_CCL = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2];
|
||||
Pack_DCL = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
Minimum_Pack_Voltage = (rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6];
|
||||
break;
|
||||
case 0x355:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
Pack_Health = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2];
|
||||
Pack_SOC_ppt = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case 0x35A:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x36:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
CellID = rx_frame.data.u8[0];
|
||||
CellBalancing = (rx_frame.data.u8[3] & 0x80) >> 7;
|
||||
CellVoltage = (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2];
|
||||
CellResistance = ((rx_frame.data.u8[3] & 0x7F) << 8) | rx_frame.data.u8[4];
|
||||
CellOpenVoltage = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
Checksum = rx_frame.data.u8[7]; //Value = (0x36 + 8 + byte0 + byte1 + ... + byte6) & 0xFF
|
||||
|
||||
if (CellID >= MAX_AMOUNT_CELLS) {
|
||||
CellID = MAX_AMOUNT_CELLS;
|
||||
}
|
||||
cellvoltages[CellID] = (CellVoltage / 10);
|
||||
if (CellID > amount_of_detected_cells) {
|
||||
amount_of_detected_cells = CellID;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void transmit_can_battery() {
|
||||
unsigned long currentMillis = millis();
|
||||
// No transmission needed for this integration
|
||||
}
|
||||
|
||||
void setup_battery(void) { // Performs one time setup at startup
|
||||
strncpy(datalayer.system.info.battery_protocol, "DIY battery with Orion BMS (Victron setting)", 63);
|
||||
datalayer.system.info.battery_protocol[63] = '\0';
|
||||
datalayer.battery.info.number_of_cells = NUMBER_OF_CELLS;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
}
|
||||
|
||||
#endif
|
19
Software/src/battery/ORION-BMS.h
Normal file
19
Software/src/battery/ORION-BMS.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef ORION_BMS_H
|
||||
#define ORION_BMS_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
/* Change the following to suit your battery */
|
||||
#define NUMBER_OF_CELLS 96
|
||||
#define MAX_PACK_VOLTAGE_DV 5000 //5000 = 500.0V
|
||||
#define MIN_PACK_VOLTAGE_DV 1500
|
||||
#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 150
|
||||
|
||||
void setup_battery(void);
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
|
||||
#endif
|
|
@ -74,6 +74,8 @@ static uint16_t fan_start_setting_value = 0;
|
|||
static uint16_t ptc_heating_start_setting_value = 0;
|
||||
static uint16_t default_channel_state = 0;
|
||||
static uint8_t timespent_without_soc = 0;
|
||||
static bool charging_active = false;
|
||||
static bool discharging_active = false;
|
||||
|
||||
void update_values_battery() {
|
||||
|
||||
|
@ -96,7 +98,13 @@ void update_values_battery() {
|
|||
|
||||
datalayer.battery.status.voltage_dV = total_voltage;
|
||||
|
||||
datalayer.battery.status.current_dA = total_current;
|
||||
if (charging_active) {
|
||||
datalayer.battery.status.current_dA = total_current;
|
||||
} else if (discharging_active) {
|
||||
datalayer.battery.status.current_dA = -total_current;
|
||||
} else { //No direction data. Should never occur, but send current as charging, better than nothing
|
||||
datalayer.battery.status.current_dA = total_current;
|
||||
}
|
||||
|
||||
// Charge power is set in .h file
|
||||
if (datalayer.battery.status.real_soc > 9900) {
|
||||
|
@ -204,6 +212,13 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
|||
host_temperature = (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2];
|
||||
status_accounting = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4];
|
||||
equalization_starting_voltage = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
if ((rx_frame.data.u8[4] & 0x40) >> 6) {
|
||||
charging_active = true;
|
||||
discharging_active = false;
|
||||
} else {
|
||||
charging_active = false;
|
||||
discharging_active = true;
|
||||
}
|
||||
} else if (mux == 0x07) { // Cellvoltages 1-3
|
||||
cellvoltages[0] = (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2];
|
||||
cellvoltages[1] = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4];
|
||||
|
|
667
Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp
Normal file
667
Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp
Normal file
|
@ -0,0 +1,667 @@
|
|||
#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 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;
|
||||
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
|
16
Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h
Normal file
16
Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef VOLVO_SPA_HYBRID_BATTERY_H
|
||||
#define VOLVO_SPA_HYBRID_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#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
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ battery_pause_status emulator_pause_status = NORMAL;
|
|||
void update_machineryprotection() {
|
||||
// Start checking that the battery is within reason. Incase we see any funny business, raise an event!
|
||||
|
||||
// Pause function is on
|
||||
if (emulator_pause_request_ON) {
|
||||
// Pause function is on OR we have a critical fault event active
|
||||
if (emulator_pause_request_ON || (datalayer.battery.status.bms_status == FAULT)) {
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
}
|
||||
|
|
|
@ -1321,10 +1321,100 @@ String advanced_battery_processor(const String& var) {
|
|||
content += "<button onclick='Volvo_BECMecuReset()'>Restart BECM module</button>";
|
||||
#endif // VOLVO_SPA_BATTERY
|
||||
|
||||
#ifdef VOLVO_SPA_HYBRID_BATTERY
|
||||
content += "<h4>BECM reported SOC: " + String(datalayer_extended.VolvoHybrid.soc_bms) + "</h4>";
|
||||
content += "<h4>Calculated SOC: " + String(datalayer_extended.VolvoHybrid.soc_calc) + "</h4>";
|
||||
content += "<h4>Rescaled SOC: " + String(datalayer_extended.VolvoHybrid.soc_rescaled / 10) + "</h4>";
|
||||
content += "<h4>BECM reported SOH: " + String(datalayer_extended.VolvoHybrid.soh_bms) + "</h4>";
|
||||
content += "<h4>BECM supply voltage: " + String(datalayer_extended.VolvoHybrid.BECMsupplyVoltage) + " mV</h4>";
|
||||
|
||||
content += "<h4>HV voltage: " + String(datalayer_extended.VolvoHybrid.BECMBatteryVoltage) + " V</h4>";
|
||||
content += "<h4>HV current: " + String(datalayer_extended.VolvoHybrid.BECMBatteryCurrent) + " A</h4>";
|
||||
content += "<h4>Dynamic max voltage: " + String(datalayer_extended.VolvoHybrid.BECMUDynMaxLim) + " V</h4>";
|
||||
content += "<h4>Dynamic min voltage: " + String(datalayer_extended.VolvoHybrid.BECMUDynMinLim) + " V</h4>";
|
||||
|
||||
content += "<h4>Discharge power limit 1: " + String(datalayer_extended.VolvoHybrid.HvBattPwrLimDcha1) + " kW</h4>";
|
||||
content +=
|
||||
"<h4>Discharge soft power limit: " + String(datalayer_extended.VolvoHybrid.HvBattPwrLimDchaSoft) + " kW</h4>";
|
||||
|
||||
content += "<h4>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 += "</h4><h4>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 += "</h4><h4>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 += "</h4><h4>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 += "<br><br><button onclick='Volvo_askEraseDTC()'>Erase DTC</button><br>";
|
||||
content += "<button onclick='Volvo_askReadDTC()'>Read DTC (result must be checked in CANlog)</button><br>";
|
||||
content += "<button onclick='Volvo_BECMecuReset()'>Restart BECM module</button>";
|
||||
#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
|
||||
|
|
|
@ -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) {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -3,6 +3,6 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
|
||||
extern const uint8_t ELEGANT_HTML[10214];
|
||||
extern const uint8_t ELEGANT_HTML[41354];
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue