Merge pull request #642 from dalathegreat/feature/bolt-ampera-battery

Feature: Add base for Bolt-Ampera battery
This commit is contained in:
Daniel Öster 2024-12-23 16:26:08 +02:00 committed by GitHub
commit 47c99f9c3a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 1019 additions and 3 deletions

View file

@ -11,6 +11,7 @@
/* Select battery used */
//#define BMW_I3_BATTERY
//#define BMW_IX_BATTERY
//#define BOLT_AMPERA_BATTERY
//#define BYD_ATTO_3_BATTERY
//#define CELLPOWER_BMS
//#define CHADEMO_BATTERY //NOTE: inherently enables CONTACTOR_CONTROL below

View file

@ -10,6 +10,10 @@
#include "BMW-IX-BATTERY.h"
#endif
#ifdef BOLT_AMPERA_BATTERY
#include "BOLT-AMPERA-BATTERY.h"
#endif
#ifdef BYD_ATTO_3_BATTERY
#include "BYD-ATTO-3-BATTERY.h"
#endif

View file

@ -0,0 +1,789 @@
#include "../include.h"
#ifdef BOLT_AMPERA_BATTERY
#include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h"
#include "../devboard/utils/events.h"
#include "BOLT-AMPERA-BATTERY.h"
/*
TODOs left for this implementation
- The battery has 3 CAN ports. One of them is responsible for the 7E4 polls, the other for the 7E7 polls
- Current implementation only seems to get the 7E7 polls working.
- Could on of the CAN channels be GMLAN?
- The values missing for a working implementation is:
- SOC% missing! This is absolutely mandatory to fix before starting to use this!
- Capacity (kWh) (can be estimated)
- Charge max power (can be estimated)
- Discharge max power (can be estimated)
- SOH% (low prio))
*/
/* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis20ms = 0; // will store last time a 20ms CAN Message was send
static unsigned long previousMillis100ms = 0; // will store last time a 100ms CAN Message was send
static unsigned long previousMillis120ms = 0; // will store last time a 120ms CAN Message was send
CAN_frame BOLT_778 = {.FD = false, // Unsure of what this message is, added only as example
.ext_ID = false,
.DLC = 7,
.ID = 0x778,
.data = {0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BOLT_POLL_7E4 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E4,
.data = {0x03, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BOLT_ACK_7E4 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E4,
.data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BOLT_POLL_7E7 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E7,
.data = {0x03, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BOLT_ACK_7E7 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E7,
.data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
// 7E4 Battery , reply 000007EC
// 7E7 Battery (Cell voltages), reply 000007EF
static uint16_t battery_cell_voltages[96]; //array with all the cellvoltages
static uint16_t battery_capacity_my17_18 = 0;
static uint16_t battery_capacity_my19plus = 0;
static uint16_t battery_SOC_display = 0;
static uint16_t battery_SOC_raw_highprec = 0;
static uint16_t battery_max_temperature = 0;
static uint16_t battery_min_temperature = 0;
static uint16_t battery_min_cell_voltage = 0;
static uint16_t battery_max_cell_voltage = 0;
static uint16_t battery_internal_resistance = 0;
static uint16_t battery_lowest_cell = 0;
static uint16_t battery_highest_cell = 0;
static uint16_t battery_voltage_polled = 0;
static uint16_t battery_voltage_periodic = 0;
static uint16_t battery_vehicle_isolation = 0;
static uint16_t battery_isolation_kohm = 0;
static uint16_t battery_HV_locked = 0;
static uint16_t battery_crash_event = 0;
static uint16_t battery_HVIL = 0;
static uint16_t battery_HVIL_status = 0;
static uint16_t battery_5V_ref = 0;
static int16_t battery_current_7E4 = 0;
static int16_t battery_module_temp_1 = 0;
static int16_t battery_module_temp_2 = 0;
static int16_t battery_module_temp_3 = 0;
static int16_t battery_module_temp_4 = 0;
static int16_t battery_module_temp_5 = 0;
static int16_t battery_module_temp_6 = 0;
static uint16_t battery_cell_average_voltage = 0;
static uint16_t battery_cell_average_voltage_2 = 0;
static uint16_t battery_terminal_voltage = 0;
static uint16_t battery_ignition_power_mode = 0;
static int16_t battery_current_7E7 = 0;
static int16_t temperature_1 = 0;
static int16_t temperature_2 = 0;
static int16_t temperature_3 = 0;
static int16_t temperature_4 = 0;
static int16_t temperature_5 = 0;
static int16_t temperature_6 = 0;
static int16_t temperature_highest = 0;
static int16_t temperature_lowest = 0;
static uint8_t mux = 0;
static uint8_t poll_index_7E4 = 0;
static uint16_t currentpoll_7E4 = POLL_7E4_CAPACITY_EST_GEN1;
static uint16_t reply_poll_7E4 = 0;
static uint8_t poll_index_7E7 = 0;
static uint16_t currentpoll_7E7 = POLL_7E7_CURRENT;
static uint16_t reply_poll_7E7 = 0;
const uint16_t poll_commands_7E4[19] = {POLL_7E4_CAPACITY_EST_GEN1,
POLL_7E4_CAPACITY_EST_GEN2,
POLL_7E4_SOC_DISPLAY,
POLL_7E4_SOC_RAW_HIGHPREC,
POLL_7E4_MAX_TEMPERATURE,
POLL_7E4_MIN_TEMPERATURE,
POLL_7E4_MIN_CELL_V,
POLL_7E4_MAX_CELL_V,
POLL_7E4_INTERNAL_RES,
POLL_7E4_LOWEST_CELL_NUMBER,
POLL_7E4_HIGHEST_CELL_NUMBER,
POLL_7E4_VOLTAGE,
POLL_7E4_VEHICLE_ISOLATION,
POLL_7E4_ISOLATION_TEST_KOHM,
POLL_7E4_HV_LOCKED_OUT,
POLL_7E4_CRASH_EVENT,
POLL_7E4_HVIL,
POLL_7E4_HVIL_STATUS,
POLL_7E4_CURRENT};
const uint16_t poll_commands_7E7[108] = {POLL_7E7_CURRENT, POLL_7E7_5V_REF,
POLL_7E7_MODULE_TEMP_1, POLL_7E7_MODULE_TEMP_2,
POLL_7E7_MODULE_TEMP_3, POLL_7E7_MODULE_TEMP_4,
POLL_7E7_MODULE_TEMP_5, POLL_7E7_MODULE_TEMP_6,
POLL_7E7_CELL_AVG_VOLTAGE, POLL_7E7_CELL_AVG_VOLTAGE_2,
POLL_7E7_TERMINAL_VOLTAGE, POLL_7E7_IGNITION_POWER_MODE,
POLL_7E7_CELL_01, POLL_7E7_CELL_02,
POLL_7E7_CELL_03, POLL_7E7_CELL_04,
POLL_7E7_CELL_05, POLL_7E7_CELL_06,
POLL_7E7_CELL_07, POLL_7E7_CELL_08,
POLL_7E7_CELL_09, POLL_7E7_CELL_10,
POLL_7E7_CELL_11, POLL_7E7_CELL_12,
POLL_7E7_CELL_13, POLL_7E7_CELL_14,
POLL_7E7_CELL_15, POLL_7E7_CELL_16,
POLL_7E7_CELL_17, POLL_7E7_CELL_18,
POLL_7E7_CELL_19, POLL_7E7_CELL_20,
POLL_7E7_CELL_21, POLL_7E7_CELL_22,
POLL_7E7_CELL_23, POLL_7E7_CELL_24,
POLL_7E7_CELL_25, POLL_7E7_CELL_26,
POLL_7E7_CELL_27, POLL_7E7_CELL_28,
POLL_7E7_CELL_29, POLL_7E7_CELL_30,
POLL_7E7_CELL_31, POLL_7E7_CELL_32,
POLL_7E7_CELL_33, POLL_7E7_CELL_34,
POLL_7E7_CELL_35, POLL_7E7_CELL_36,
POLL_7E7_CELL_37, POLL_7E7_CELL_38,
POLL_7E7_CELL_39, POLL_7E7_CELL_40,
POLL_7E7_CELL_41, POLL_7E7_CELL_42,
POLL_7E7_CELL_43, POLL_7E7_CELL_44,
POLL_7E7_CELL_45, POLL_7E7_CELL_46,
POLL_7E7_CELL_47, POLL_7E7_CELL_48,
POLL_7E7_CELL_49, POLL_7E7_CELL_50,
POLL_7E7_CELL_51, POLL_7E7_CELL_52,
POLL_7E7_CELL_53, POLL_7E7_CELL_54,
POLL_7E7_CELL_55, POLL_7E7_CELL_56,
POLL_7E7_CELL_57, POLL_7E7_CELL_58,
POLL_7E7_CELL_59, POLL_7E7_CELL_60,
POLL_7E7_CELL_61, POLL_7E7_CELL_62,
POLL_7E7_CELL_63, POLL_7E7_CELL_64,
POLL_7E7_CELL_65, POLL_7E7_CELL_66,
POLL_7E7_CELL_67, POLL_7E7_CELL_68,
POLL_7E7_CELL_69, POLL_7E7_CELL_70,
POLL_7E7_CELL_71, POLL_7E7_CELL_72,
POLL_7E7_CELL_73, POLL_7E7_CELL_74,
POLL_7E7_CELL_75, POLL_7E7_CELL_76,
POLL_7E7_CELL_77, POLL_7E7_CELL_78,
POLL_7E7_CELL_79, POLL_7E7_CELL_80,
POLL_7E7_CELL_81, POLL_7E7_CELL_82,
POLL_7E7_CELL_83, POLL_7E7_CELL_84,
POLL_7E7_CELL_85, POLL_7E7_CELL_86,
POLL_7E7_CELL_87, POLL_7E7_CELL_88,
POLL_7E7_CELL_89, POLL_7E7_CELL_90,
POLL_7E7_CELL_91, POLL_7E7_CELL_92,
POLL_7E7_CELL_93, POLL_7E7_CELL_94,
POLL_7E7_CELL_95, POLL_7E7_CELL_96};
void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer
datalayer.battery.status.real_soc = battery_SOC_display;
//datalayer.battery.status.voltage_dV = battery_voltage * 0.52;
datalayer.battery.status.voltage_dV = (battery_voltage_periodic / 8) * 10;
datalayer.battery.status.current_dA = battery_current_7E7;
datalayer.battery.info.total_capacity_Wh;
datalayer.battery.status.remaining_capacity_Wh;
datalayer.battery.status.soh_pptt;
datalayer.battery.status.max_discharge_power_W;
datalayer.battery.status.max_charge_power_W;
// Store temperatures in an array
int16_t temperatures[] = {temperature_1, temperature_2, temperature_3, temperature_4, temperature_5, temperature_6};
// Initialize highest and lowest to the first element
temperature_highest = temperatures[0];
temperature_lowest = temperatures[0];
// Iterate through the array to find the highest and lowest values
for (uint8_t i = 1; i < 6; ++i) {
if (temperatures[i] > temperature_highest) {
temperature_highest = temperatures[i];
}
if (temperatures[i] < temperature_lowest) {
temperature_lowest = temperatures[i];
}
}
datalayer.battery.status.temperature_min_dC = temperature_lowest * 10;
datalayer.battery.status.temperature_max_dC = temperature_highest * 10;
//Map all cell voltages to the global array
memcpy(datalayer.battery.status.cell_voltages_mV, battery_cell_voltages, 96 * sizeof(uint16_t));
// Update webserver datalayer
datalayer_extended.boltampera.battery_5V_ref = battery_5V_ref;
datalayer_extended.boltampera.battery_module_temp_1 = battery_module_temp_1;
datalayer_extended.boltampera.battery_module_temp_2 = battery_module_temp_2;
datalayer_extended.boltampera.battery_module_temp_3 = battery_module_temp_3;
datalayer_extended.boltampera.battery_module_temp_4 = battery_module_temp_4;
datalayer_extended.boltampera.battery_module_temp_5 = battery_module_temp_5;
datalayer_extended.boltampera.battery_module_temp_6 = battery_module_temp_6;
datalayer_extended.boltampera.battery_cell_average_voltage = battery_cell_average_voltage;
datalayer_extended.boltampera.battery_cell_average_voltage_2 = battery_cell_average_voltage_2;
datalayer_extended.boltampera.battery_terminal_voltage = battery_terminal_voltage;
datalayer_extended.boltampera.battery_ignition_power_mode = battery_ignition_power_mode;
datalayer_extended.boltampera.battery_current_7E7 = battery_current_7E7;
datalayer_extended.boltampera.battery_capacity_my17_18 = battery_capacity_my17_18;
datalayer_extended.boltampera.battery_capacity_my19plus = battery_capacity_my19plus;
datalayer_extended.boltampera.battery_SOC_display = battery_SOC_display;
datalayer_extended.boltampera.battery_SOC_raw_highprec = battery_SOC_raw_highprec;
datalayer_extended.boltampera.battery_max_temperature = battery_max_temperature;
datalayer_extended.boltampera.battery_min_temperature = battery_min_temperature;
datalayer_extended.boltampera.battery_min_cell_voltage = battery_min_cell_voltage;
datalayer_extended.boltampera.battery_max_cell_voltage = battery_max_cell_voltage;
datalayer_extended.boltampera.battery_lowest_cell = battery_lowest_cell;
datalayer_extended.boltampera.battery_highest_cell = battery_highest_cell;
datalayer_extended.boltampera.battery_internal_resistance = battery_internal_resistance;
datalayer_extended.boltampera.battery_voltage_polled = battery_voltage_polled;
datalayer_extended.boltampera.battery_vehicle_isolation = battery_vehicle_isolation;
datalayer_extended.boltampera.battery_isolation_kohm = battery_isolation_kohm;
datalayer_extended.boltampera.battery_HV_locked = battery_HV_locked;
datalayer_extended.boltampera.battery_crash_event = battery_crash_event;
datalayer_extended.boltampera.battery_HVIL = battery_HVIL;
datalayer_extended.boltampera.battery_HVIL_status = battery_HVIL_status;
datalayer_extended.boltampera.battery_current_7E4 = battery_current_7E4;
}
void receive_can_battery(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x200:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
break;
case 0x202:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
break;
case 0x204:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
break;
case 0x206:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
break;
case 0x208:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
break;
case 0x20C:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x216:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x2C7:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
battery_voltage_periodic = (rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[4] >> 4);
break;
case 0x260:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x270:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x272:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x274:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x302:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
temperature_1 = ((rx_frame.data.u8[1] / 2) - 40); //Module 1 Temperature
temperature_2 = ((rx_frame.data.u8[2] / 2) - 40); //Module 2 Temperature
temperature_3 = ((rx_frame.data.u8[3] / 2) - 40); //Module 3 Temperature
temperature_4 = ((rx_frame.data.u8[4] / 2) - 40); //Module 4 Temperature
temperature_5 = ((rx_frame.data.u8[5] / 2) - 40); //Module 5 Temperature
temperature_6 = ((rx_frame.data.u8[6] / 2) - 40); //Module 6 Temperature
break;
case 0x3E3:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x460:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x5EF:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x7EC: //When polling 7E4 BMS replies with 7EC ??
if (rx_frame.data.u8[0] == 0x10) { //"PID Header"
transmit_can(&BOLT_ACK_7E4, can_config.battery);
}
//Frame 2 & 3 contains reply
reply_poll_7E4 = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
switch (reply_poll_7E4) {
case POLL_7E4_CAPACITY_EST_GEN1:
battery_capacity_my17_18 = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
break;
case POLL_7E4_CAPACITY_EST_GEN2:
battery_capacity_my19plus = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
break;
case POLL_7E4_SOC_DISPLAY:
battery_SOC_display = ((rx_frame.data.u8[4] * 100) / 255);
break;
case POLL_7E4_SOC_RAW_HIGHPREC:
battery_SOC_raw_highprec = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 100) / 65535);
break;
case POLL_7E4_MAX_TEMPERATURE:
battery_max_temperature = (rx_frame.data.u8[4] - 40);
break;
case POLL_7E4_MIN_TEMPERATURE:
battery_min_temperature = (rx_frame.data.u8[4] - 40);
break;
case POLL_7E4_MIN_CELL_V:
battery_min_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 1666;
break;
case POLL_7E4_MAX_CELL_V:
battery_max_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 1666;
break;
case POLL_7E4_INTERNAL_RES:
battery_internal_resistance = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 2;
break;
case POLL_7E4_LOWEST_CELL_NUMBER:
battery_lowest_cell = rx_frame.data.u8[4];
break;
case POLL_7E4_HIGHEST_CELL_NUMBER:
battery_highest_cell = rx_frame.data.u8[4];
break;
case POLL_7E4_VOLTAGE:
battery_voltage_polled = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 0.52);
break;
case POLL_7E4_VEHICLE_ISOLATION:
battery_vehicle_isolation = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
break;
case POLL_7E4_ISOLATION_TEST_KOHM:
battery_isolation_kohm = (rx_frame.data.u8[4] * 25);
break;
case POLL_7E4_HV_LOCKED_OUT:
battery_HV_locked = rx_frame.data.u8[4];
break;
case POLL_7E4_CRASH_EVENT:
battery_crash_event = rx_frame.data.u8[4];
break;
case POLL_7E4_HVIL:
battery_HVIL = rx_frame.data.u8[4];
break;
case POLL_7E4_HVIL_STATUS:
battery_HVIL_status = rx_frame.data.u8[4];
break;
case POLL_7E4_CURRENT:
battery_current_7E4 = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / (-6.675));
break;
default:
break;
}
break;
case 0x7EF: //When polling 7E7 BMS replies with 7EF
if (rx_frame.data.u8[0] == 0x10) { //"PID Header"
transmit_can(&BOLT_ACK_7E7, can_config.battery);
}
//Frame 2 & 3 contains reply
reply_poll_7E7 = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
switch (reply_poll_7E7) {
case POLL_7E7_CURRENT:
battery_current_7E7 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
break;
case POLL_7E7_5V_REF:
battery_5V_ref = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5) / 65535);
break;
case POLL_7E7_MODULE_TEMP_1:
battery_module_temp_1 = (rx_frame.data.u8[4] - 40);
break;
case POLL_7E7_MODULE_TEMP_2:
battery_module_temp_2 = (rx_frame.data.u8[4] - 40);
break;
case POLL_7E7_MODULE_TEMP_3:
battery_module_temp_3 = (rx_frame.data.u8[4] - 40);
break;
case POLL_7E7_MODULE_TEMP_4:
battery_module_temp_4 = (rx_frame.data.u8[4] - 40);
break;
case POLL_7E7_MODULE_TEMP_5:
battery_module_temp_5 = (rx_frame.data.u8[4] - 40);
break;
case POLL_7E7_MODULE_TEMP_6:
battery_module_temp_6 = (rx_frame.data.u8[4] - 40);
break;
case POLL_7E7_CELL_AVG_VOLTAGE:
battery_cell_average_voltage = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_AVG_VOLTAGE_2:
battery_cell_average_voltage_2 = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 8000) * 1000);
break;
case POLL_7E7_TERMINAL_VOLTAGE:
battery_terminal_voltage = rx_frame.data.u8[4] * 2;
break;
case POLL_7E7_IGNITION_POWER_MODE:
battery_ignition_power_mode = rx_frame.data.u8[4];
break;
case POLL_7E7_CELL_01:
battery_cell_voltages[0] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_02:
battery_cell_voltages[1] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_03:
battery_cell_voltages[2] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_04:
battery_cell_voltages[3] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_05:
battery_cell_voltages[4] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_06:
battery_cell_voltages[5] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_07:
battery_cell_voltages[6] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_08:
battery_cell_voltages[7] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_09:
battery_cell_voltages[8] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_10:
battery_cell_voltages[9] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_11:
battery_cell_voltages[10] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_12:
battery_cell_voltages[11] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_13:
battery_cell_voltages[12] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_14:
battery_cell_voltages[13] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_15:
battery_cell_voltages[14] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_16:
battery_cell_voltages[15] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_17:
battery_cell_voltages[16] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_18:
battery_cell_voltages[17] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_19:
battery_cell_voltages[18] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_20:
battery_cell_voltages[19] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_21:
battery_cell_voltages[20] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_22:
battery_cell_voltages[21] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_23:
battery_cell_voltages[22] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_24:
battery_cell_voltages[23] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_25:
battery_cell_voltages[24] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_26:
battery_cell_voltages[25] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_27:
battery_cell_voltages[26] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_28:
battery_cell_voltages[27] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_29:
battery_cell_voltages[28] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_30:
battery_cell_voltages[29] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_31:
battery_cell_voltages[30] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_32:
battery_cell_voltages[31] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_33:
battery_cell_voltages[32] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_34:
battery_cell_voltages[33] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_35:
battery_cell_voltages[34] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_36:
battery_cell_voltages[35] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_37:
battery_cell_voltages[36] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_38:
battery_cell_voltages[37] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_39:
battery_cell_voltages[38] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_40:
battery_cell_voltages[39] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_41:
battery_cell_voltages[40] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_42:
battery_cell_voltages[41] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_43:
battery_cell_voltages[42] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_44:
battery_cell_voltages[43] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_45:
battery_cell_voltages[44] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_46:
battery_cell_voltages[45] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_47:
battery_cell_voltages[46] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_48:
battery_cell_voltages[47] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_49:
battery_cell_voltages[48] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_50:
battery_cell_voltages[49] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_51:
battery_cell_voltages[50] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_52:
battery_cell_voltages[51] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_53:
battery_cell_voltages[52] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_54:
battery_cell_voltages[53] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_55:
battery_cell_voltages[54] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_56:
battery_cell_voltages[55] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_57:
battery_cell_voltages[56] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_58:
battery_cell_voltages[57] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_59:
battery_cell_voltages[58] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_60:
battery_cell_voltages[59] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_61:
battery_cell_voltages[60] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_62:
battery_cell_voltages[61] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_63:
battery_cell_voltages[62] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_64:
battery_cell_voltages[63] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_65:
battery_cell_voltages[64] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_66:
battery_cell_voltages[65] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_67:
battery_cell_voltages[66] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_68:
battery_cell_voltages[67] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_69:
battery_cell_voltages[68] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_70:
battery_cell_voltages[69] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_71:
battery_cell_voltages[70] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_72:
battery_cell_voltages[71] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_73:
battery_cell_voltages[72] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_74:
battery_cell_voltages[73] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_75:
battery_cell_voltages[74] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_76:
battery_cell_voltages[75] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_77:
battery_cell_voltages[76] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_78:
battery_cell_voltages[77] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_79:
battery_cell_voltages[78] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_80:
battery_cell_voltages[79] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_81:
battery_cell_voltages[80] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_82:
battery_cell_voltages[81] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_83:
battery_cell_voltages[82] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_84:
battery_cell_voltages[83] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_85:
battery_cell_voltages[84] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_86:
battery_cell_voltages[85] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_87:
battery_cell_voltages[86] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_88:
battery_cell_voltages[87] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_89:
battery_cell_voltages[88] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_90:
battery_cell_voltages[89] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_91:
battery_cell_voltages[90] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_92:
battery_cell_voltages[91] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_93:
battery_cell_voltages[92] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_94:
battery_cell_voltages[93] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_95:
battery_cell_voltages[94] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
case POLL_7E7_CELL_96:
battery_cell_voltages[95] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535);
break;
default:
break;
}
default:
break;
}
}
void send_can_battery() {
unsigned long currentMillis = millis();
//Send 20ms message
if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis20ms >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20ms));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis20ms = currentMillis;
transmit_can(&BOLT_778, can_config.battery);
}
//Send 100ms message
if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) {
previousMillis100ms = currentMillis;
// Update current poll from the 7E7 array
currentpoll_7E7 = poll_commands_7E7[poll_index_7E7];
poll_index_7E7 = (poll_index_7E7 + 1) % 108;
BOLT_POLL_7E7.data.u8[2] = (uint8_t)((currentpoll_7E7 & 0xFF00) >> 8);
BOLT_POLL_7E7.data.u8[3] = (uint8_t)(currentpoll_7E7 & 0x00FF);
transmit_can(&BOLT_POLL_7E7, can_config.battery);
}
//Send 120ms message
if (currentMillis - previousMillis120ms >= 120) {
previousMillis120ms = currentMillis;
// Update current poll from the 7E4 array
currentpoll_7E4 = poll_commands_7E4[poll_index_7E4];
poll_index_7E4 = (poll_index_7E4 + 1) % 19;
BOLT_POLL_7E4.data.u8[2] = (uint8_t)((currentpoll_7E4 & 0xFF00) >> 8);
BOLT_POLL_7E4.data.u8[3] = (uint8_t)(currentpoll_7E4 & 0x00FF);
transmit_can(&BOLT_POLL_7E4, can_config.battery);
}
}
void setup_battery(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, "Chevrolet Bolt EV/Opel Ampera-e", 63);
datalayer.system.info.battery_protocol[63] = '\0';
datalayer.battery.info.number_of_cells = 96;
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
datalayer.system.status.battery_allows_contactor_closing = true;
}
#endif

View file

@ -0,0 +1,146 @@
#ifndef BOLT_AMPERA_BATTERY_H
#define BOLT_AMPERA_BATTERY_H
#include <Arduino.h>
#include "../include.h"
#define BATTERY_SELECTED
#define MAX_PACK_VOLTAGE_DV 4150 //5000 = 500.0V
#define MIN_PACK_VOLTAGE_DV 2500
#define MAX_CELL_DEVIATION_MV 500
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
#define POLL_7E4_CAPACITY_EST_GEN1 0x41A3
#define POLL_7E4_CAPACITY_EST_GEN2 0x45F9
#define POLL_7E4_SOC_DISPLAY 0x8334
#define POLL_7E4_SOC_RAW_HIGHPREC 0x43AF
#define POLL_7E4_MAX_TEMPERATURE 0x4349
#define POLL_7E4_MIN_TEMPERATURE 0x434A
#define POLL_7E4_MIN_CELL_V 0x4329
#define POLL_7E4_MAX_CELL_V 0x432B
#define POLL_7E4_INTERNAL_RES 0x40E9
#define POLL_7E4_LOWEST_CELL_NUMBER 0x433B
#define POLL_7E4_HIGHEST_CELL_NUMBER 0x433C
#define POLL_7E4_VOLTAGE 0x432D
#define POLL_7E4_VEHICLE_ISOLATION 0x41EC
#define POLL_7E4_ISOLATION_TEST_KOHM 0x43A6
#define POLL_7E4_HV_LOCKED_OUT 0x44F8
#define POLL_7E4_CRASH_EVENT 0x4522
#define POLL_7E4_HVIL 0x4310
#define POLL_7E4_HVIL_STATUS 0x4311
#define POLL_7E4_CURRENT 0x4356
#define POLL_7E7_CURRENT 0x40D4
#define POLL_7E7_5V_REF 0x40D3
#define POLL_7E7_MODULE_TEMP_1 0x40D7
#define POLL_7E7_MODULE_TEMP_2 0x40D9
#define POLL_7E7_MODULE_TEMP_3 0x40DB
#define POLL_7E7_MODULE_TEMP_4 0x40DD
#define POLL_7E7_MODULE_TEMP_5 0x40DF
#define POLL_7E7_MODULE_TEMP_6 0x40E1
#define POLL_7E7_CELL_AVG_VOLTAGE 0xC218
#define POLL_7E7_CELL_AVG_VOLTAGE_2 0x44B9
#define POLL_7E7_TERMINAL_VOLTAGE 0x82A3
#define POLL_7E7_IGNITION_POWER_MODE 0x8002
#define POLL_7E7_CELL_01 0x4181
#define POLL_7E7_CELL_02 0x4182
#define POLL_7E7_CELL_03 0x4183
#define POLL_7E7_CELL_04 0x4184
#define POLL_7E7_CELL_05 0x4185
#define POLL_7E7_CELL_06 0x4186
#define POLL_7E7_CELL_07 0x4187
#define POLL_7E7_CELL_08 0x4188
#define POLL_7E7_CELL_09 0x4189
#define POLL_7E7_CELL_10 0x418A
#define POLL_7E7_CELL_11 0x418B
#define POLL_7E7_CELL_12 0x418C
#define POLL_7E7_CELL_13 0x418D
#define POLL_7E7_CELL_14 0x418E
#define POLL_7E7_CELL_15 0x418F
#define POLL_7E7_CELL_16 0x4190
#define POLL_7E7_CELL_17 0x4191
#define POLL_7E7_CELL_18 0x4192
#define POLL_7E7_CELL_19 0x4193
#define POLL_7E7_CELL_20 0x4194
#define POLL_7E7_CELL_21 0x4195
#define POLL_7E7_CELL_22 0x4196
#define POLL_7E7_CELL_23 0x4197
#define POLL_7E7_CELL_24 0x4198
#define POLL_7E7_CELL_25 0x4199
#define POLL_7E7_CELL_26 0x419A
#define POLL_7E7_CELL_27 0x419B
#define POLL_7E7_CELL_28 0x419C
#define POLL_7E7_CELL_29 0x419D
#define POLL_7E7_CELL_30 0x419E
#define POLL_7E7_CELL_31 0x419F
#define POLL_7E7_CELL_32 0x4200
#define POLL_7E7_CELL_33 0x4201
#define POLL_7E7_CELL_34 0x4202
#define POLL_7E7_CELL_35 0x4203
#define POLL_7E7_CELL_36 0x4204
#define POLL_7E7_CELL_37 0x4205
#define POLL_7E7_CELL_38 0x4206
#define POLL_7E7_CELL_39 0x4207
#define POLL_7E7_CELL_40 0x4208
#define POLL_7E7_CELL_41 0x4209
#define POLL_7E7_CELL_42 0x420A
#define POLL_7E7_CELL_43 0x420B
#define POLL_7E7_CELL_44 0x420C
#define POLL_7E7_CELL_45 0x420D
#define POLL_7E7_CELL_46 0x420E
#define POLL_7E7_CELL_47 0x420F
#define POLL_7E7_CELL_48 0x4210
#define POLL_7E7_CELL_49 0x4211
#define POLL_7E7_CELL_50 0x4212
#define POLL_7E7_CELL_51 0x4213
#define POLL_7E7_CELL_52 0x4214
#define POLL_7E7_CELL_53 0x4215
#define POLL_7E7_CELL_54 0x4216
#define POLL_7E7_CELL_55 0x4217
#define POLL_7E7_CELL_56 0x4218
#define POLL_7E7_CELL_57 0x4219
#define POLL_7E7_CELL_58 0x421A
#define POLL_7E7_CELL_59 0x421B
#define POLL_7E7_CELL_60 0x421C
#define POLL_7E7_CELL_61 0x421D
#define POLL_7E7_CELL_62 0x421E
#define POLL_7E7_CELL_63 0x421F
#define POLL_7E7_CELL_64 0x4220
#define POLL_7E7_CELL_65 0x4221
#define POLL_7E7_CELL_66 0x4222
#define POLL_7E7_CELL_67 0x4223
#define POLL_7E7_CELL_68 0x4224
#define POLL_7E7_CELL_69 0x4225
#define POLL_7E7_CELL_70 0x4226
#define POLL_7E7_CELL_71 0x4227
#define POLL_7E7_CELL_72 0x4228
#define POLL_7E7_CELL_73 0x4229
#define POLL_7E7_CELL_74 0x422A
#define POLL_7E7_CELL_75 0x422B
#define POLL_7E7_CELL_76 0x422C
#define POLL_7E7_CELL_77 0x422D
#define POLL_7E7_CELL_78 0x422E
#define POLL_7E7_CELL_79 0x422F
#define POLL_7E7_CELL_80 0x4230
#define POLL_7E7_CELL_81 0x4231
#define POLL_7E7_CELL_82 0x4232
#define POLL_7E7_CELL_83 0x4233
#define POLL_7E7_CELL_84 0x4234
#define POLL_7E7_CELL_85 0x4235
#define POLL_7E7_CELL_86 0x4236
#define POLL_7E7_CELL_87 0x4237
#define POLL_7E7_CELL_88 0x4238
#define POLL_7E7_CELL_89 0x4239
#define POLL_7E7_CELL_90 0x423A
#define POLL_7E7_CELL_91 0x423B
#define POLL_7E7_CELL_92 0x423C
#define POLL_7E7_CELL_93 0x423D
#define POLL_7E7_CELL_94 0x423E
#define POLL_7E7_CELL_95 0x423F
#define POLL_7E7_CELL_96 0x4240
void setup_battery(void);
void transmit_can(CAN_frame* tx_frame, int interface);
#endif

View file

@ -3,6 +3,42 @@
#include "../include.h"
typedef struct {
/** uint16_t */
/** PID polling parameters */
uint16_t battery_5V_ref = 0;
int16_t battery_module_temp_1 = 0;
int16_t battery_module_temp_2 = 0;
int16_t battery_module_temp_3 = 0;
int16_t battery_module_temp_4 = 0;
int16_t battery_module_temp_5 = 0;
int16_t battery_module_temp_6 = 0;
uint16_t battery_cell_average_voltage = 0;
uint16_t battery_cell_average_voltage_2 = 0;
uint16_t battery_terminal_voltage = 0;
uint16_t battery_ignition_power_mode = 0;
int16_t battery_current_7E7 = 0;
uint16_t battery_capacity_my17_18 = 0;
uint16_t battery_capacity_my19plus = 0;
uint16_t battery_SOC_display = 0;
uint16_t battery_SOC_raw_highprec = 0;
uint16_t battery_max_temperature = 0;
uint16_t battery_min_temperature = 0;
uint16_t battery_max_cell_voltage = 0;
uint16_t battery_min_cell_voltage = 0;
uint16_t battery_lowest_cell = 0;
uint16_t battery_highest_cell = 0;
uint16_t battery_internal_resistance = 0;
uint16_t battery_voltage_polled = 0;
uint16_t battery_vehicle_isolation = 0;
uint16_t battery_isolation_kohm = 0;
uint16_t battery_HV_locked = 0;
uint16_t battery_crash_event = 0;
uint16_t battery_HVIL = 0;
uint16_t battery_HVIL_status = 0;
int16_t battery_current_7E4 = 0;
} DATALAYER_INFO_BOLTAMPERA;
typedef struct {
/** uint16_t */
/** Terminal 30 - 12V SME Supply Voltage */
@ -403,6 +439,7 @@ typedef struct {
class DataLayerExtended {
public:
DATALAYER_INFO_BOLTAMPERA boltampera;
DATALAYER_INFO_BMWIX bmwix;
DATALAYER_INFO_BMWI3 bmwi3;
DATALAYER_INFO_BYDATTO3 bydAtto3;

View file

@ -20,6 +20,44 @@ String advanced_battery_processor(const String& var) {
// Start a new block with a specific background color
content += "<div style='background-color: #303E47; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
#ifdef BOLT_AMPERA_BATTERY
content += "<h4>5V Reference: " + String(datalayer_extended.boltampera.battery_5V_ref) + "</h4>";
content += "<h4>Module 1 temp: " + String(datalayer_extended.boltampera.battery_module_temp_1) + "</h4>";
content += "<h4>Module 2 temp: " + String(datalayer_extended.boltampera.battery_module_temp_2) + "</h4>";
content += "<h4>Module 3 temp: " + String(datalayer_extended.boltampera.battery_module_temp_3) + "</h4>";
content += "<h4>Module 4 temp: " + String(datalayer_extended.boltampera.battery_module_temp_4) + "</h4>";
content += "<h4>Module 5 temp: " + String(datalayer_extended.boltampera.battery_module_temp_5) + "</h4>";
content += "<h4>Module 6 temp: " + String(datalayer_extended.boltampera.battery_module_temp_6) + "</h4>";
content +=
"<h4>Cell average voltage: " + String(datalayer_extended.boltampera.battery_cell_average_voltage) + "</h4>";
content +=
"<h4>Cell average voltage 2: " + String(datalayer_extended.boltampera.battery_cell_average_voltage_2) + "</h4>";
content += "<h4>Terminal voltage: " + String(datalayer_extended.boltampera.battery_terminal_voltage) + "</h4>";
content +=
"<h4>Ignition power mode: " + String(datalayer_extended.boltampera.battery_ignition_power_mode) + "</h4>";
content += "<h4>Battery current (7E7): " + String(datalayer_extended.boltampera.battery_current_7E7) + "</h4>";
content += "<h4>Capacity MY17-18: " + String(datalayer_extended.boltampera.battery_capacity_my17_18) + "</h4>";
content += "<h4>Capacity MY19+: " + String(datalayer_extended.boltampera.battery_capacity_my19plus) + "</h4>";
content += "<h4>SOC Display: " + String(datalayer_extended.boltampera.battery_SOC_display) + "</h4>";
content += "<h4>SOC Raw highprec: " + String(datalayer_extended.boltampera.battery_SOC_raw_highprec) + "</h4>";
content += "<h4>Max temp: " + String(datalayer_extended.boltampera.battery_max_temperature) + "</h4>";
content += "<h4>Min temp: " + String(datalayer_extended.boltampera.battery_min_temperature) + "</h4>";
content += "<h4>Cell max mV: " + String(datalayer_extended.boltampera.battery_max_cell_voltage) + "</h4>";
content += "<h4>Cell min mV: " + String(datalayer_extended.boltampera.battery_min_cell_voltage) + "</h4>";
content += "<h4>Lowest cell: " + String(datalayer_extended.boltampera.battery_lowest_cell) + "</h4>";
content += "<h4>Highest cell: " + String(datalayer_extended.boltampera.battery_highest_cell) + "</h4>";
content +=
"<h4>Internal resistance: " + String(datalayer_extended.boltampera.battery_internal_resistance) + "</h4>";
content += "<h4>Voltage: " + String(datalayer_extended.boltampera.battery_voltage_polled) + "</h4>";
content += "<h4>Isolation Ohm: " + String(datalayer_extended.boltampera.battery_vehicle_isolation) + "</h4>";
content += "<h4>Isolation kOhm: " + String(datalayer_extended.boltampera.battery_isolation_kohm) + "</h4>";
content += "<h4>HV locked: " + String(datalayer_extended.boltampera.battery_HV_locked) + "</h4>";
content += "<h4>Crash event: " + String(datalayer_extended.boltampera.battery_crash_event) + "</h4>";
content += "<h4>HVIL: " + String(datalayer_extended.boltampera.battery_HVIL) + "</h4>";
content += "<h4>HVIL status: " + String(datalayer_extended.boltampera.battery_HVIL_status) + "</h4>";
content += "<h4>Current (7E4): " + String(datalayer_extended.boltampera.battery_current_7E4) + "</h4>";
#endif //BOLT_AMPERA_BATTERY
#ifdef BMW_IX_BATTERY
content +=
"<h4>Battery Voltage after Contactor: " + String(datalayer_extended.bmwix.battery_voltage_after_contactor) +
@ -680,9 +718,10 @@ String advanced_battery_processor(const String& var) {
content += "<h4>soc max: " + String(datalayer_extended.zoePH2.battery_soc_max) + "</h4>";
#endif //RENAULT_ZOE_GEN2_BATTERY
#if !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \
!defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \
!defined(MEB_BATTERY) //Only the listed types have extra info
#if !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_BATTERY) && !defined(TESLA_BATTERY) && \
!defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && !defined(BYD_ATTO_3_BATTERY) && \
!defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \
!defined(MEB_BATTERY) // Only the listed types have extra info
content += "No extra information available for this battery type";
#endif