mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-06 03:50:13 +02:00
BYD Atto 3 battery converted to use the base class
This commit is contained in:
parent
75427cdcd6
commit
09e719690f
2 changed files with 224 additions and 395 deletions
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef BYD_ATTO_3_BATTERY
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
|
@ -11,76 +12,6 @@ If you have a crash-locked pack, See the Wiki for more info on how to attempt an
|
|||
After battery has been unlocked, you can remove the "USE_ESTIMATED_SOC" from the BYD-ATTO-3-BATTERY.h file
|
||||
*/
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
#define NOT_DETERMINED_YET 0
|
||||
#define STANDARD_RANGE 1
|
||||
#define EXTENDED_RANGE 2
|
||||
#define NOT_RUNNING 0xFF
|
||||
#define STARTED 0
|
||||
#define RUNNING_STEP_1 1
|
||||
#define RUNNING_STEP_2 2
|
||||
static uint8_t battery_type = NOT_DETERMINED_YET;
|
||||
static uint8_t stateMachineClearCrash = NOT_RUNNING;
|
||||
static unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was send
|
||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||
static unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was send
|
||||
static bool SOC_method = false;
|
||||
static uint8_t counter_50ms = 0;
|
||||
static uint8_t counter_100ms = 0;
|
||||
static uint8_t frame6_counter = 0xB;
|
||||
static uint8_t frame7_counter = 0x5;
|
||||
static uint16_t battery_voltage = 0;
|
||||
static int16_t battery_temperature_ambient = 0;
|
||||
static int16_t battery_daughterboard_temperatures[10];
|
||||
static int16_t battery_lowest_temperature = 0;
|
||||
static int16_t battery_highest_temperature = 0;
|
||||
static int16_t battery_calc_min_temperature = 0;
|
||||
static int16_t battery_calc_max_temperature = 0;
|
||||
static uint16_t battery_highprecision_SOC = 0;
|
||||
static uint16_t BMS_SOC = 0;
|
||||
static uint16_t BMS_voltage = 0;
|
||||
static int16_t BMS_current = 0;
|
||||
static int16_t BMS_lowest_cell_temperature = 0;
|
||||
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 uint32_t BMS_unknown0 = 0;
|
||||
static uint32_t BMS_unknown1 = 0;
|
||||
static uint16_t BMS_allowed_charge_power = 0;
|
||||
static uint16_t BMS_unknown3 = 0;
|
||||
static uint16_t BMS_unknown4 = 0;
|
||||
static uint16_t BMS_unknown5 = 0;
|
||||
static uint16_t BMS_unknown6 = 0;
|
||||
static uint16_t BMS_unknown7 = 0;
|
||||
static uint16_t BMS_unknown8 = 0;
|
||||
static uint16_t BMS_unknown9 = 0;
|
||||
static uint8_t BMS_unknown10 = 0;
|
||||
static uint8_t BMS_unknown11 = 0;
|
||||
static uint8_t BMS_unknown12 = 0;
|
||||
static uint8_t BMS_unknown13 = 0;
|
||||
static uint8_t battery_frame_index = 0;
|
||||
static uint16_t battery_cellvoltages[CELLCOUNT_EXTENDED] = {0};
|
||||
#ifdef DOUBLE_BATTERY
|
||||
static int16_t battery2_temperature_ambient = 0;
|
||||
static int16_t battery2_daughterboard_temperatures[10];
|
||||
static int16_t battery2_lowest_temperature = 0;
|
||||
static int16_t battery2_highest_temperature = 0;
|
||||
static int16_t battery2_calc_min_temperature = 0;
|
||||
static int16_t battery2_calc_max_temperature = 0;
|
||||
static uint16_t battery2_highprecision_SOC = 0;
|
||||
static uint16_t BMS2_SOC = 0;
|
||||
static uint16_t BMS2_voltage = 0;
|
||||
static int16_t BMS2_current = 0;
|
||||
static int16_t BMS2_lowest_cell_temperature = 0;
|
||||
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[CELLCOUNT_EXTENDED] = {0};
|
||||
#endif //DOUBLE_BATTERY
|
||||
#define POLL_FOR_BATTERY_SOC 0x0005
|
||||
#define POLL_FOR_BATTERY_VOLTAGE 0x0008
|
||||
#define POLL_FOR_BATTERY_CURRENT 0x0009
|
||||
#define POLL_FOR_LOWEST_TEMP_CELL 0x002f
|
||||
|
@ -165,34 +96,6 @@ static uint16_t battery2_cellvoltages[CELLCOUNT_EXTENDED] = {0};
|
|||
|
||||
#define ESTIMATED 0
|
||||
#define MEASURED 1
|
||||
static uint16_t poll_state = POLL_FOR_BATTERY_SOC;
|
||||
static uint16_t pid_reply = 0;
|
||||
|
||||
CAN_frame ATTO_3_12D = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x12D,
|
||||
.data = {0xA0, 0x28, 0x02, 0xA0, 0x0C, 0x71, 0xCF, 0x49}};
|
||||
CAN_frame ATTO_3_441 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x441,
|
||||
.data = {0x98, 0x3A, 0x88, 0x13, 0x07, 0x00, 0xFF, 0x8C}};
|
||||
CAN_frame ATTO_3_7E7_POLL = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7E7, //Poll PID 03 22 00 05 (POLL_FOR_BATTERY_SOC)
|
||||
.data = {0x03, 0x22, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ATTO_3_7E7_ACK = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7E7, //ACK frame for long PIDs
|
||||
.data = {0x30, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ATTO_3_7E7_CLEAR_CRASH = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7E7,
|
||||
.data = {0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
// Define the data points for %SOC depending on pack voltage
|
||||
const uint8_t numPoints = 28;
|
||||
|
@ -241,10 +144,11 @@ uint16_t estimateSOCstandard(uint16_t packVoltage) { // Linear interpolation fu
|
|||
return 0; // Default return for safety, should never reach here
|
||||
}
|
||||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
void BydAttoBattery::
|
||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
||||
if (BMS_voltage > 0) {
|
||||
datalayer.battery.status.voltage_dV = BMS_voltage * 10;
|
||||
datalayer_battery->status.voltage_dV = BMS_voltage * 10;
|
||||
}
|
||||
|
||||
#ifdef USE_ESTIMATED_SOC
|
||||
|
@ -252,32 +156,32 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
// We instead estimate the SOC% based on the battery voltage.
|
||||
// This is a bad solution, you wont be able to use 100% of the battery
|
||||
if (battery_type == EXTENDED_RANGE) {
|
||||
datalayer.battery.status.real_soc = estimateSOCextended(datalayer.battery.status.voltage_dV);
|
||||
datalayer_battery->status.real_soc = estimateSOCextended(datalayer_battery->status.voltage_dV);
|
||||
}
|
||||
if (battery_type == STANDARD_RANGE) {
|
||||
datalayer.battery.status.real_soc = estimateSOCstandard(datalayer.battery.status.voltage_dV);
|
||||
datalayer_battery->status.real_soc = estimateSOCstandard(datalayer_battery->status.voltage_dV);
|
||||
}
|
||||
SOC_method = ESTIMATED;
|
||||
#else // Pack is not crashed, we can use periodically transmitted SOC
|
||||
datalayer.battery.status.real_soc = battery_highprecision_SOC * 10;
|
||||
datalayer_battery->status.real_soc = battery_highprecision_SOC * 10;
|
||||
SOC_method = MEASURED;
|
||||
#endif
|
||||
|
||||
datalayer.battery.status.current_dA = -BMS_current;
|
||||
datalayer_battery->status.current_dA = -BMS_current;
|
||||
|
||||
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.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.max_discharge_power_W = MAXPOWER_DISCHARGE_W; //TODO: Map from CAN later on
|
||||
datalayer_battery->status.max_discharge_power_W = MAXPOWER_DISCHARGE_W; //TODO: Map from CAN later on
|
||||
|
||||
datalayer.battery.status.max_charge_power_W = BMS_allowed_charge_power * 10; //TODO: Scaling unknown, *10 best guess
|
||||
datalayer_battery->status.max_charge_power_W = BMS_allowed_charge_power * 10; //TODO: Scaling unknown, *10 best guess
|
||||
|
||||
datalayer.battery.status.cell_max_voltage_mV = BMS_highest_cell_voltage_mV;
|
||||
datalayer_battery->status.cell_max_voltage_mV = BMS_highest_cell_voltage_mV;
|
||||
|
||||
datalayer.battery.status.cell_min_voltage_mV = BMS_lowest_cell_voltage_mV;
|
||||
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, CELLCOUNT_EXTENDED * sizeof(uint16_t));
|
||||
memcpy(datalayer_battery->status.cell_voltages_mV, battery_cellvoltages, CELLCOUNT_EXTENDED * sizeof(uint16_t));
|
||||
|
||||
// Check if we are on Standard range or Extended range battery.
|
||||
// We use a variety of checks to ensure we catch a potential Standard range battery
|
||||
|
@ -296,16 +200,16 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
|
||||
switch (battery_type) {
|
||||
case STANDARD_RANGE:
|
||||
datalayer.battery.info.total_capacity_Wh = 50000;
|
||||
datalayer.battery.info.number_of_cells = CELLCOUNT_STANDARD;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_STANDARD_DV;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_STANDARD_DV;
|
||||
datalayer_battery->info.total_capacity_Wh = 50000;
|
||||
datalayer_battery->info.number_of_cells = CELLCOUNT_STANDARD;
|
||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_STANDARD_DV;
|
||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_STANDARD_DV;
|
||||
break;
|
||||
case EXTENDED_RANGE:
|
||||
datalayer.battery.info.total_capacity_Wh = 60000;
|
||||
datalayer.battery.info.number_of_cells = CELLCOUNT_EXTENDED;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_EXTENDED_DV;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_EXTENDED_DV;
|
||||
datalayer_battery->info.total_capacity_Wh = 60000;
|
||||
datalayer_battery->info.number_of_cells = CELLCOUNT_EXTENDED;
|
||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_EXTENDED_DV;
|
||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_EXTENDED_DV;
|
||||
break;
|
||||
case NOT_DETERMINED_YET:
|
||||
default:
|
||||
|
@ -338,106 +242,108 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
//Write the result to datalayer
|
||||
if ((battery_calc_min_temperature != 0) && (battery_calc_max_temperature != 0)) {
|
||||
//Avoid triggering high delta if only one of the values is available
|
||||
datalayer.battery.status.temperature_min_dC = battery_calc_min_temperature * 10;
|
||||
datalayer.battery.status.temperature_max_dC = battery_calc_max_temperature * 10;
|
||||
datalayer_battery->status.temperature_min_dC = battery_calc_min_temperature * 10;
|
||||
datalayer_battery->status.temperature_max_dC = battery_calc_max_temperature * 10;
|
||||
}
|
||||
#else //User does not need filtering out a broken sensor, just use the min-max the BMS sends
|
||||
if ((BMS_lowest_cell_temperature != 0) && (BMS_highest_cell_temperature != 0)) {
|
||||
//Avoid triggering high delta if only one of the values is available
|
||||
datalayer.battery.status.temperature_min_dC = BMS_lowest_cell_temperature * 10;
|
||||
datalayer.battery.status.temperature_max_dC = BMS_highest_cell_temperature * 10;
|
||||
datalayer_battery->status.temperature_min_dC = BMS_lowest_cell_temperature * 10;
|
||||
datalayer_battery->status.temperature_max_dC = BMS_highest_cell_temperature * 10;
|
||||
}
|
||||
#endif //!SKIP_TEMPERATURE_SENSOR_NUMBER
|
||||
|
||||
// Update webserver datalayer
|
||||
datalayer_extended.bydAtto3.SOC_method = SOC_method;
|
||||
datalayer_extended.bydAtto3.SOC_estimated = datalayer.battery.status.real_soc;
|
||||
if (datalayer_bydatto) {
|
||||
datalayer_bydatto->SOC_method = SOC_method;
|
||||
datalayer_bydatto->SOC_estimated = datalayer_battery->status.real_soc;
|
||||
//Once we implement switching logic, remember to change from where the estimated is taken
|
||||
datalayer_extended.bydAtto3.SOC_highprec = battery_highprecision_SOC;
|
||||
datalayer_extended.bydAtto3.SOC_polled = BMS_SOC;
|
||||
datalayer_extended.bydAtto3.voltage_periodic = battery_voltage;
|
||||
datalayer_extended.bydAtto3.voltage_polled = BMS_voltage;
|
||||
datalayer_extended.bydAtto3.battery_temperatures[0] = battery_daughterboard_temperatures[0];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[1] = battery_daughterboard_temperatures[1];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[2] = battery_daughterboard_temperatures[2];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[3] = battery_daughterboard_temperatures[3];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[4] = battery_daughterboard_temperatures[4];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[5] = battery_daughterboard_temperatures[5];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[6] = battery_daughterboard_temperatures[6];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[7] = battery_daughterboard_temperatures[7];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[8] = battery_daughterboard_temperatures[8];
|
||||
datalayer_extended.bydAtto3.battery_temperatures[9] = battery_daughterboard_temperatures[9];
|
||||
datalayer_extended.bydAtto3.unknown0 = BMS_unknown0;
|
||||
datalayer_extended.bydAtto3.unknown1 = BMS_unknown1;
|
||||
datalayer_extended.bydAtto3.chargePower = BMS_allowed_charge_power;
|
||||
datalayer_extended.bydAtto3.unknown3 = BMS_unknown3;
|
||||
datalayer_extended.bydAtto3.unknown4 = BMS_unknown4;
|
||||
datalayer_extended.bydAtto3.unknown5 = BMS_unknown5;
|
||||
datalayer_extended.bydAtto3.unknown6 = BMS_unknown6;
|
||||
datalayer_extended.bydAtto3.unknown7 = BMS_unknown7;
|
||||
datalayer_extended.bydAtto3.unknown8 = BMS_unknown8;
|
||||
datalayer_extended.bydAtto3.unknown9 = BMS_unknown9;
|
||||
datalayer_extended.bydAtto3.unknown10 = BMS_unknown10;
|
||||
datalayer_extended.bydAtto3.unknown11 = BMS_unknown11;
|
||||
datalayer_extended.bydAtto3.unknown12 = BMS_unknown12;
|
||||
datalayer_extended.bydAtto3.unknown13 = BMS_unknown13;
|
||||
datalayer_bydatto->SOC_highprec = battery_highprecision_SOC;
|
||||
datalayer_bydatto->SOC_polled = BMS_SOC;
|
||||
datalayer_bydatto->voltage_periodic = battery_voltage;
|
||||
datalayer_bydatto->voltage_polled = BMS_voltage;
|
||||
datalayer_bydatto->battery_temperatures[0] = battery_daughterboard_temperatures[0];
|
||||
datalayer_bydatto->battery_temperatures[1] = battery_daughterboard_temperatures[1];
|
||||
datalayer_bydatto->battery_temperatures[2] = battery_daughterboard_temperatures[2];
|
||||
datalayer_bydatto->battery_temperatures[3] = battery_daughterboard_temperatures[3];
|
||||
datalayer_bydatto->battery_temperatures[4] = battery_daughterboard_temperatures[4];
|
||||
datalayer_bydatto->battery_temperatures[5] = battery_daughterboard_temperatures[5];
|
||||
datalayer_bydatto->battery_temperatures[6] = battery_daughterboard_temperatures[6];
|
||||
datalayer_bydatto->battery_temperatures[7] = battery_daughterboard_temperatures[7];
|
||||
datalayer_bydatto->battery_temperatures[8] = battery_daughterboard_temperatures[8];
|
||||
datalayer_bydatto->battery_temperatures[9] = battery_daughterboard_temperatures[9];
|
||||
datalayer_bydatto->unknown0 = BMS_unknown0;
|
||||
datalayer_bydatto->unknown1 = BMS_unknown1;
|
||||
datalayer_bydatto->chargePower = BMS_allowed_charge_power;
|
||||
datalayer_bydatto->unknown3 = BMS_unknown3;
|
||||
datalayer_bydatto->unknown4 = BMS_unknown4;
|
||||
datalayer_bydatto->unknown5 = BMS_unknown5;
|
||||
datalayer_bydatto->unknown6 = BMS_unknown6;
|
||||
datalayer_bydatto->unknown7 = BMS_unknown7;
|
||||
datalayer_bydatto->unknown8 = BMS_unknown8;
|
||||
datalayer_bydatto->unknown9 = BMS_unknown9;
|
||||
datalayer_bydatto->unknown10 = BMS_unknown10;
|
||||
datalayer_bydatto->unknown11 = BMS_unknown11;
|
||||
datalayer_bydatto->unknown12 = BMS_unknown12;
|
||||
datalayer_bydatto->unknown13 = BMS_unknown13;
|
||||
|
||||
// Update requests from webserver datalayer
|
||||
if (datalayer_extended.bydAtto3.UserRequestCrashReset && stateMachineClearCrash == NOT_RUNNING) {
|
||||
if (datalayer_bydatto->UserRequestCrashReset && stateMachineClearCrash == NOT_RUNNING) {
|
||||
stateMachineClearCrash = STARTED;
|
||||
datalayer_extended.bydAtto3.UserRequestCrashReset = false;
|
||||
datalayer_bydatto->UserRequestCrashReset = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||
void BydAttoBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||
switch (rx_frame.ID) {
|
||||
case 0x244:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x245:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
if (rx_frame.data.u8[0] == 0x01) {
|
||||
battery_temperature_ambient = (rx_frame.data.u8[4] - 40);
|
||||
}
|
||||
break;
|
||||
case 0x286:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x334:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x338:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x344:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x345:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x347:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x34A:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x35E:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x360:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x36C:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x438:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x43A:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x43B:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x43C:
|
||||
if (rx_frame.data.u8[0] == 0x00) {
|
||||
|
@ -456,7 +362,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
|||
}
|
||||
break;
|
||||
case 0x43D:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_frame_index = rx_frame.data.u8[0];
|
||||
|
||||
if (battery_frame_index < (CELLCOUNT_EXTENDED / 3)) {
|
||||
|
@ -468,31 +374,31 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
|||
}
|
||||
break;
|
||||
case 0x444:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_voltage = ((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[0];
|
||||
//battery_temperature_something = rx_frame.data.u8[7] - 40; resides in frame 7
|
||||
break;
|
||||
case 0x445:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x446:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x447:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_highprecision_SOC = ((rx_frame.data.u8[5] & 0x0F) << 8) | rx_frame.data.u8[4]; // 03 E0 = 992 = 99.2%
|
||||
battery_lowest_temperature = (rx_frame.data.u8[1] - 40); //Best guess for now
|
||||
battery_highest_temperature = (rx_frame.data.u8[3] - 40); //Best guess for now
|
||||
break;
|
||||
case 0x47B:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x524:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x7EF: //OBD2 PID reply from battery
|
||||
if (rx_frame.data.u8[0] == 0x10) {
|
||||
transmit_can_frame(&ATTO_3_7E7_ACK, can_config.battery); //Send next line request
|
||||
transmit_can_frame(&ATTO_3_7E7_ACK, can_interface); //Send next line request
|
||||
}
|
||||
pid_reply = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
|
||||
switch (pid_reply) {
|
||||
|
@ -572,13 +478,14 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
void transmit_can_battery(unsigned long currentMillis) {
|
||||
|
||||
void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
||||
//Send 50ms message
|
||||
if (currentMillis - previousMillis50 >= INTERVAL_50_MS) {
|
||||
previousMillis50 = currentMillis;
|
||||
|
||||
// Set close contactors to allowed (Useful for crashed packs, started via contactor control thru GPIO)
|
||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||
if (datalayer_battery->status.bms_status == ACTIVE) {
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
} else { // Fault state, open contactors!
|
||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
||||
|
@ -606,10 +513,7 @@ void transmit_can_battery(unsigned long currentMillis) {
|
|||
ATTO_3_12D.data.u8[6] = (0x0F | (frame6_counter << 4));
|
||||
ATTO_3_12D.data.u8[7] = (0x09 | (frame7_counter << 4));
|
||||
|
||||
transmit_can_frame(&ATTO_3_12D, can_config.battery);
|
||||
#ifdef DOUBLE_BATTERY
|
||||
transmit_can_frame(&ATTO_3_12D, can_config.battery_double);
|
||||
#endif //DOUBLE_BATTERY
|
||||
transmit_can_frame(&ATTO_3_12D, can_interface);
|
||||
}
|
||||
// Send 100ms CAN Message
|
||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
|
@ -626,24 +530,21 @@ void transmit_can_battery(unsigned long currentMillis) {
|
|||
ATTO_3_441.data.u8[7] = 0xF5;
|
||||
}
|
||||
|
||||
transmit_can_frame(&ATTO_3_441, can_config.battery);
|
||||
#ifdef DOUBLE_BATTERY
|
||||
transmit_can_frame(&ATTO_3_441, can_config.battery_double);
|
||||
#endif //DOUBLE_BATTERY
|
||||
transmit_can_frame(&ATTO_3_441, can_interface);
|
||||
switch (stateMachineClearCrash) {
|
||||
case STARTED:
|
||||
ATTO_3_7E7_CLEAR_CRASH.data = {0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_config.battery);
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_interface);
|
||||
stateMachineClearCrash = RUNNING_STEP_1;
|
||||
break;
|
||||
case RUNNING_STEP_1:
|
||||
ATTO_3_7E7_CLEAR_CRASH.data = {0x04, 0x14, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_config.battery);
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_interface);
|
||||
stateMachineClearCrash = RUNNING_STEP_2;
|
||||
break;
|
||||
case RUNNING_STEP_2:
|
||||
ATTO_3_7E7_CLEAR_CRASH.data = {0x03, 0x19, 0x02, 0x09, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_config.battery);
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_interface);
|
||||
stateMachineClearCrash = NOT_RUNNING;
|
||||
break;
|
||||
case NOT_RUNNING:
|
||||
|
@ -773,210 +674,21 @@ void transmit_can_battery(unsigned long currentMillis) {
|
|||
}
|
||||
|
||||
if (stateMachineClearCrash == NOT_RUNNING) { //Don't poll battery for data if clear crash running
|
||||
transmit_can_frame(&ATTO_3_7E7_POLL, can_config.battery);
|
||||
#ifdef DOUBLE_BATTERY
|
||||
transmit_can_frame(&ATTO_3_7E7_POLL, can_config.battery_double);
|
||||
#endif //DOUBLE_BATTERY
|
||||
transmit_can_frame(&ATTO_3_7E7_POLL, can_interface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup_battery(void) { // Performs one time setup at startup
|
||||
void BydAttoBattery::setup(void) { // Performs one time setup at startup
|
||||
strncpy(datalayer.system.info.battery_protocol, "BYD Atto 3", 63);
|
||||
datalayer.system.info.battery_protocol[63] = '\0';
|
||||
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_EXTENDED_DV; //Startup in extremes
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_STANDARD_DV; //We later determine range
|
||||
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;
|
||||
#ifdef DOUBLE_BATTERY
|
||||
datalayer.battery2.info.number_of_cells = CELLCOUNT_STANDARD;
|
||||
datalayer.battery2.info.chemistry = battery_chemistry_enum::LFP;
|
||||
datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV;
|
||||
datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV;
|
||||
datalayer.battery2.info.max_cell_voltage_mV = datalayer.battery.info.max_cell_voltage_mV;
|
||||
datalayer.battery2.info.min_cell_voltage_mV = datalayer.battery.info.min_cell_voltage_mV;
|
||||
datalayer.battery2.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||
#endif //DOUBLE_BATTERY
|
||||
datalayer_battery->info.number_of_cells = CELLCOUNT_STANDARD;
|
||||
datalayer_battery->info.chemistry = battery_chemistry_enum::LFP;
|
||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_EXTENDED_DV; //Startup in extremes
|
||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_STANDARD_DV; //We later determine range
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef DOUBLE_BATTERY
|
||||
|
||||
void update_values_battery2() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
||||
if (BMS2_voltage > 0) {
|
||||
datalayer.battery2.status.voltage_dV = BMS2_voltage * 10;
|
||||
}
|
||||
|
||||
// We instead estimate the SOC% based on the battery2 voltage
|
||||
// This is a very bad solution, and as soon as an usable SOC% value has been found on CAN, we should switch to that!
|
||||
if (battery_type == EXTENDED_RANGE) {
|
||||
datalayer.battery2.status.real_soc = estimateSOCextended(datalayer.battery2.status.voltage_dV);
|
||||
}
|
||||
if (battery_type == STANDARD_RANGE) {
|
||||
datalayer.battery2.status.real_soc = estimateSOCstandard(datalayer.battery2.status.voltage_dV);
|
||||
}
|
||||
|
||||
datalayer.battery2.status.current_dA = -BMS2_current;
|
||||
|
||||
datalayer.battery2.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
||||
(static_cast<double>(datalayer.battery2.status.real_soc) / 10000) * datalayer.battery2.info.total_capacity_Wh);
|
||||
|
||||
datalayer.battery2.status.max_discharge_power_W = 10000; //TODO: Map from CAN later on
|
||||
|
||||
datalayer.battery2.status.max_charge_power_W = 10000; //TODO: Map from CAN later on
|
||||
|
||||
datalayer.battery2.status.cell_max_voltage_mV = BMS2_highest_cell_voltage_mV;
|
||||
|
||||
datalayer.battery2.status.cell_min_voltage_mV = BMS2_lowest_cell_voltage_mV;
|
||||
|
||||
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, CELLCOUNT_EXTENDED * sizeof(uint16_t));
|
||||
|
||||
datalayer.battery2.info.total_capacity_Wh = datalayer.battery.info.total_capacity_Wh;
|
||||
datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells;
|
||||
datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV;
|
||||
datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV;
|
||||
}
|
||||
|
||||
void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
||||
switch (rx_frame.ID) {
|
||||
case 0x244:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x245:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
if (rx_frame.data.u8[0] == 0x01) {
|
||||
battery2_temperature_ambient = (rx_frame.data.u8[4] - 40);
|
||||
}
|
||||
break;
|
||||
case 0x286:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x334:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x338:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x344:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x345:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x347:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x34A:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x35E:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x360:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x36C:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x438:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x43A:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x43B:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x43C: // Daughterboard temperatures reside in this CAN message
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
if (rx_frame.data.u8[0] == 0x00) {
|
||||
battery2_daughterboard_temperatures[0] = (rx_frame.data.u8[1] - 40);
|
||||
battery2_daughterboard_temperatures[1] = (rx_frame.data.u8[2] - 40);
|
||||
battery2_daughterboard_temperatures[2] = (rx_frame.data.u8[3] - 40);
|
||||
battery2_daughterboard_temperatures[3] = (rx_frame.data.u8[4] - 40);
|
||||
battery2_daughterboard_temperatures[4] = (rx_frame.data.u8[5] - 40);
|
||||
battery2_daughterboard_temperatures[5] = (rx_frame.data.u8[6] - 40);
|
||||
}
|
||||
if (rx_frame.data.u8[0] == 0x01) {
|
||||
battery2_daughterboard_temperatures[6] = (rx_frame.data.u8[1] - 40);
|
||||
battery2_daughterboard_temperatures[7] = (rx_frame.data.u8[2] - 40);
|
||||
battery2_daughterboard_temperatures[8] = (rx_frame.data.u8[3] - 40);
|
||||
battery2_daughterboard_temperatures[9] = (rx_frame.data.u8[4] - 40);
|
||||
}
|
||||
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 < (CELLCOUNT_EXTENDED / 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;
|
||||
break;
|
||||
case 0x445:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x446:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x447:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery2_highprecision_SOC = ((rx_frame.data.u8[5] & 0x0F) << 8) | rx_frame.data.u8[4];
|
||||
battery2_lowest_temperature = (rx_frame.data.u8[1] - 40);
|
||||
battery2_highest_temperature = (rx_frame.data.u8[3] - 40);
|
||||
break;
|
||||
case 0x47B:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x524:
|
||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x7EF: //OBD2 PID reply from battery2
|
||||
switch (rx_frame.data.u8[3]) {
|
||||
case POLL_FOR_BATTERY_SOC:
|
||||
BMS2_SOC = rx_frame.data.u8[4];
|
||||
break;
|
||||
case POLL_FOR_BATTERY_VOLTAGE:
|
||||
BMS2_voltage = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case POLL_FOR_BATTERY_CURRENT:
|
||||
BMS2_current = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) - 5000;
|
||||
break;
|
||||
case POLL_FOR_LOWEST_TEMP_CELL:
|
||||
BMS2_lowest_cell_temperature = (rx_frame.data.u8[4] - 40);
|
||||
break;
|
||||
case POLL_FOR_HIGHEST_TEMP_CELL:
|
||||
BMS2_highest_cell_temperature = (rx_frame.data.u8[4] - 40);
|
||||
break;
|
||||
case POLL_FOR_BATTERY_PACK_AVG_TEMP:
|
||||
BMS2_average_cell_temperature = (rx_frame.data.u8[4] - 40);
|
||||
break;
|
||||
case POLL_FOR_BATTERY_CELL_MV_MAX:
|
||||
BMS2_highest_cell_voltage_mV = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case POLL_FOR_BATTERY_CELL_MV_MIN:
|
||||
BMS2_lowest_cell_voltage_mV = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
default: //Unrecognized reply
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif //DOUBLE_BATTERY
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
#ifndef ATTO_3_BATTERY_H
|
||||
#define ATTO_3_BATTERY_H
|
||||
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
#define USE_ESTIMATED_SOC // If enabled, SOC is estimated from pack voltage. Useful for locked packs. \
|
||||
// Comment out this only if you know your BMS is unlocked and able to send SOC%
|
||||
#define MAXPOWER_CHARGE_W 10000
|
||||
|
@ -14,6 +18,8 @@
|
|||
|
||||
/* Do not modify the rows below */
|
||||
#define BATTERY_SELECTED
|
||||
#define SELECTED_BATTERY_CLASS BydAttoBattery
|
||||
|
||||
#define CELLCOUNT_EXTENDED 126
|
||||
#define CELLCOUNT_STANDARD 104
|
||||
#define MAX_PACK_VOLTAGE_EXTENDED_DV 4410 //Extended range
|
||||
|
@ -24,7 +30,118 @@
|
|||
#define MAX_CELL_VOLTAGE_MV 3650 //Charging stops if one cell exceeds this value
|
||||
#define MIN_CELL_VOLTAGE_MV 2800 //Discharging stops if one cell goes below this value
|
||||
|
||||
void setup_battery(void);
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
class BydAttoBattery : public CanBattery {
|
||||
public:
|
||||
// Use this constructor for the second battery.
|
||||
BydAttoBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* allows_contactor_closing_ptr,
|
||||
DATALAYER_INFO_BYDATTO3* extended, int targetCan) {
|
||||
datalayer_battery = datalayer_ptr;
|
||||
datalayer_bydatto = extended;
|
||||
allows_contactor_closing = allows_contactor_closing_ptr;
|
||||
can_interface = targetCan;
|
||||
}
|
||||
|
||||
// Use the default constructor to create the first or single battery.
|
||||
BydAttoBattery() {
|
||||
datalayer_battery = &datalayer.battery;
|
||||
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||
can_interface = can_config.battery;
|
||||
datalayer_bydatto = &datalayer_extended.bydAtto3;
|
||||
}
|
||||
|
||||
virtual void setup(void);
|
||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||
virtual void update_values();
|
||||
virtual void transmit_can(unsigned long currentMillis);
|
||||
|
||||
private:
|
||||
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||
DATALAYER_INFO_BYDATTO3* datalayer_bydatto;
|
||||
bool* allows_contactor_closing;
|
||||
|
||||
int can_interface;
|
||||
|
||||
static const int POLL_FOR_BATTERY_SOC = 0x0005;
|
||||
static const uint8_t NOT_DETERMINED_YET = 0;
|
||||
static const uint8_t STANDARD_RANGE = 1;
|
||||
static const uint8_t EXTENDED_RANGE = 2;
|
||||
|
||||
static const uint8_t NOT_RUNNING = 0xFF;
|
||||
static const uint8_t STARTED = 0;
|
||||
static const uint8_t RUNNING_STEP_1 = 1;
|
||||
static const uint8_t RUNNING_STEP_2 = 2;
|
||||
|
||||
uint8_t battery_type = NOT_DETERMINED_YET;
|
||||
uint8_t stateMachineClearCrash = NOT_RUNNING;
|
||||
unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was send
|
||||
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||
unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was send
|
||||
bool SOC_method = false;
|
||||
uint8_t counter_50ms = 0;
|
||||
uint8_t counter_100ms = 0;
|
||||
uint8_t frame6_counter = 0xB;
|
||||
uint8_t frame7_counter = 0x5;
|
||||
uint16_t battery_voltage = 0;
|
||||
int16_t battery_temperature_ambient = 0;
|
||||
int16_t battery_daughterboard_temperatures[10];
|
||||
int16_t battery_lowest_temperature = 0;
|
||||
int16_t battery_highest_temperature = 0;
|
||||
int16_t battery_calc_min_temperature = 0;
|
||||
int16_t battery_calc_max_temperature = 0;
|
||||
uint16_t battery_highprecision_SOC = 0;
|
||||
uint16_t BMS_SOC = 0;
|
||||
uint16_t BMS_voltage = 0;
|
||||
int16_t BMS_current = 0;
|
||||
int16_t BMS_lowest_cell_temperature = 0;
|
||||
int16_t BMS_highest_cell_temperature = 0;
|
||||
int16_t BMS_average_cell_temperature = 0;
|
||||
uint16_t BMS_lowest_cell_voltage_mV = 3300;
|
||||
uint16_t BMS_highest_cell_voltage_mV = 3300;
|
||||
uint32_t BMS_unknown0 = 0;
|
||||
uint32_t BMS_unknown1 = 0;
|
||||
uint16_t BMS_allowed_charge_power = 0;
|
||||
uint16_t BMS_unknown3 = 0;
|
||||
uint16_t BMS_unknown4 = 0;
|
||||
uint16_t BMS_unknown5 = 0;
|
||||
uint16_t BMS_unknown6 = 0;
|
||||
uint16_t BMS_unknown7 = 0;
|
||||
uint16_t BMS_unknown8 = 0;
|
||||
uint16_t BMS_unknown9 = 0;
|
||||
uint8_t BMS_unknown10 = 0;
|
||||
uint8_t BMS_unknown11 = 0;
|
||||
uint8_t BMS_unknown12 = 0;
|
||||
uint8_t BMS_unknown13 = 0;
|
||||
uint8_t battery_frame_index = 0;
|
||||
uint16_t battery_cellvoltages[CELLCOUNT_EXTENDED] = {0};
|
||||
|
||||
uint16_t poll_state = POLL_FOR_BATTERY_SOC;
|
||||
uint16_t pid_reply = 0;
|
||||
|
||||
CAN_frame ATTO_3_12D = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x12D,
|
||||
.data = {0xA0, 0x28, 0x02, 0xA0, 0x0C, 0x71, 0xCF, 0x49}};
|
||||
CAN_frame ATTO_3_441 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x441,
|
||||
.data = {0x98, 0x3A, 0x88, 0x13, 0x07, 0x00, 0xFF, 0x8C}};
|
||||
CAN_frame ATTO_3_7E7_POLL = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7E7, //Poll PID 03 22 00 05 (POLL_FOR_BATTERY_SOC)
|
||||
.data = {0x03, 0x22, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ATTO_3_7E7_ACK = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7E7, //ACK frame for long PIDs
|
||||
.data = {0x30, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ATTO_3_7E7_CLEAR_CRASH = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7E7,
|
||||
.data = {0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue