mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 18:29:48 +02:00
Merge branch 'main' into bugfix/pylon-battery-soh
This commit is contained in:
commit
c81c176c60
31 changed files with 2187 additions and 2016 deletions
|
@ -273,7 +273,7 @@ void core_loop(void*) {
|
||||||
transmit_can(currentMillis); // Send CAN messages to all components
|
transmit_can(currentMillis); // Send CAN messages to all components
|
||||||
|
|
||||||
#ifdef RS485_BATTERY_SELECTED
|
#ifdef RS485_BATTERY_SELECTED
|
||||||
transmit_rs485();
|
transmit_rs485(currentMillis);
|
||||||
#endif // RS485_BATTERY_SELECTED
|
#endif // RS485_BATTERY_SELECTED
|
||||||
#ifdef FUNCTION_TIME_MEASUREMENT
|
#ifdef FUNCTION_TIME_MEASUREMENT
|
||||||
END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us);
|
END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us);
|
||||||
|
@ -331,9 +331,9 @@ void check_interconnect_available() {
|
||||||
clear_event(EVENT_VOLTAGE_DIFFERENCE);
|
clear_event(EVENT_VOLTAGE_DIFFERENCE);
|
||||||
if (datalayer.battery.status.bms_status == FAULT) {
|
if (datalayer.battery.status.bms_status == FAULT) {
|
||||||
// If main battery is in fault state, disengage the second battery
|
// If main battery is in fault state, disengage the second battery
|
||||||
datalayer.system.status.battery2_allows_contactor_closing = false;
|
datalayer.system.status.battery2_allowed_contactor_closing = false;
|
||||||
} else { // If main battery is OK, allow second battery to join
|
} else { // If main battery is OK, allow second battery to join
|
||||||
datalayer.system.status.battery2_allows_contactor_closing = true;
|
datalayer.system.status.battery2_allowed_contactor_closing = true;
|
||||||
}
|
}
|
||||||
} else { //Voltage between the two packs is too large
|
} else { //Voltage between the two packs is too large
|
||||||
set_event(EVENT_VOLTAGE_DIFFERENCE, (uint8_t)(voltage_diff / 10));
|
set_event(EVENT_VOLTAGE_DIFFERENCE, (uint8_t)(voltage_diff / 10));
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
//#define FOXESS_BATTERY
|
//#define FOXESS_BATTERY
|
||||||
//#define CELLPOWER_BMS
|
//#define CELLPOWER_BMS
|
||||||
//#define CHADEMO_BATTERY //NOTE: inherently enables CONTACTOR_CONTROL below
|
//#define CHADEMO_BATTERY //NOTE: inherently enables CONTACTOR_CONTROL below
|
||||||
|
//#define GEELY_GEOMETRY_C_BATTERY
|
||||||
//#define CMFA_EV_BATTERY
|
//#define CMFA_EV_BATTERY
|
||||||
//#define IMIEV_CZERO_ION_BATTERY
|
//#define IMIEV_CZERO_ION_BATTERY
|
||||||
//#define JAGUAR_IPACE_BATTERY
|
//#define JAGUAR_IPACE_BATTERY
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "RS485Battery.h"
|
#include "RS485Battery.h"
|
||||||
|
|
||||||
|
@ -25,14 +26,18 @@ void setup_battery() {
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
if (battery2 == nullptr) {
|
if (battery2 == nullptr) {
|
||||||
#ifdef BMW_I3_BATTERY
|
#if defined(BMW_I3_BATTERY)
|
||||||
battery2 =
|
battery2 =
|
||||||
new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer.system.status.battery2_allows_contactor_closing,
|
new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer.system.status.battery2_allowed_contactor_closing,
|
||||||
can_config.battery_double, WUP_PIN2);
|
can_config.battery_double, WUP_PIN2);
|
||||||
|
#elif defined(KIA_HYUNDAI_64_BATTERY)
|
||||||
|
battery2 = new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer_extended.KiaHyundai64_2,
|
||||||
|
&datalayer.system.status.battery2_allowed_contactor_closing,
|
||||||
|
can_config.battery_double);
|
||||||
|
#elif defined(SANTA_FE_PHEV_BATTERY) || defined(TEST_FAKE_BATTERY)
|
||||||
|
battery2 = new SELECTED_BATTERY_CLASS(&datalayer.battery2, can_config.battery_double);
|
||||||
#else
|
#else
|
||||||
battery2 =
|
battery2 = new SELECTED_BATTERY_CLASS(&datalayer.battery2, nullptr, can_config.battery_double);
|
||||||
new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer.system.status.battery2_allows_contactor_closing,
|
|
||||||
nullptr, can_config.battery_double);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
battery2->setup();
|
battery2->setup();
|
||||||
|
|
|
@ -46,6 +46,10 @@ void setup_can_shunt();
|
||||||
#include "FOXESS-BATTERY.h"
|
#include "FOXESS-BATTERY.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef GEELY_GEOMETRY_C_BATTERY
|
||||||
|
#include "GEELY-GEOMETRY-C-BATTERY.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ORION_BMS
|
#ifdef ORION_BMS
|
||||||
#include "ORION-BMS.h"
|
#include "ORION-BMS.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -151,7 +155,7 @@ void setup_battery(void);
|
||||||
void update_values_battery();
|
void update_values_battery();
|
||||||
|
|
||||||
#ifdef RS485_BATTERY_SELECTED
|
#ifdef RS485_BATTERY_SELECTED
|
||||||
void transmit_rs485();
|
void transmit_rs485(unsigned long currentMillis);
|
||||||
void receive_RS485();
|
void receive_RS485();
|
||||||
#else
|
#else
|
||||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame);
|
void handle_incoming_can_frame_battery(CAN_frame rx_frame);
|
||||||
|
|
|
@ -329,11 +329,15 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
||||||
BMW_13E.data.u8[4] = BMW_13E_counter;
|
BMW_13E.data.u8[4] = BMW_13E_counter;
|
||||||
|
|
||||||
if (datalayer_battery->status.bms_status == FAULT) {
|
if (datalayer_battery->status.bms_status == FAULT) {
|
||||||
} //If battery is not in Fault mode, allow contactor to close by sending 10B
|
} else if (allows_contactor_closing) {
|
||||||
else if (*allows_contactor_closing == true) {
|
//If battery is not in Fault mode, and we are allowed to control contactors, we allow contactor to close by sending 10B
|
||||||
|
*allows_contactor_closing = true;
|
||||||
|
transmit_can_frame(&BMW_10B, can_interface);
|
||||||
|
} else if (contactor_closing_allowed && *contactor_closing_allowed) {
|
||||||
transmit_can_frame(&BMW_10B, can_interface);
|
transmit_can_frame(&BMW_10B, can_interface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send 100ms CAN Message
|
// Send 100ms CAN Message
|
||||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||||
previousMillis100 = currentMillis;
|
previousMillis100 = currentMillis;
|
||||||
|
@ -512,7 +516,10 @@ void BmwI3Battery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH;
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH;
|
||||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH;
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH;
|
||||||
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
|
||||||
|
if (allows_contactor_closing) {
|
||||||
|
*allows_contactor_closing = true;
|
||||||
|
}
|
||||||
datalayer_battery->info.number_of_cells = NUMBER_OF_CELLS;
|
datalayer_battery->info.number_of_cells = NUMBER_OF_CELLS;
|
||||||
|
|
||||||
pinMode(wakeup_pin, OUTPUT);
|
pinMode(wakeup_pin, OUTPUT);
|
||||||
|
|
|
@ -12,9 +12,10 @@
|
||||||
class BmwI3Battery : public CanBattery {
|
class BmwI3Battery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
// Use this constructor for the second battery.
|
// Use this constructor for the second battery.
|
||||||
BmwI3Battery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* allows_contactor_closing_ptr, int targetCan, int wakeup) {
|
BmwI3Battery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* contactor_closing_allowed_ptr, int targetCan, int wakeup) {
|
||||||
datalayer_battery = datalayer_ptr;
|
datalayer_battery = datalayer_ptr;
|
||||||
allows_contactor_closing = allows_contactor_closing_ptr;
|
contactor_closing_allowed = contactor_closing_allowed_ptr;
|
||||||
|
allows_contactor_closing = nullptr;
|
||||||
can_interface = targetCan;
|
can_interface = targetCan;
|
||||||
wakeup_pin = wakeup;
|
wakeup_pin = wakeup;
|
||||||
*allows_contactor_closing = true;
|
*allows_contactor_closing = true;
|
||||||
|
@ -27,6 +28,7 @@ class BmwI3Battery : public CanBattery {
|
||||||
BmwI3Battery() {
|
BmwI3Battery() {
|
||||||
datalayer_battery = &datalayer.battery;
|
datalayer_battery = &datalayer.battery;
|
||||||
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||||
|
contactor_closing_allowed = nullptr;
|
||||||
can_interface = can_config.battery;
|
can_interface = can_config.battery;
|
||||||
wakeup_pin = WUP_PIN1;
|
wakeup_pin = WUP_PIN1;
|
||||||
}
|
}
|
||||||
|
@ -53,9 +55,14 @@ class BmwI3Battery : public CanBattery {
|
||||||
const int NUMBER_OF_CELLS = 96;
|
const int NUMBER_OF_CELLS = 96;
|
||||||
|
|
||||||
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||||
bool* allows_contactor_closing;
|
|
||||||
int wakeup_pin;
|
|
||||||
|
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
|
// If not null, this battery listens to this boolean to determine whether contactor closing is allowed
|
||||||
|
bool* contactor_closing_allowed;
|
||||||
|
|
||||||
|
int wakeup_pin;
|
||||||
int can_interface;
|
int can_interface;
|
||||||
|
|
||||||
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send
|
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send
|
||||||
|
|
|
@ -485,10 +485,12 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
||||||
previousMillis50 = currentMillis;
|
previousMillis50 = currentMillis;
|
||||||
|
|
||||||
// Set close contactors to allowed (Useful for crashed packs, started via contactor control thru GPIO)
|
// Set close contactors to allowed (Useful for crashed packs, started via contactor control thru GPIO)
|
||||||
if (datalayer_battery->status.bms_status == ACTIVE) {
|
if (allows_contactor_closing) {
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
if (datalayer_battery->status.bms_status == ACTIVE) {
|
||||||
} else { // Fault state, open contactors!
|
*allows_contactor_closing = true;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
} else { // Fault state, open contactors!
|
||||||
|
*allows_contactor_closing = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
counter_50ms++;
|
counter_50ms++;
|
||||||
|
|
|
@ -33,11 +33,10 @@
|
||||||
class BydAttoBattery : public CanBattery {
|
class BydAttoBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
// Use this constructor for the second battery.
|
// Use this constructor for the second battery.
|
||||||
BydAttoBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* allows_contactor_closing_ptr,
|
BydAttoBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, DATALAYER_INFO_BYDATTO3* extended, int targetCan) {
|
||||||
DATALAYER_INFO_BYDATTO3* extended, int targetCan) {
|
|
||||||
datalayer_battery = datalayer_ptr;
|
datalayer_battery = datalayer_ptr;
|
||||||
datalayer_bydatto = extended;
|
datalayer_bydatto = extended;
|
||||||
allows_contactor_closing = allows_contactor_closing_ptr;
|
allows_contactor_closing = nullptr;
|
||||||
can_interface = targetCan;
|
can_interface = targetCan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,24 +156,22 @@ void decode_packet(uint8_t command, uint8_t data[8]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DalyBms::transmit_rs485() {
|
void DalyBms::transmit_rs485(unsigned long currentMillis) {
|
||||||
|
|
||||||
static uint8_t nextCommand = 0x90;
|
static uint8_t nextCommand = 0x90;
|
||||||
|
|
||||||
if (millis() - lastPacket > 60) {
|
if (currentMillis - lastPacket > 60) {
|
||||||
|
lastPacket = currentMillis;
|
||||||
uint8_t tx_buff[13] = {0};
|
uint8_t tx_buff[13] = {0};
|
||||||
tx_buff[0] = 0xA5;
|
tx_buff[0] = 0xA5;
|
||||||
tx_buff[1] = 0x40;
|
tx_buff[1] = 0x40;
|
||||||
tx_buff[2] = nextCommand;
|
tx_buff[2] = nextCommand;
|
||||||
tx_buff[3] = 8;
|
tx_buff[3] = 8;
|
||||||
tx_buff[12] = calculate_checksum(tx_buff);
|
tx_buff[12] = calculate_checksum(tx_buff);
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
dump_buff("transmitting: ", tx_buff, 13);
|
dump_buff("transmitting: ", tx_buff, 13);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Serial2.write(tx_buff, 13);
|
Serial2.write(tx_buff, 13);
|
||||||
lastPacket = millis();
|
|
||||||
|
|
||||||
nextCommand++;
|
nextCommand++;
|
||||||
if (nextCommand > 0x98)
|
if (nextCommand > 0x98)
|
||||||
nextCommand = 0x90;
|
nextCommand = 0x90;
|
||||||
|
|
|
@ -22,7 +22,7 @@ class DalyBms : public RS485Battery {
|
||||||
public:
|
public:
|
||||||
void setup();
|
void setup();
|
||||||
void update_values();
|
void update_values();
|
||||||
void transmit_rs485();
|
void transmit_rs485(unsigned long currentMillis);
|
||||||
void receive_RS485();
|
void receive_RS485();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
675
Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp
Normal file
675
Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp
Normal file
|
@ -0,0 +1,675 @@
|
||||||
|
#include "../include.h"
|
||||||
|
#ifdef GEELY_GEOMETRY_C_BATTERY
|
||||||
|
#include "../communication/can/comm_can.h"
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
|
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||||
|
#include "../devboard/utils/events.h"
|
||||||
|
#include "GEELY-GEOMETRY-C-BATTERY.h"
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
- Contactor closing: CAN log needed from complete H-CAN of Geely Geometry C vehicle. We are not sure what needs to be sent towards the battery yet to get contactor closing working. DTC readout complains that a "Power CAN BUS Data Missing" message is still missing
|
||||||
|
- Unsure if the current CAN sending routine is enough to keep BMS alive 24/7. Testing needed
|
||||||
|
- There are a few UNKNOWN PID polls, these need to be decoded
|
||||||
|
- Some critical values are still missing:
|
||||||
|
- Current sensor (Mandatory!)
|
||||||
|
- Max charge power (can be estimated)
|
||||||
|
- Max discharge power (can be estimated)
|
||||||
|
- Cell voltage min/max (not mandatory, but very nice to have)
|
||||||
|
- All cell voltages (not mandatory, but very nice to have)
|
||||||
|
|
||||||
|
Node descriptions, these can send CAN messages in the Geely Geometry C
|
||||||
|
DSCU (Drivers Seat Control Unit)
|
||||||
|
OBC (On Board Charger)
|
||||||
|
FRS (Front Radar System)
|
||||||
|
IPU (Integrated Power Unit Control)
|
||||||
|
EGSM (Electronic Gear Shifter)
|
||||||
|
MMI
|
||||||
|
T-BOX (Electrocar Communication Control Module)
|
||||||
|
IPK
|
||||||
|
FCS
|
||||||
|
FRS
|
||||||
|
TCM(SAS)
|
||||||
|
RPS
|
||||||
|
ESC
|
||||||
|
ACU(YRS)
|
||||||
|
DSCU
|
||||||
|
PEPS
|
||||||
|
ESCL
|
||||||
|
BCM (Body Control Module)
|
||||||
|
AC
|
||||||
|
BMSH (Battery Management System)
|
||||||
|
VCU (Vehicle Control Unit)
|
||||||
|
AVAS
|
||||||
|
IB
|
||||||
|
RSRS
|
||||||
|
RML
|
||||||
|
|
||||||
|
There are 4 CAN buses in the Geometry C, we are interested in the Hybrid CAN (HB-CAN)
|
||||||
|
- Hybrid, HB CAN: gateway, electronic shifter, VCU, T-BOX, BMS, high and low voltage charging system, integrated power controller
|
||||||
|
- Infotainent, IF CAN: gateway, diagnostic interface, combined instrument, controller, head-up display, audio host, T-BOX
|
||||||
|
- Comfort, CF CAN: gateway, diagnostic interface, low-speed alarm controller, thermal management control module, electronic
|
||||||
|
steering column lock, BCM, seat module
|
||||||
|
- Chassis, CS CAN: gateway, steering wheel angle sensor, front monocular camera, VCU, millimeter wave radar probe, EPS,
|
||||||
|
smart booster, ESC, airbag control module, automatic parking module
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
|
|
||||||
|
void GeelyGeometryCBattery::update_values() {
|
||||||
|
datalayer_battery->status.soh_pptt;
|
||||||
|
|
||||||
|
datalayer_battery->status.real_soc = poll_soc * 10;
|
||||||
|
|
||||||
|
datalayer_battery->status.voltage_dV = battery_voltage;
|
||||||
|
|
||||||
|
datalayer_battery->status.current_dA;
|
||||||
|
|
||||||
|
if (poll_amount_cells == 102) { // We have determined that we are on 70kWh pack
|
||||||
|
datalayer_battery->info.total_capacity_Wh = 70000;
|
||||||
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_70_DV;
|
||||||
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_70_DV;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
||||||
|
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 = discharge_power_allowed * 100;
|
||||||
|
|
||||||
|
datalayer_battery->status.max_charge_power_W;
|
||||||
|
|
||||||
|
datalayer_battery->status.cell_min_voltage_mV = maximum_cell_voltage - 10; //TODO: Fix once we have min value
|
||||||
|
|
||||||
|
datalayer_battery->status.cell_max_voltage_mV = maximum_cell_voltage;
|
||||||
|
|
||||||
|
// Initialize highest and lowest to the first element
|
||||||
|
maximum_temperature = poll_temperature[0];
|
||||||
|
minimum_temperature = poll_temperature[0];
|
||||||
|
|
||||||
|
// Iterate through the array to find the highest and lowest values
|
||||||
|
for (uint8_t i = 1; i < 6; ++i) {
|
||||||
|
if (poll_temperature[i] > maximum_temperature) {
|
||||||
|
maximum_temperature = poll_temperature[i];
|
||||||
|
}
|
||||||
|
if (poll_temperature[i] < minimum_temperature) {
|
||||||
|
minimum_temperature = poll_temperature[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
datalayer_battery->status.temperature_min_dC = minimum_temperature * 10;
|
||||||
|
|
||||||
|
datalayer_battery->status.temperature_max_dC = maximum_temperature * 10;
|
||||||
|
|
||||||
|
if (HVIL_signal > 0) {
|
||||||
|
set_event(EVENT_HVIL_FAILURE, HVIL_signal);
|
||||||
|
} else {
|
||||||
|
clear_event(EVENT_HVIL_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update webserver more battery info page
|
||||||
|
memcpy(datalayer_geometryc->BatterySerialNumber, serialnumbers, sizeof(serialnumbers));
|
||||||
|
memcpy(datalayer_geometryc->ModuleTemperatures, poll_temperature, sizeof(poll_temperature));
|
||||||
|
memcpy(datalayer_geometryc->BatterySoftwareVersion, poll_software_version, sizeof(poll_software_version));
|
||||||
|
memcpy(datalayer_geometryc->BatteryHardwareVersion, poll_hardware_version, sizeof(poll_hardware_version));
|
||||||
|
datalayer_geometryc->soc = poll_soc;
|
||||||
|
datalayer_geometryc->CC2voltage = poll_cc2_voltage;
|
||||||
|
datalayer_geometryc->cellMaxVoltageNumber = poll_cell_max_voltage_number;
|
||||||
|
datalayer_geometryc->cellMinVoltageNumber = poll_cell_min_voltage_number;
|
||||||
|
datalayer_geometryc->cellTotalAmount = poll_amount_cells;
|
||||||
|
datalayer_geometryc->specificialVoltage = poll_specificial_voltage;
|
||||||
|
datalayer_geometryc->unknown1 = poll_unknown1;
|
||||||
|
datalayer_geometryc->rawSOCmax = poll_raw_soc_max;
|
||||||
|
datalayer_geometryc->rawSOCmin = poll_raw_soc_min;
|
||||||
|
datalayer_geometryc->unknown4 = poll_unknown4;
|
||||||
|
datalayer_geometryc->capModMax = poll_cap_module_max;
|
||||||
|
datalayer_geometryc->capModMin = poll_cap_module_min;
|
||||||
|
datalayer_geometryc->unknown7 = poll_unknown7;
|
||||||
|
datalayer_geometryc->unknown8 = poll_unknown8;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char crctable[256] = { // CRC8_SAE_J1850_ZER0 formula,0x2F Poly,initial value 0xFF,Final XOR value 0xFF
|
||||||
|
0x00, 0x2F, 0x5E, 0x71, 0xBC, 0x93, 0xE2, 0xCD, 0x57, 0x78, 0x09, 0x26, 0xEB, 0xC4, 0xB5, 0x9A, 0xAE, 0x81, 0xF0,
|
||||||
|
0xDF, 0x12, 0x3D, 0x4C, 0x63, 0xF9, 0xD6, 0xA7, 0x88, 0x45, 0x6A, 0x1B, 0x34, 0x73, 0x5C, 0x2D, 0x02, 0xCF, 0xE0,
|
||||||
|
0x91, 0xBE, 0x24, 0x0B, 0x7A, 0x55, 0x98, 0xB7, 0xC6, 0xE9, 0xDD, 0xF2, 0x83, 0xAC, 0x61, 0x4E, 0x3F, 0x10, 0x8A,
|
||||||
|
0xA5, 0xD4, 0xFB, 0x36, 0x19, 0x68, 0x47, 0xE6, 0xC9, 0xB8, 0x97, 0x5A, 0x75, 0x04, 0x2B, 0xB1, 0x9E, 0xEF, 0xC0,
|
||||||
|
0x0D, 0x22, 0x53, 0x7C, 0x48, 0x67, 0x16, 0x39, 0xF4, 0xDB, 0xAA, 0x85, 0x1F, 0x30, 0x41, 0x6E, 0xA3, 0x8C, 0xFD,
|
||||||
|
0xD2, 0x95, 0xBA, 0xCB, 0xE4, 0x29, 0x06, 0x77, 0x58, 0xC2, 0xED, 0x9C, 0xB3, 0x7E, 0x51, 0x20, 0x0F, 0x3B, 0x14,
|
||||||
|
0x65, 0x4A, 0x87, 0xA8, 0xD9, 0xF6, 0x6C, 0x43, 0x32, 0x1D, 0xD0, 0xFF, 0x8E, 0xA1, 0xE3, 0xCC, 0xBD, 0x92, 0x5F,
|
||||||
|
0x70, 0x01, 0x2E, 0xB4, 0x9B, 0xEA, 0xC5, 0x08, 0x27, 0x56, 0x79, 0x4D, 0x62, 0x13, 0x3C, 0xF1, 0xDE, 0xAF, 0x80,
|
||||||
|
0x1A, 0x35, 0x44, 0x6B, 0xA6, 0x89, 0xF8, 0xD7, 0x90, 0xBF, 0xCE, 0xE1, 0x2C, 0x03, 0x72, 0x5D, 0xC7, 0xE8, 0x99,
|
||||||
|
0xB6, 0x7B, 0x54, 0x25, 0x0A, 0x3E, 0x11, 0x60, 0x4F, 0x82, 0xAD, 0xDC, 0xF3, 0x69, 0x46, 0x37, 0x18, 0xD5, 0xFA,
|
||||||
|
0x8B, 0xA4, 0x05, 0x2A, 0x5B, 0x74, 0xB9, 0x96, 0xE7, 0xC8, 0x52, 0x7D, 0x0C, 0x23, 0xEE, 0xC1, 0xB0, 0x9F, 0xAB,
|
||||||
|
0x84, 0xF5, 0xDA, 0x17, 0x38, 0x49, 0x66, 0xFC, 0xD3, 0xA2, 0x8D, 0x40, 0x6F, 0x1E, 0x31, 0x76, 0x59, 0x28, 0x07,
|
||||||
|
0xCA, 0xE5, 0x94, 0xBB, 0x21, 0x0E, 0x7F, 0x50, 0x9D, 0xB2, 0xC3, 0xEC, 0xD8, 0xF7, 0x86, 0xA9, 0x64, 0x4B, 0x3A,
|
||||||
|
0x15, 0x8F, 0xA0, 0xD1, 0xFE, 0x33, 0x1C, 0x6D, 0x42};
|
||||||
|
|
||||||
|
bool is_message_corrupt(CAN_frame* rx_frame) {
|
||||||
|
uint8_t crc = 0xFF; // Initial value
|
||||||
|
for (uint8_t j = 0; j < 7; j++) {
|
||||||
|
crc = crctable[crc ^ rx_frame->data.u8[j]];
|
||||||
|
}
|
||||||
|
crc = (crc ^ 0xFF); // Final XOR
|
||||||
|
return crc != rx_frame->data.u8[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeelyGeometryCBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
|
switch (rx_frame.ID) {
|
||||||
|
case 0x0B0: //10ms
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
if (is_message_corrupt(&rx_frame)) {
|
||||||
|
datalayer.battery2.status.CAN_error_counter++;
|
||||||
|
break; //Message content malformed, abort reading data from it
|
||||||
|
}
|
||||||
|
//Contains:
|
||||||
|
//HVIL Signal
|
||||||
|
// - HVIL not connected: 000000B0 00 8 10 06 00 00 00 00 8E 31
|
||||||
|
// - HVIL connected: 000000B0 00 8 10 00 00 00 00 00 82 0D
|
||||||
|
// Based on this, the two HVIL is most likely frame1
|
||||||
|
HVIL_signal = (rx_frame.data.u8[1] & 0x0F);
|
||||||
|
//BatteryDchgSysFaultLevel
|
||||||
|
//ChgFaultLevel
|
||||||
|
//frame7, CRC
|
||||||
|
//frame6, low byte counter 0-F
|
||||||
|
break;
|
||||||
|
case 0x178: //10ms (64 13 88 00 0E 30 0A 85)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
if (is_message_corrupt(&rx_frame)) {
|
||||||
|
datalayer.battery2.status.CAN_error_counter++;
|
||||||
|
break; //Message content malformed, abort reading data from it
|
||||||
|
}
|
||||||
|
battery_voltage = ((rx_frame.data.u8[4] & 0x1F) << 8) | rx_frame.data.u8[5];
|
||||||
|
//frame7, CRC
|
||||||
|
//frame6, low byte counter 0-F
|
||||||
|
break;
|
||||||
|
case 0x179: //20ms (3E 52 BA 5D A4 3F 0C D9)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
if (is_message_corrupt(&rx_frame)) {
|
||||||
|
datalayer.battery2.status.CAN_error_counter++;
|
||||||
|
break; //Message content malformed, abort reading data from it
|
||||||
|
}
|
||||||
|
//2BA = 69.8 //Potentially charge power allowed
|
||||||
|
//frame7, CRC
|
||||||
|
//frame6, low byte counter 0-F
|
||||||
|
break;
|
||||||
|
case 0x17A: //100ms (Battery 01 B4 52 28 4A 46 6E AE)
|
||||||
|
//(Car log 0A 3D EE F1 BD C6 67 F7)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
if (is_message_corrupt(&rx_frame)) {
|
||||||
|
datalayer.battery2.status.CAN_error_counter++;
|
||||||
|
break; //Message content malformed, abort reading data from it
|
||||||
|
}
|
||||||
|
//frame7, CRC
|
||||||
|
//frame6, low byte counter 0-F
|
||||||
|
break;
|
||||||
|
case 0x17B: //20ms (00 00 10 00 0F FE 03 C9) (car is the same, static)
|
||||||
|
if (is_message_corrupt(&rx_frame)) {
|
||||||
|
datalayer.battery2.status.CAN_error_counter++;
|
||||||
|
break; //Message content malformed, abort reading data from it
|
||||||
|
}
|
||||||
|
//frame7, CRC
|
||||||
|
//frame6, low byte counter 0-F
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x210: //100ms (38 04 3A 01 38 22 22 39)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
if (is_message_corrupt(&rx_frame)) {
|
||||||
|
datalayer.battery2.status.CAN_error_counter++;
|
||||||
|
break; //Message content malformed, abort reading data from it
|
||||||
|
}
|
||||||
|
discharge_power_allowed = ((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[2]; //TODO, not confirmed
|
||||||
|
//43A = 108.2kW potentially discharge power allowed
|
||||||
|
//frame7, CRC
|
||||||
|
//frame6, counter 0 - 0x22
|
||||||
|
break;
|
||||||
|
case 0x211: //100ms (00 D8 C6 00 00 00 0F 3A)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
if (is_message_corrupt(&rx_frame)) {
|
||||||
|
datalayer.battery2.status.CAN_error_counter++;
|
||||||
|
break; //Message content malformed, abort reading data from it
|
||||||
|
}
|
||||||
|
//frame7, CRC
|
||||||
|
//frame6, low byte counter 0-F
|
||||||
|
break;
|
||||||
|
case 0x212: //500ms (Completely empty)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x351: //100ms (4A 31 71 B8 6E F8 84 00)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x352: //500ms (76 78 00 00 82 FF FF 00)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x353: //500ms (00 00 00 00 62 00 EA 5D) (car 00 00 00 00 00 00 E6 04)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x354: //500ms (Completely empty)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x355: //500ms (89 4A 03 5C 39 06 04 00)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x356: //1s (6B 09 0C 69 0A F1 D3 86)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x357: //20ms (18 17 6F 20 00 00 00 00)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
//Frame 0 and 1 seems to count something large
|
||||||
|
break;
|
||||||
|
case 0x358: //1s (03 DF 10 3C DA 0E 20 DE)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x359: //1s (1F 40 00 00 00 00 00 36)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
//Frame7 loops 01-21-22-36-01-21...
|
||||||
|
break;
|
||||||
|
case 0x35B: //200ms (Serialnumbers)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
mux = rx_frame.data.u8[0];
|
||||||
|
switch (mux) {
|
||||||
|
case 0x01:
|
||||||
|
serialnumbers[0] = rx_frame.data.u8[1];
|
||||||
|
serialnumbers[1] = rx_frame.data.u8[2];
|
||||||
|
serialnumbers[2] = rx_frame.data.u8[3];
|
||||||
|
serialnumbers[3] = rx_frame.data.u8[4];
|
||||||
|
serialnumbers[4] = rx_frame.data.u8[5];
|
||||||
|
serialnumbers[5] = rx_frame.data.u8[6];
|
||||||
|
serialnumbers[6] = rx_frame.data.u8[7];
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
serialnumbers[7] = rx_frame.data.u8[1];
|
||||||
|
serialnumbers[8] = rx_frame.data.u8[2];
|
||||||
|
serialnumbers[9] = rx_frame.data.u8[3];
|
||||||
|
serialnumbers[10] = rx_frame.data.u8[4];
|
||||||
|
serialnumbers[11] = rx_frame.data.u8[5];
|
||||||
|
serialnumbers[12] = rx_frame.data.u8[6];
|
||||||
|
serialnumbers[13] = rx_frame.data.u8[7];
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
serialnumbers[14] = rx_frame.data.u8[1];
|
||||||
|
serialnumbers[15] = rx_frame.data.u8[2];
|
||||||
|
serialnumbers[16] = rx_frame.data.u8[3];
|
||||||
|
serialnumbers[17] = rx_frame.data.u8[4];
|
||||||
|
serialnumbers[18] = rx_frame.data.u8[5];
|
||||||
|
serialnumbers[19] = rx_frame.data.u8[6];
|
||||||
|
serialnumbers[20] = rx_frame.data.u8[7];
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
serialnumbers[21] = rx_frame.data.u8[1];
|
||||||
|
serialnumbers[22] = rx_frame.data.u8[2];
|
||||||
|
serialnumbers[23] = rx_frame.data.u8[3];
|
||||||
|
serialnumbers[24] = rx_frame.data.u8[4];
|
||||||
|
serialnumbers[25] = rx_frame.data.u8[5];
|
||||||
|
serialnumbers[26] = rx_frame.data.u8[6];
|
||||||
|
serialnumbers[27] = rx_frame.data.u8[7];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x424: //500ms (24 10 01 01 02 00 00 00)
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
break;
|
||||||
|
case 0x7EA:
|
||||||
|
if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK
|
||||||
|
transmit_can_frame(&GEELY_ACK, can_config.battery);
|
||||||
|
//Multiframe has the poll reply slightly different location
|
||||||
|
incoming_poll = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4];
|
||||||
|
}
|
||||||
|
if (rx_frame.data.u8[0] < 0x10) { //One line response
|
||||||
|
incoming_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||||
|
|
||||||
|
switch (incoming_poll) {
|
||||||
|
case POLL_SOC:
|
||||||
|
poll_soc = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
break;
|
||||||
|
case POLL_CC2_VOLTAGE:
|
||||||
|
poll_cc2_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
break;
|
||||||
|
case POLL_CELL_MAX_VOLTAGE_NUMBER:
|
||||||
|
poll_cell_max_voltage_number = rx_frame.data.u8[4];
|
||||||
|
break;
|
||||||
|
case POLL_CELL_MIN_VOLTAGE_NUMBER:
|
||||||
|
poll_cell_min_voltage_number = rx_frame.data.u8[4];
|
||||||
|
break;
|
||||||
|
case POLL_AMOUNT_CELLS:
|
||||||
|
poll_amount_cells = rx_frame.data.u8[4];
|
||||||
|
datalayer_battery->info.number_of_cells = poll_amount_cells;
|
||||||
|
break;
|
||||||
|
case POLL_SPECIFICIAL_VOLTAGE:
|
||||||
|
poll_specificial_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
break;
|
||||||
|
case POLL_UNKNOWN_1:
|
||||||
|
poll_unknown1 = rx_frame.data.u8[4];
|
||||||
|
break;
|
||||||
|
case POLL_RAW_SOC_MAX:
|
||||||
|
poll_raw_soc_max = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
break;
|
||||||
|
case POLL_RAW_SOC_MIN:
|
||||||
|
poll_raw_soc_min = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
break;
|
||||||
|
case POLL_UNKNOWN_4:
|
||||||
|
poll_unknown4 = rx_frame.data.u8[4];
|
||||||
|
break;
|
||||||
|
case POLL_CAPACITY_MODULE_MAX:
|
||||||
|
poll_cap_module_max = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
break;
|
||||||
|
case POLL_CAPACITY_MODULE_MIN:
|
||||||
|
poll_cap_module_min = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
break;
|
||||||
|
case POLL_UNKNOWN_7:
|
||||||
|
poll_unknown7 = rx_frame.data.u8[4];
|
||||||
|
break;
|
||||||
|
case POLL_UNKNOWN_8:
|
||||||
|
poll_unknown8 = rx_frame.data.u8[4];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (incoming_poll) //Multiframe response
|
||||||
|
{
|
||||||
|
case POLL_MULTI_TEMPS:
|
||||||
|
switch (rx_frame.data.u8[0]) {
|
||||||
|
case 0x10:
|
||||||
|
poll_temperature[0] = (rx_frame.data.u8[5] - TEMP_OFFSET);
|
||||||
|
poll_temperature[1] = (rx_frame.data.u8[6] - TEMP_OFFSET);
|
||||||
|
poll_temperature[2] = (rx_frame.data.u8[7] - TEMP_OFFSET);
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
poll_temperature[3] = (rx_frame.data.u8[1] - TEMP_OFFSET);
|
||||||
|
poll_temperature[4] = (rx_frame.data.u8[2] - TEMP_OFFSET);
|
||||||
|
poll_temperature[5] = (rx_frame.data.u8[3] - TEMP_OFFSET);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POLL_MULTI_SOFTWARE_VERSION:
|
||||||
|
switch (rx_frame.data.u8[0]) {
|
||||||
|
case 0x10:
|
||||||
|
poll_software_version[0] = rx_frame.data.u8[5];
|
||||||
|
poll_software_version[1] = rx_frame.data.u8[6];
|
||||||
|
poll_software_version[2] = rx_frame.data.u8[7];
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
poll_software_version[3] = rx_frame.data.u8[1];
|
||||||
|
poll_software_version[4] = rx_frame.data.u8[2];
|
||||||
|
poll_software_version[5] = rx_frame.data.u8[3];
|
||||||
|
poll_software_version[6] = rx_frame.data.u8[4];
|
||||||
|
poll_software_version[7] = rx_frame.data.u8[5];
|
||||||
|
poll_software_version[8] = rx_frame.data.u8[6];
|
||||||
|
poll_software_version[9] = rx_frame.data.u8[7];
|
||||||
|
break;
|
||||||
|
case 0x22:
|
||||||
|
poll_software_version[10] = rx_frame.data.u8[1];
|
||||||
|
poll_software_version[11] = rx_frame.data.u8[2];
|
||||||
|
poll_software_version[12] = rx_frame.data.u8[3];
|
||||||
|
poll_software_version[13] = rx_frame.data.u8[4];
|
||||||
|
poll_software_version[14] = rx_frame.data.u8[5];
|
||||||
|
poll_software_version[15] = rx_frame.data.u8[6];
|
||||||
|
break;
|
||||||
|
case 0x23:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POLL_MULTI_HARDWARE_VERSION:
|
||||||
|
switch (rx_frame.data.u8[0]) {
|
||||||
|
case 0x10:
|
||||||
|
poll_hardware_version[0] = rx_frame.data.u8[5];
|
||||||
|
poll_hardware_version[1] = rx_frame.data.u8[6];
|
||||||
|
poll_hardware_version[2] = rx_frame.data.u8[7];
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
poll_hardware_version[3] = rx_frame.data.u8[1];
|
||||||
|
poll_hardware_version[4] = rx_frame.data.u8[2];
|
||||||
|
poll_hardware_version[5] = rx_frame.data.u8[3];
|
||||||
|
poll_hardware_version[6] = rx_frame.data.u8[4];
|
||||||
|
poll_hardware_version[7] = rx_frame.data.u8[5];
|
||||||
|
poll_hardware_version[8] = rx_frame.data.u8[6];
|
||||||
|
poll_hardware_version[9] = rx_frame.data.u8[7];
|
||||||
|
break;
|
||||||
|
case 0x22:
|
||||||
|
poll_hardware_version[10] = rx_frame.data.u8[1];
|
||||||
|
poll_hardware_version[11] = rx_frame.data.u8[2];
|
||||||
|
poll_hardware_version[12] = rx_frame.data.u8[3];
|
||||||
|
poll_hardware_version[13] = rx_frame.data.u8[4];
|
||||||
|
poll_hardware_version[14] = rx_frame.data.u8[5];
|
||||||
|
poll_hardware_version[15] = rx_frame.data.u8[6];
|
||||||
|
break;
|
||||||
|
case 0x23:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//Not a multiframe response, do nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t calc_crc8_geely(CAN_frame* rx_frame) {
|
||||||
|
uint8_t crc = 0xFF; // Initial value
|
||||||
|
|
||||||
|
for (uint8_t j = 0; j < 7; j++) {
|
||||||
|
crc = crctable[crc ^ rx_frame->data.u8[j]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc ^ 0xFF; // Final XOR
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeelyGeometryCBattery::transmit_can(unsigned long currentMillis) {
|
||||||
|
// Send 10ms CAN Message
|
||||||
|
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
|
||||||
|
previousMillis10 = currentMillis;
|
||||||
|
|
||||||
|
GEELY_191.data.u8[6] = ((GEELY_191.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_191.data.u8[7] = calc_crc8_geely(&GEELY_191);
|
||||||
|
GEELY_0A6.data.u8[6] = ((GEELY_0A6.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_0A6.data.u8[7] = calc_crc8_geely(&GEELY_0A6);
|
||||||
|
GEELY_165.data.u8[6] = ((GEELY_165.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_165.data.u8[7] = calc_crc8_geely(&GEELY_165);
|
||||||
|
GEELY_1A4.data.u8[6] = ((GEELY_1A4.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_1A4.data.u8[7] = calc_crc8_geely(&GEELY_1A4);
|
||||||
|
GEELY_162.data.u8[6] = ((GEELY_162.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_162.data.u8[7] = calc_crc8_geely(&GEELY_162);
|
||||||
|
GEELY_1A5.data.u8[6] = ((GEELY_1A5.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_1A5.data.u8[7] = calc_crc8_geely(&GEELY_1A5);
|
||||||
|
GEELY_220.data.u8[6] = ((GEELY_220.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_220.data.u8[7] = calc_crc8_geely(&GEELY_220);
|
||||||
|
GEELY_0E0.data.u8[4] = ((GEELY_0E0.data.u8[4] & 0xF0) | counter_10ms); //unique
|
||||||
|
GEELY_0E0.data.u8[5] = calc_crc8_geely(&GEELY_0E0); //unique
|
||||||
|
|
||||||
|
counter_10ms = (counter_10ms + 1) % 17; // 0-1-...F-0-1 etc.
|
||||||
|
|
||||||
|
transmit_can_frame(&GEELY_191, can_config.battery);
|
||||||
|
transmit_can_frame(&GEELY_0A6, can_config.battery);
|
||||||
|
transmit_can_frame(&GEELY_160, can_config.battery);
|
||||||
|
transmit_can_frame(&GEELY_165, can_config.battery);
|
||||||
|
transmit_can_frame(&GEELY_1A4, can_config.battery);
|
||||||
|
transmit_can_frame(&GEELY_162, can_config.battery); //CONFIRMED MANDATORY! VCU message
|
||||||
|
transmit_can_frame(&GEELY_1A5, can_config.battery);
|
||||||
|
transmit_can_frame(&GEELY_220, can_config.battery); //CONFIRMED MANDATORY! OBC message
|
||||||
|
transmit_can_frame(&GEELY_0E0, can_config.battery);
|
||||||
|
}
|
||||||
|
if (currentMillis - previousMillis20 >= INTERVAL_20_MS) {
|
||||||
|
previousMillis20 = currentMillis;
|
||||||
|
|
||||||
|
GEELY_145.data.u8[6] = ((GEELY_145.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_145.data.u8[7] = calc_crc8_geely(&GEELY_145);
|
||||||
|
GEELY_150.data.u8[6] = ((GEELY_150.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_150.data.u8[7] = calc_crc8_geely(&GEELY_150);
|
||||||
|
|
||||||
|
counter_20ms = (counter_20ms + 1) % 17; // 0-1-...F-0-1 etc.
|
||||||
|
|
||||||
|
transmit_can_frame(&GEELY_145, can_config.battery); //CONFIRMED MANDATORY! shifter
|
||||||
|
transmit_can_frame(&GEELY_0F9, can_config.battery); //CONFIRMED MANDATORY! shifter
|
||||||
|
transmit_can_frame(&GEELY_0FA, can_config.battery); //Might be unnecessary, not in workshop manual
|
||||||
|
transmit_can_frame(&GEELY_197, can_config.battery); //Might be unnecessary, not in workshop manual
|
||||||
|
transmit_can_frame(&GEELY_150, can_config.battery);
|
||||||
|
}
|
||||||
|
if (currentMillis - previousMillis50 >= INTERVAL_50_MS) {
|
||||||
|
previousMillis50 = currentMillis;
|
||||||
|
|
||||||
|
GEELY_1A3.data.u8[6] = ((GEELY_1A3.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_1A3.data.u8[7] = calc_crc8_geely(&GEELY_1A3);
|
||||||
|
GEELY_0A8.data.u8[6] = ((GEELY_0A8.data.u8[6] & 0xF0) | counter_10ms);
|
||||||
|
GEELY_0A8.data.u8[7] = calc_crc8_geely(&GEELY_0A8);
|
||||||
|
|
||||||
|
counter_50ms = (counter_50ms + 1) % 17; // 0-1-...F-0-1 etc.
|
||||||
|
|
||||||
|
transmit_can_frame(&GEELY_1B2, can_config.battery);
|
||||||
|
transmit_can_frame(&GEELY_221, can_config.battery); //CONFIRMED MANDATORY! OBC message
|
||||||
|
//transmit_can_frame(&GEELY_1A3, can_config.battery); //Might be unnecessary, radar info
|
||||||
|
transmit_can_frame(&GEELY_1A7, can_config.battery); //Might be unnecessary
|
||||||
|
transmit_can_frame(&GEELY_0A8, can_config.battery); //CONFIRMED MANDATORY! IPU message
|
||||||
|
transmit_can_frame(&GEELY_1F2, can_config.battery); //Might be unnecessary, not in manual
|
||||||
|
transmit_can_frame(&GEELY_1A6, can_config.battery); //Might be unnecessary, not in manual
|
||||||
|
}
|
||||||
|
// Send 100ms CAN Message
|
||||||
|
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||||
|
previousMillis100 = currentMillis;
|
||||||
|
|
||||||
|
GEELY_0A8.data.u8[6] = ((GEELY_0A8.data.u8[6] & 0x0F) | (counter_10ms << 4)); //unique bitshift
|
||||||
|
GEELY_0A8.data.u8[7] = calc_crc8_geely(&GEELY_0A8);
|
||||||
|
|
||||||
|
counter_100ms = (counter_100ms + 1) % 17; // 0-1-...F-0-1 etc.
|
||||||
|
|
||||||
|
transmit_can_frame(&GEELY_222, can_config.battery); //CONFIRMED MANDATORY! OBC message
|
||||||
|
//transmit_can_frame(&GEELY_2D2, can_config.battery); //Might be unnecessary, seat info
|
||||||
|
transmit_can_frame(&GEELY_292, can_config.battery); //CONFIRMED MANDATORY! T-BOX
|
||||||
|
}
|
||||||
|
// Send 200ms CAN Message
|
||||||
|
if (currentMillis - previousMillis200 >= INTERVAL_200_MS) {
|
||||||
|
previousMillis200 = currentMillis;
|
||||||
|
|
||||||
|
switch (poll_pid) {
|
||||||
|
case POLL_SOC:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_SOC >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_SOC;
|
||||||
|
poll_pid = POLL_CC2_VOLTAGE;
|
||||||
|
break;
|
||||||
|
case POLL_CC2_VOLTAGE:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_CC2_VOLTAGE >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_CC2_VOLTAGE;
|
||||||
|
poll_pid = POLL_CELL_MAX_VOLTAGE_NUMBER;
|
||||||
|
break;
|
||||||
|
case POLL_CELL_MAX_VOLTAGE_NUMBER:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_CELL_MAX_VOLTAGE_NUMBER >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_CELL_MAX_VOLTAGE_NUMBER;
|
||||||
|
poll_pid = POLL_CELL_MIN_VOLTAGE_NUMBER;
|
||||||
|
break;
|
||||||
|
case POLL_CELL_MIN_VOLTAGE_NUMBER:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_CELL_MIN_VOLTAGE_NUMBER >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_CELL_MIN_VOLTAGE_NUMBER;
|
||||||
|
poll_pid = POLL_AMOUNT_CELLS;
|
||||||
|
break;
|
||||||
|
case POLL_AMOUNT_CELLS:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_AMOUNT_CELLS >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_AMOUNT_CELLS;
|
||||||
|
poll_pid = POLL_SPECIFICIAL_VOLTAGE;
|
||||||
|
break;
|
||||||
|
case POLL_SPECIFICIAL_VOLTAGE:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_SPECIFICIAL_VOLTAGE >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_SPECIFICIAL_VOLTAGE;
|
||||||
|
poll_pid = POLL_UNKNOWN_1;
|
||||||
|
break;
|
||||||
|
case POLL_UNKNOWN_1:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_UNKNOWN_1 >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_UNKNOWN_1;
|
||||||
|
poll_pid = POLL_RAW_SOC_MAX;
|
||||||
|
break;
|
||||||
|
case POLL_RAW_SOC_MAX:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_RAW_SOC_MAX >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_RAW_SOC_MAX;
|
||||||
|
poll_pid = POLL_RAW_SOC_MIN;
|
||||||
|
break;
|
||||||
|
case POLL_RAW_SOC_MIN:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_RAW_SOC_MIN >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_RAW_SOC_MIN;
|
||||||
|
poll_pid = POLL_UNKNOWN_4;
|
||||||
|
break;
|
||||||
|
case POLL_UNKNOWN_4:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_UNKNOWN_4 >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_UNKNOWN_4;
|
||||||
|
poll_pid = POLL_CAPACITY_MODULE_MAX;
|
||||||
|
break;
|
||||||
|
case POLL_CAPACITY_MODULE_MAX:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_CAPACITY_MODULE_MAX >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_CAPACITY_MODULE_MAX;
|
||||||
|
poll_pid = POLL_CAPACITY_MODULE_MIN;
|
||||||
|
break;
|
||||||
|
case POLL_CAPACITY_MODULE_MIN:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_CAPACITY_MODULE_MIN >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_CAPACITY_MODULE_MIN;
|
||||||
|
poll_pid = POLL_UNKNOWN_7;
|
||||||
|
break;
|
||||||
|
case POLL_UNKNOWN_7:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_UNKNOWN_7 >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_UNKNOWN_7;
|
||||||
|
poll_pid = POLL_UNKNOWN_8;
|
||||||
|
break;
|
||||||
|
case POLL_UNKNOWN_8:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_UNKNOWN_8 >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_UNKNOWN_8;
|
||||||
|
poll_pid = POLL_MULTI_TEMPS;
|
||||||
|
break;
|
||||||
|
case POLL_MULTI_TEMPS:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_TEMPS >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_TEMPS;
|
||||||
|
poll_pid = POLL_MULTI_UNKNOWN_2;
|
||||||
|
break;
|
||||||
|
case POLL_MULTI_UNKNOWN_2:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_UNKNOWN_2 >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_UNKNOWN_2;
|
||||||
|
poll_pid = POLL_MULTI_UNKNOWN_3;
|
||||||
|
break;
|
||||||
|
case POLL_MULTI_UNKNOWN_3:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_UNKNOWN_3 >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_UNKNOWN_3;
|
||||||
|
poll_pid = POLL_MULTI_UNKNOWN_4;
|
||||||
|
break;
|
||||||
|
case POLL_MULTI_UNKNOWN_4:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_UNKNOWN_4 >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_UNKNOWN_4;
|
||||||
|
poll_pid = POLL_MULTI_HARDWARE_VERSION;
|
||||||
|
break;
|
||||||
|
case POLL_MULTI_HARDWARE_VERSION:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_HARDWARE_VERSION >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_HARDWARE_VERSION;
|
||||||
|
poll_pid = POLL_MULTI_SOFTWARE_VERSION;
|
||||||
|
break;
|
||||||
|
case POLL_MULTI_SOFTWARE_VERSION:
|
||||||
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_SOFTWARE_VERSION >> 8);
|
||||||
|
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_SOFTWARE_VERSION;
|
||||||
|
poll_pid = POLL_SOC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
poll_pid = POLL_SOC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
transmit_can_frame(&GEELY_POLL, can_config.battery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeelyGeometryCBattery::setup(void) { // Performs one time setup at startup
|
||||||
|
strncpy(datalayer.system.info.battery_protocol, "Geely Geometry C", 63);
|
||||||
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
|
datalayer_battery->info.number_of_cells = 102; //70kWh pack has 102S, startup in this mode
|
||||||
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_70_DV; //Startup in extreme ends
|
||||||
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_53_DV; //Before pack size determined
|
||||||
|
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
|
217
Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h
Normal file
217
Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
#ifndef GEELY_GEOMETRY_C_BATTERY_H
|
||||||
|
#define GEELY_GEOMETRY_C_BATTERY_H
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
|
#include "../datalayer/datalayer_extended.h"
|
||||||
|
#include "../include.h"
|
||||||
|
#include "CanBattery.h"
|
||||||
|
|
||||||
|
#define BATTERY_SELECTED
|
||||||
|
#define SELECTED_BATTERY_CLASS GeelyGeometryCBattery
|
||||||
|
|
||||||
|
#define POLL_SOC 0x4B35
|
||||||
|
#define POLL_CC2_VOLTAGE 0x4BCF
|
||||||
|
#define POLL_CELL_MAX_VOLTAGE_NUMBER 0x4B1E
|
||||||
|
#define POLL_CELL_MIN_VOLTAGE_NUMBER 0x4B20
|
||||||
|
#define POLL_AMOUNT_CELLS 0x4B07
|
||||||
|
#define POLL_SPECIFICIAL_VOLTAGE 0x4B05
|
||||||
|
#define POLL_UNKNOWN_1 0x4BDA //245 on two batteries
|
||||||
|
#define POLL_RAW_SOC_MAX 0x4BC3
|
||||||
|
#define POLL_RAW_SOC_MIN 0x4BC4
|
||||||
|
#define POLL_UNKNOWN_4 0xDF00 //144 (the other battery 143)
|
||||||
|
#define POLL_CAPACITY_MODULE_MAX 0x4B3D
|
||||||
|
#define POLL_CAPACITY_MODULE_MIN 0x4B3E
|
||||||
|
#define POLL_UNKNOWN_7 0x4B24 //1 (the other battery 23)
|
||||||
|
#define POLL_UNKNOWN_8 0x4B26 //16 (the other battery 33)
|
||||||
|
#define POLL_MULTI_TEMPS 0x4B0F
|
||||||
|
#define POLL_MULTI_UNKNOWN_2 0x4B10
|
||||||
|
#define POLL_MULTI_UNKNOWN_3 0x4B53
|
||||||
|
#define POLL_MULTI_UNKNOWN_4 0x4B54
|
||||||
|
#define POLL_MULTI_HARDWARE_VERSION 0x4B6B
|
||||||
|
#define POLL_MULTI_SOFTWARE_VERSION 0x4B6C
|
||||||
|
|
||||||
|
class GeelyGeometryCBattery : public CanBattery {
|
||||||
|
public:
|
||||||
|
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:
|
||||||
|
const int MAX_PACK_VOLTAGE_70_DV 4420 //70kWh
|
||||||
|
const int MIN_PACK_VOLTAGE_70_DV 2860 const int MAX_PACK_VOLTAGE_53_DV 4160 //53kWh
|
||||||
|
const int MIN_PACK_VOLTAGE_53_DV 2700 const int MAX_CELL_DEVIATION_MV 150 const int
|
||||||
|
MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
const int MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||||
|
DATALAYER_INFO_GEELY_GEOMETRY_C* datalayer_geometryc;
|
||||||
|
|
||||||
|
CAN_frame GEELY_191 = {.FD = false, //PAS_APA_Status , 10ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x191,
|
||||||
|
.data = {0x00, 0x00, 0x81, 0x20, 0x00, 0x00, 0x00, 0x01}};
|
||||||
|
CAN_frame GEELY_2D2 = {.FD = false, //DSCU 100ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x2D2,
|
||||||
|
.data = {0x60, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame GEELY_0A6 = {.FD = false, //VCU 10ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x0A6,
|
||||||
|
.data = {0xFA, 0x0F, 0xA0, 0x00, 0x00, 0xFA, 0x00, 0xE4}};
|
||||||
|
CAN_frame GEELY_160 = {.FD = false, //VCU 10ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x160,
|
||||||
|
.data = {0x00, 0x01, 0x67, 0xF7, 0xC0, 0x19, 0x00, 0x20}};
|
||||||
|
CAN_frame GEELY_165 = {.FD = false, //VCU_ModeControl 10ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x165,
|
||||||
|
.data = {0x00, 0x81, 0xA1, 0x00, 0x00, 0x1E, 0x00, 0xD6}};
|
||||||
|
CAN_frame GEELY_1A4 = {.FD = false, //VCU 10ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x1A4,
|
||||||
|
.data = {0x17, 0x73, 0x17, 0x70, 0x02, 0x1C, 0x00, 0x56}};
|
||||||
|
CAN_frame GEELY_162 = {.FD = false, //VCU 10ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x162,
|
||||||
|
.data = {0x00, 0x05, 0x06, 0x81, 0x00, 0x09, 0x00, 0xC6}};
|
||||||
|
CAN_frame GEELY_1A5 = {.FD = false, //VCU 10ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x1A5,
|
||||||
|
.data = {0x17, 0x70, 0x24, 0x0B, 0x00, 0x00, 0x00, 0xF9}};
|
||||||
|
CAN_frame GEELY_1B2 = {.FD = false, //??? 50ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x1B2,
|
||||||
|
.data = {0x17, 0x70, 0x24, 0x0B, 0x00, 0x00, 0x00, 0xF9}};
|
||||||
|
CAN_frame GEELY_221 = {.FD = false, //OBC 50ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x221,
|
||||||
|
.data = {0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00}};
|
||||||
|
CAN_frame GEELY_220 = {.FD = false, //OBC 100ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x220,
|
||||||
|
.data = {0x0B, 0x43, 0x69, 0xF3, 0x3A, 0x10, 0x00, 0x31}};
|
||||||
|
CAN_frame GEELY_1A3 = {.FD = false, //FRS 50ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x1A3,
|
||||||
|
.data = {0xFF, 0x18, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4F}};
|
||||||
|
CAN_frame GEELY_1A7 = {.FD = false, //??? 50ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x1A7,
|
||||||
|
.data = {0x00, 0x7F, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame GEELY_0A8 = {.FD = false, //IPU 100ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x0A8,
|
||||||
|
.data = {0x00, 0x2E, 0xDC, 0x4E, 0x20, 0x00, 0x20, 0xA2}};
|
||||||
|
CAN_frame GEELY_1F2 = {.FD = false, //??? 50ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x1F2,
|
||||||
|
.data = {0x9B, 0xA3, 0x99, 0xA2, 0x41, 0x42, 0x41, 0x42}};
|
||||||
|
CAN_frame GEELY_222 = {.FD = false, //OBC 100ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x222,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame GEELY_1A6 = {.FD = false, //OBC 100ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x1A6,
|
||||||
|
.data = {0x00, 0x7F, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame GEELY_145 = {.FD = false, //EGSM 20ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x145,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A}};
|
||||||
|
CAN_frame GEELY_0E0 = {.FD = false, //IPU 10ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x0E0,
|
||||||
|
.data = {0xFF, 0x09, 0x00, 0xE0, 0x00, 0x8F, 0x00, 0x00}};
|
||||||
|
CAN_frame GEELY_0F9 = {.FD = false, //??? 20ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x0F9,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame GEELY_292 = {.FD = false, //T-BOX 100ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x292,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x1F, 0xE7, 0xE7, 0x00, 0xBC}};
|
||||||
|
CAN_frame GEELY_0FA = {.FD = false, //??? 20ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x0FA,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame GEELY_197 = {.FD = false, //??? 20ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x197,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A}};
|
||||||
|
CAN_frame GEELY_150 = {.FD = false, //EPS 20ms
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x150,
|
||||||
|
.data = {0x7E, 0x00, 0x24, 0x00, 0x01, 0x01, 0x00, 0xA9}};
|
||||||
|
CAN_frame GEELY_POLL = {.FD = false, //Polling frame
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E2,
|
||||||
|
.data = {0x03, 0x22, 0x4B, 0xDA, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame GEELY_ACK = {.FD = false, //Ack frame
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E2,
|
||||||
|
.data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
uint16_t poll_pid = POLL_SOC;
|
||||||
|
uint16_t incoming_poll = 0;
|
||||||
|
uint8_t counter_10ms = 0;
|
||||||
|
uint8_t counter_20ms = 0;
|
||||||
|
uint8_t counter_50ms = 0;
|
||||||
|
uint8_t counter_100ms = 0;
|
||||||
|
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent
|
||||||
|
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was sent
|
||||||
|
unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was sent
|
||||||
|
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
|
||||||
|
unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was sent
|
||||||
|
uint8_t mux = 0;
|
||||||
|
uint16_t battery_voltage = 3700;
|
||||||
|
int16_t maximum_temperature = 0;
|
||||||
|
int16_t minimum_temperature = 0;
|
||||||
|
uint8_t HVIL_signal = 0;
|
||||||
|
uint8_t serialnumbers[28] = {0};
|
||||||
|
uint16_t maximum_cell_voltage = 3700;
|
||||||
|
uint16_t discharge_power_allowed = 0;
|
||||||
|
uint16_t poll_soc = 0;
|
||||||
|
uint16_t poll_cc2_voltage = 0;
|
||||||
|
uint16_t poll_cell_max_voltage_number = 0;
|
||||||
|
uint16_t poll_cell_min_voltage_number = 0;
|
||||||
|
uint16_t poll_amount_cells = 0;
|
||||||
|
uint16_t poll_specificial_voltage = 0;
|
||||||
|
uint16_t poll_unknown1 = 0;
|
||||||
|
uint16_t poll_raw_soc_max = 0;
|
||||||
|
uint16_t poll_raw_soc_min = 0;
|
||||||
|
uint16_t poll_unknown4 = 0;
|
||||||
|
uint16_t poll_cap_module_max = 0;
|
||||||
|
uint16_t poll_cap_module_min = 0;
|
||||||
|
uint16_t poll_unknown7 = 0;
|
||||||
|
uint16_t poll_unknown8 = 0;
|
||||||
|
int16_t poll_temperature[6] = {0};
|
||||||
|
#define TEMP_OFFSET 30 //TODO, not calibrated yet, best guess
|
||||||
|
uint8_t poll_software_version[16] = {0};
|
||||||
|
uint8_t poll_hardware_version[16] = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -161,7 +161,7 @@ uint16_t selectSOC(uint16_t SOC_low, uint16_t SOC_high) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These messages are needed for contactor closing */
|
/* These messages are needed for contactor closing */
|
||||||
unsigned long startMillis;
|
unsigned long startMillis = 0;
|
||||||
uint8_t messageIndex = 0;
|
uint8_t messageIndex = 0;
|
||||||
uint8_t messageDelays[63] = {0, 0, 5, 10, 10, 15, 19, 19, 20, 20, 25, 30, 30, 35, 40, 40,
|
uint8_t messageDelays[63] = {0, 0, 5, 10, 10, 15, 19, 19, 20, 20, 25, 30, 30, 35, 40, 40,
|
||||||
45, 49, 49, 50, 50, 52, 53, 53, 54, 55, 60, 60, 65, 67, 67, 70,
|
45, 49, 49, 50, 50, 52, 53, 53, 54, 55, 60, 60, 65, 67, 67, 70,
|
||||||
|
@ -1100,7 +1100,7 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageIndex >= 63) {
|
if (messageIndex >= 63) {
|
||||||
startMillis = millis(); // Start over!
|
startMillis = currentMillis; // Start over!
|
||||||
messageIndex = 0;
|
messageIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1131,9 +1131,6 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
void setup_battery(void) { // Performs one time setup at startup
|
void setup_battery(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai EGMP platform", 63);
|
strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai EGMP platform", 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
|
|
||||||
startMillis = millis(); // Record the starting time
|
|
||||||
|
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery
|
datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
|
|
@ -1,176 +1,36 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#ifdef KIA_HYUNDAI_64_BATTERY
|
#ifdef KIA_HYUNDAI_64_BATTERY
|
||||||
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "KIA-HYUNDAI-64-BATTERY.h"
|
#include "KIA-HYUNDAI-64-BATTERY.h"
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
void KiaHyundai64Battery::
|
||||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
static unsigned long previousMillis10 = 0; // will store last time a 10s CAN Message was send
|
|
||||||
|
|
||||||
static uint16_t soc_calculated = 0;
|
datalayer_battery->status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
||||||
static uint16_t SOC_BMS = 0;
|
|
||||||
static uint16_t SOC_Display = 0;
|
|
||||||
static uint16_t batterySOH = 1000;
|
|
||||||
static uint16_t CellVoltMax_mV = 3700;
|
|
||||||
static uint16_t CellVoltMin_mV = 3700;
|
|
||||||
static uint16_t allowedDischargePower = 0;
|
|
||||||
static uint16_t allowedChargePower = 0;
|
|
||||||
static uint16_t batteryVoltage = 0;
|
|
||||||
static uint16_t inverterVoltageFrameHigh = 0;
|
|
||||||
static uint16_t inverterVoltage = 0;
|
|
||||||
static uint16_t cellvoltages_mv[98];
|
|
||||||
static int16_t leadAcidBatteryVoltage = 120;
|
|
||||||
static int16_t batteryAmps = 0;
|
|
||||||
static int16_t temperatureMax = 0;
|
|
||||||
static int16_t temperatureMin = 0;
|
|
||||||
static int16_t poll_data_pid = 0;
|
|
||||||
static bool holdPidCounter = false;
|
|
||||||
static uint8_t CellVmaxNo = 0;
|
|
||||||
static uint8_t CellVminNo = 0;
|
|
||||||
static uint8_t batteryManagementMode = 0;
|
|
||||||
static uint8_t BMS_ign = 0;
|
|
||||||
static uint8_t batteryRelay = 0;
|
|
||||||
static uint8_t waterleakageSensor = 164;
|
|
||||||
static uint8_t counter_200 = 0;
|
|
||||||
static int8_t temperature_water_inlet = 0;
|
|
||||||
static int8_t heatertemp = 0;
|
|
||||||
static int8_t powerRelayTemperature = 0;
|
|
||||||
static bool startedUp = false;
|
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
datalayer_battery->status.soh_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00%
|
||||||
static uint8_t counter_200_2 = 0;
|
|
||||||
static uint16_t battery2_soc_calculated = 0;
|
|
||||||
static uint16_t battery2_SOC_BMS = 0;
|
|
||||||
static uint16_t battery2_SOC_Display = 0;
|
|
||||||
static uint16_t battery2_batterySOH = 1000;
|
|
||||||
static uint16_t battery2_CellVoltMax_mV = 3700;
|
|
||||||
static uint16_t battery2_CellVoltMin_mV = 3700;
|
|
||||||
static uint16_t battery2_allowedDischargePower = 0;
|
|
||||||
static uint16_t battery2_allowedChargePower = 0;
|
|
||||||
static uint16_t battery2_batteryVoltage = 0;
|
|
||||||
static uint16_t battery2_inverterVoltageFrameHigh = 0;
|
|
||||||
static uint16_t battery2_inverterVoltage = 0;
|
|
||||||
static uint16_t battery2_cellvoltages_mv[98];
|
|
||||||
static int16_t battery2_leadAcidBatteryVoltage = 120;
|
|
||||||
static int16_t battery2_batteryAmps = 0;
|
|
||||||
static int16_t battery2_temperatureMax = 0;
|
|
||||||
static int16_t battery2_temperatureMin = 0;
|
|
||||||
static int16_t battery2_poll_data_pid = 0;
|
|
||||||
static bool battery2_holdPidCounter = false;
|
|
||||||
static uint8_t battery2_CellVmaxNo = 0;
|
|
||||||
static uint8_t battery2_CellVminNo = 0;
|
|
||||||
static uint8_t battery2_batteryManagementMode = 0;
|
|
||||||
static uint8_t battery2_BMS_ign = 0;
|
|
||||||
static uint8_t battery2_batteryRelay = 0;
|
|
||||||
static uint8_t battery2_waterleakageSensor = 164;
|
|
||||||
static uint8_t battery2_counter_200 = 0;
|
|
||||||
static int8_t battery2_temperature_water_inlet = 0;
|
|
||||||
static int8_t battery2_heatertemp = 0;
|
|
||||||
static int8_t battery2_powerRelayTemperature = 0;
|
|
||||||
static bool battery2_startedUp = false;
|
|
||||||
CAN_frame KIA_HYUNDAI_200_2 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x200,
|
|
||||||
.data = {0x00, 0x80, 0xD8, 0x04, 0x00, 0x17, 0xD0, 0x00}}; //2nd battery
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
|
|
||||||
CAN_frame KIA_HYUNDAI_200 = {.FD = false,
|
datalayer_battery->status.voltage_dV = batteryVoltage; //value is *10 (3700 = 370.0)
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x200,
|
|
||||||
.data = {0x00, 0x80, 0xD8, 0x04, 0x00, 0x17, 0xD0, 0x00}};
|
|
||||||
CAN_frame KIA_HYUNDAI_523 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x523,
|
|
||||||
.data = {0x08, 0x38, 0x36, 0x36, 0x33, 0x34, 0x00, 0x01}};
|
|
||||||
CAN_frame KIA_HYUNDAI_524 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x524,
|
|
||||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
//553 Needed frame 200ms
|
|
||||||
CAN_frame KIA64_553 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x553,
|
|
||||||
.data = {0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00}};
|
|
||||||
//57F Needed frame 100ms
|
|
||||||
CAN_frame KIA64_57F = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x57F,
|
|
||||||
.data = {0x80, 0x0A, 0x72, 0x00, 0x00, 0x00, 0x00, 0x72}};
|
|
||||||
//Needed frame 100ms
|
|
||||||
CAN_frame KIA64_2A1 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x2A1,
|
|
||||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
CAN_frame KIA64_7E4_id1 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4,
|
|
||||||
.data = {0x03, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 01
|
|
||||||
CAN_frame KIA64_7E4_id2 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4,
|
|
||||||
.data = {0x03, 0x22, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 02
|
|
||||||
CAN_frame KIA64_7E4_id3 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4,
|
|
||||||
.data = {0x03, 0x22, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 03
|
|
||||||
CAN_frame KIA64_7E4_id4 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4,
|
|
||||||
.data = {0x03, 0x22, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 04
|
|
||||||
CAN_frame KIA64_7E4_id5 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4,
|
|
||||||
.data = {0x03, 0x22, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 05
|
|
||||||
CAN_frame KIA64_7E4_id6 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4,
|
|
||||||
.data = {0x03, 0x22, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 06
|
|
||||||
CAN_frame KIA64_7E4_ack = {
|
|
||||||
.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4,
|
|
||||||
.data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Ack frame, correct PID is returned
|
|
||||||
|
|
||||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
datalayer_battery->status.current_dA = -batteryAmps; //value is *10 (150 = 15.0) , invert the sign
|
||||||
|
|
||||||
datalayer.battery.status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
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.soh_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00%
|
datalayer_battery->status.max_charge_power_W = allowedChargePower * 10;
|
||||||
|
|
||||||
datalayer.battery.status.voltage_dV = batteryVoltage; //value is *10 (3700 = 370.0)
|
datalayer_battery->status.max_discharge_power_W = allowedDischargePower * 10;
|
||||||
|
|
||||||
datalayer.battery.status.current_dA = -batteryAmps; //value is *10 (150 = 15.0) , invert the sign
|
datalayer_battery->status.temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
||||||
|
|
||||||
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
datalayer_battery->status.temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
||||||
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
|
|
||||||
|
|
||||||
datalayer.battery.status.max_charge_power_W = allowedChargePower * 10;
|
datalayer_battery->status.cell_max_voltage_mV = CellVoltMax_mV;
|
||||||
|
|
||||||
datalayer.battery.status.max_discharge_power_W = allowedDischargePower * 10;
|
datalayer_battery->status.cell_min_voltage_mV = CellVoltMin_mV;
|
||||||
|
|
||||||
datalayer.battery.status.temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
|
||||||
|
|
||||||
datalayer.battery.status.temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
|
||||||
|
|
||||||
datalayer.battery.status.cell_max_voltage_mV = CellVoltMax_mV;
|
|
||||||
|
|
||||||
datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV;
|
|
||||||
|
|
||||||
if (waterleakageSensor == 0) {
|
if (waterleakageSensor == 0) {
|
||||||
set_event(EVENT_WATER_INGRESS, 0);
|
set_event(EVENT_WATER_INGRESS, 0);
|
||||||
|
@ -181,14 +41,14 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update webserver datalayer
|
// Update webserver datalayer
|
||||||
datalayer_extended.KiaHyundai64.total_cell_count = datalayer.battery.info.number_of_cells;
|
datalayer_battery_extended->total_cell_count = datalayer_battery->info.number_of_cells;
|
||||||
datalayer_extended.KiaHyundai64.battery_12V = leadAcidBatteryVoltage;
|
datalayer_battery_extended->battery_12V = leadAcidBatteryVoltage;
|
||||||
datalayer_extended.KiaHyundai64.waterleakageSensor = waterleakageSensor;
|
datalayer_battery_extended->waterleakageSensor = waterleakageSensor;
|
||||||
datalayer_extended.KiaHyundai64.temperature_water_inlet = temperature_water_inlet;
|
datalayer_battery_extended->temperature_water_inlet = temperature_water_inlet;
|
||||||
datalayer_extended.KiaHyundai64.powerRelayTemperature = powerRelayTemperature * 2;
|
datalayer_battery_extended->powerRelayTemperature = powerRelayTemperature * 2;
|
||||||
datalayer_extended.KiaHyundai64.batteryManagementMode = batteryManagementMode;
|
datalayer_battery_extended->batteryManagementMode = batteryManagementMode;
|
||||||
datalayer_extended.KiaHyundai64.BMS_ign = BMS_ign;
|
datalayer_battery_extended->BMS_ign = BMS_ign;
|
||||||
datalayer_extended.KiaHyundai64.batteryRelay = batteryRelay;
|
datalayer_battery_extended->batteryRelay = batteryRelay;
|
||||||
|
|
||||||
//Perform logging if configured to do so
|
//Perform logging if configured to do so
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
|
@ -205,7 +65,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
logging.print(" Amps | ");
|
logging.print(" Amps | ");
|
||||||
logging.print((uint16_t)batteryVoltage / 10.0, 1);
|
logging.print((uint16_t)batteryVoltage / 10.0, 1);
|
||||||
logging.print(" Volts | ");
|
logging.print(" Volts | ");
|
||||||
logging.print((int16_t)datalayer.battery.status.active_power_W);
|
logging.print((int16_t)datalayer_battery->status.active_power_W);
|
||||||
logging.println(" Watts");
|
logging.println(" Watts");
|
||||||
logging.print("Allowed Charge ");
|
logging.print("Allowed Charge ");
|
||||||
logging.print((uint16_t)allowedChargePower * 10);
|
logging.print((uint16_t)allowedChargePower * 10);
|
||||||
|
@ -251,32 +111,32 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_number_of_cells() {
|
void KiaHyundai64Battery::update_number_of_cells() {
|
||||||
//If we have cell values and number_of_cells not initialized yet
|
//If we have cell values and number_of_cells not initialized yet
|
||||||
if (cellvoltages_mv[0] > 0 && datalayer.battery.info.number_of_cells == 0) {
|
if (cellvoltages_mv[0] > 0 && datalayer_battery->info.number_of_cells == 0) {
|
||||||
// Check if we have 98S or 90S battery
|
// Check if we have 98S or 90S battery
|
||||||
if (datalayer.battery.status.cell_voltages_mV[97] > 0) {
|
if (datalayer_battery->status.cell_voltages_mV[97] > 0) {
|
||||||
datalayer.battery.info.number_of_cells = 98;
|
datalayer_battery->info.number_of_cells = 98;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV;
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_98S_DV;
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_98S_DV;
|
||||||
datalayer.battery.info.total_capacity_Wh = 64000;
|
datalayer_battery->info.total_capacity_Wh = 64000;
|
||||||
} else {
|
} else {
|
||||||
datalayer.battery.info.number_of_cells = 90;
|
datalayer_battery->info.number_of_cells = 90;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_90S_DV;
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_90S_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV;
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV;
|
||||||
datalayer.battery.info.total_capacity_Wh = 40000;
|
datalayer_battery->info.total_capacity_Wh = 40000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
switch (rx_frame.ID) {
|
switch (rx_frame.ID) {
|
||||||
case 0x4DE:
|
case 0x4DE:
|
||||||
startedUp = true;
|
startedUp = true;
|
||||||
break;
|
break;
|
||||||
case 0x542: //BMS SOC
|
case 0x542: //BMS SOC
|
||||||
startedUp = true;
|
startedUp = true;
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
SOC_Display = rx_frame.data.u8[0] * 5; //100% = 200 ( 200 * 5 = 1000 )
|
SOC_Display = rx_frame.data.u8[0] * 5; //100% = 200 ( 200 * 5 = 1000 )
|
||||||
break;
|
break;
|
||||||
case 0x594:
|
case 0x594:
|
||||||
|
@ -321,17 +181,17 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
poll_data_pid++;
|
poll_data_pid++;
|
||||||
if (poll_data_pid == 1) {
|
if (poll_data_pid == 1) {
|
||||||
transmit_can_frame(&KIA64_7E4_id1, can_config.battery);
|
transmit_can_frame(&KIA64_7E4_id1, can_interface);
|
||||||
} else if (poll_data_pid == 2) {
|
} else if (poll_data_pid == 2) {
|
||||||
transmit_can_frame(&KIA64_7E4_id2, can_config.battery);
|
transmit_can_frame(&KIA64_7E4_id2, can_interface);
|
||||||
} else if (poll_data_pid == 3) {
|
} else if (poll_data_pid == 3) {
|
||||||
transmit_can_frame(&KIA64_7E4_id3, can_config.battery);
|
transmit_can_frame(&KIA64_7E4_id3, can_interface);
|
||||||
} else if (poll_data_pid == 4) {
|
} else if (poll_data_pid == 4) {
|
||||||
transmit_can_frame(&KIA64_7E4_id4, can_config.battery);
|
transmit_can_frame(&KIA64_7E4_id4, can_interface);
|
||||||
} else if (poll_data_pid == 5) {
|
} else if (poll_data_pid == 5) {
|
||||||
transmit_can_frame(&KIA64_7E4_id5, can_config.battery);
|
transmit_can_frame(&KIA64_7E4_id5, can_interface);
|
||||||
} else if (poll_data_pid == 6) {
|
} else if (poll_data_pid == 6) {
|
||||||
transmit_can_frame(&KIA64_7E4_id6, can_config.battery);
|
transmit_can_frame(&KIA64_7E4_id6, can_interface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -340,7 +200,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
case 0x10: //"PID Header"
|
case 0x10: //"PID Header"
|
||||||
if (rx_frame.data.u8[4] == poll_data_pid) {
|
if (rx_frame.data.u8[4] == poll_data_pid) {
|
||||||
transmit_can_frame(&KIA64_7E4_ack,
|
transmit_can_frame(&KIA64_7E4_ack,
|
||||||
can_config.battery); //Send ack to BMS if the same frame is sent as polled
|
can_interface); //Send ack to BMS if the same frame is sent as polled
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x21: //First frame in PID group
|
case 0x21: //First frame in PID group
|
||||||
|
@ -511,7 +371,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Map all cell voltages to the global array
|
//Map all cell voltages to the global array
|
||||||
memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages_mv, 98 * sizeof(uint16_t));
|
memcpy(datalayer_battery->status.cell_voltages_mV, cellvoltages_mv, 98 * sizeof(uint16_t));
|
||||||
//Update number of cells
|
//Update number of cells
|
||||||
update_number_of_cells();
|
update_number_of_cells();
|
||||||
break;
|
break;
|
||||||
|
@ -533,398 +393,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) {
|
||||||
void update_values_battery2() { // Handle the values coming in from battery #2
|
|
||||||
/* Start with mapping all values */
|
|
||||||
datalayer.battery2.status.real_soc = (battery2_SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
|
||||||
|
|
||||||
datalayer.battery2.status.soh_pptt = (battery2_batterySOH * 10); //Increase decimals from 100.0% -> 100.00%
|
|
||||||
|
|
||||||
datalayer.battery2.status.voltage_dV = battery2_batteryVoltage; //value is *10 (3700 = 370.0)
|
|
||||||
|
|
||||||
datalayer.battery2.status.current_dA = -battery2_batteryAmps; //value is *10 (150 = 15.0) , invert the sign
|
|
||||||
|
|
||||||
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_charge_power_W = battery2_allowedChargePower * 10;
|
|
||||||
|
|
||||||
datalayer.battery2.status.max_discharge_power_W = battery2_allowedDischargePower * 10;
|
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_min_dC =
|
|
||||||
(int8_t)battery2_temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_max_dC =
|
|
||||||
(int8_t)battery2_temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
|
||||||
|
|
||||||
datalayer.battery2.status.cell_max_voltage_mV = battery2_CellVoltMax_mV;
|
|
||||||
|
|
||||||
datalayer.battery2.status.cell_min_voltage_mV = battery2_CellVoltMin_mV;
|
|
||||||
|
|
||||||
if (battery2_waterleakageSensor == 0) {
|
|
||||||
set_event(EVENT_WATER_INGRESS, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (battery2_leadAcidBatteryVoltage < 110) {
|
|
||||||
set_event(EVENT_12V_LOW, leadAcidBatteryVoltage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update webserver datalayer
|
|
||||||
datalayer_extended.KiaHyundai64.battery2_total_cell_count = datalayer.battery2.info.number_of_cells;
|
|
||||||
datalayer_extended.KiaHyundai64.battery2_battery_12V = battery2_leadAcidBatteryVoltage;
|
|
||||||
datalayer_extended.KiaHyundai64.battery2_waterleakageSensor = battery2_waterleakageSensor;
|
|
||||||
datalayer_extended.KiaHyundai64.battery2_temperature_water_inlet = battery2_temperature_water_inlet;
|
|
||||||
datalayer_extended.KiaHyundai64.battery2_powerRelayTemperature = battery2_powerRelayTemperature * 2;
|
|
||||||
datalayer_extended.KiaHyundai64.battery2_batteryManagementMode = battery2_batteryManagementMode;
|
|
||||||
datalayer_extended.KiaHyundai64.battery2_BMS_ign = battery2_BMS_ign;
|
|
||||||
datalayer_extended.KiaHyundai64.battery2_batteryRelay = battery2_batteryRelay;
|
|
||||||
|
|
||||||
//Perform logging if configured to do so
|
|
||||||
#ifdef DEBUG_LOG
|
|
||||||
logging.println(); //sepatator
|
|
||||||
logging.println("Values from battery: ");
|
|
||||||
logging.print("SOC BMS: ");
|
|
||||||
logging.print((uint16_t)battery2_SOC_BMS / 10.0, 1);
|
|
||||||
logging.print("% | SOC Display: ");
|
|
||||||
logging.print((uint16_t)battery2_SOC_Display / 10.0, 1);
|
|
||||||
logging.print("% | SOH ");
|
|
||||||
logging.print((uint16_t)battery2_batterySOH / 10.0, 1);
|
|
||||||
logging.println("%");
|
|
||||||
logging.print((int16_t)battery2_batteryAmps / 10.0, 1);
|
|
||||||
logging.print(" Amps | ");
|
|
||||||
logging.print((uint16_t)battery2_batteryVoltage / 10.0, 1);
|
|
||||||
logging.print(" Volts | ");
|
|
||||||
logging.print((int16_t)datalayer.battery2.status.active_power_W);
|
|
||||||
logging.println(" Watts");
|
|
||||||
logging.print("Allowed Charge ");
|
|
||||||
logging.print((uint16_t)battery2_allowedChargePower * 10);
|
|
||||||
logging.print(" W | Allowed Discharge ");
|
|
||||||
logging.print((uint16_t)battery2_allowedDischargePower * 10);
|
|
||||||
logging.println(" W");
|
|
||||||
logging.print("MaxCellVolt ");
|
|
||||||
logging.print(battery2_CellVoltMax_mV);
|
|
||||||
logging.print(" mV No ");
|
|
||||||
logging.print(battery2_CellVmaxNo);
|
|
||||||
logging.print(" | MinCellVolt ");
|
|
||||||
logging.print(battery2_CellVoltMin_mV);
|
|
||||||
logging.print(" mV No ");
|
|
||||||
logging.println(battery2_CellVminNo);
|
|
||||||
logging.print("TempHi ");
|
|
||||||
logging.print((int16_t)battery2_temperatureMax);
|
|
||||||
logging.print("°C TempLo ");
|
|
||||||
logging.print((int16_t)battery2_temperatureMin);
|
|
||||||
logging.print("°C WaterInlet ");
|
|
||||||
logging.print((int8_t)battery2_temperature_water_inlet);
|
|
||||||
logging.print("°C PowerRelay ");
|
|
||||||
logging.print((int8_t)battery2_powerRelayTemperature * 2);
|
|
||||||
logging.println("°C");
|
|
||||||
logging.print("Aux12volt: ");
|
|
||||||
logging.print((int16_t)battery2_leadAcidBatteryVoltage / 10.0, 1);
|
|
||||||
logging.println("V | ");
|
|
||||||
logging.print("BmsManagementMode ");
|
|
||||||
logging.print((uint8_t)battery2_batteryManagementMode, BIN);
|
|
||||||
if (bitRead((uint8_t)battery2_BMS_ign, 2) == 1) {
|
|
||||||
logging.print(" | BmsIgnition ON");
|
|
||||||
} else {
|
|
||||||
logging.print(" | BmsIgnition OFF");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bitRead((uint8_t)battery2_batteryRelay, 0) == 1) {
|
|
||||||
logging.print(" | PowerRelay ON");
|
|
||||||
} else {
|
|
||||||
logging.print(" | PowerRelay OFF");
|
|
||||||
}
|
|
||||||
logging.print(" | Inverter ");
|
|
||||||
logging.print(battery2_inverterVoltage);
|
|
||||||
logging.println(" Volts");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_number_of_cells_battery2() {
|
|
||||||
//If we have cell values and number_of_cells not initialized yet
|
|
||||||
if (battery2_cellvoltages_mv[0] > 0 && datalayer.battery2.info.number_of_cells == 0) {
|
|
||||||
// Check if we have 98S or 90S battery
|
|
||||||
if (datalayer.battery2.status.cell_voltages_mV[97] > 0) {
|
|
||||||
datalayer.battery2.info.number_of_cells = 98;
|
|
||||||
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV;
|
|
||||||
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_98S_DV;
|
|
||||||
datalayer.battery2.info.total_capacity_Wh = 64000;
|
|
||||||
} else {
|
|
||||||
datalayer.battery2.info.number_of_cells = 90;
|
|
||||||
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_90S_DV;
|
|
||||||
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV;
|
|
||||||
datalayer.battery2.info.total_capacity_Wh = 40000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
|
||||||
switch (rx_frame.ID) {
|
|
||||||
case 0x4DE:
|
|
||||||
battery2_startedUp = true;
|
|
||||||
break;
|
|
||||||
case 0x542: //BMS SOC
|
|
||||||
battery2_startedUp = true;
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
battery2_SOC_Display = rx_frame.data.u8[0] * 5; //100% = 200 ( 200 * 5 = 1000 )
|
|
||||||
break;
|
|
||||||
case 0x594:
|
|
||||||
battery2_startedUp = true;
|
|
||||||
battery2_allowedChargePower = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
|
|
||||||
battery2_allowedDischargePower = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
|
|
||||||
battery2_SOC_BMS = rx_frame.data.u8[5] * 5; //100% = 200 ( 200 * 5 = 1000 )
|
|
||||||
break;
|
|
||||||
case 0x595:
|
|
||||||
battery2_startedUp = true;
|
|
||||||
battery2_batteryVoltage = (rx_frame.data.u8[7] << 8) + rx_frame.data.u8[6];
|
|
||||||
battery2_batteryAmps = (rx_frame.data.u8[5] << 8) + rx_frame.data.u8[4];
|
|
||||||
if (battery2_counter_200 > 3) {
|
|
||||||
//KIA_HYUNDAI_524.data.u8[0] = (uint8_t)(battery2_batteryVoltage / 10);
|
|
||||||
//KIA_HYUNDAI_524.data.u8[1] = (uint8_t)((battery2_batteryVoltage / 10) >> 8);
|
|
||||||
} //VCU measured voltage sent back to bms (Not required since battery1 writes this)
|
|
||||||
break;
|
|
||||||
case 0x596:
|
|
||||||
battery2_startedUp = true;
|
|
||||||
battery2_leadAcidBatteryVoltage = rx_frame.data.u8[1]; //12v Battery Volts
|
|
||||||
battery2_temperatureMin = rx_frame.data.u8[6]; //Lowest temp in battery
|
|
||||||
battery2_temperatureMax = rx_frame.data.u8[7]; //Highest temp in battery
|
|
||||||
break;
|
|
||||||
case 0x598:
|
|
||||||
battery2_startedUp = true;
|
|
||||||
break;
|
|
||||||
case 0x5D5:
|
|
||||||
battery2_startedUp = true;
|
|
||||||
battery2_waterleakageSensor =
|
|
||||||
rx_frame.data.u8[3]; //Water sensor inside pack, value 164 is no water --> 0 is short
|
|
||||||
battery2_powerRelayTemperature = rx_frame.data.u8[7];
|
|
||||||
break;
|
|
||||||
case 0x5D8:
|
|
||||||
battery2_startedUp = true;
|
|
||||||
|
|
||||||
//PID data is polled after last message sent from battery every other time:
|
|
||||||
if (battery2_holdPidCounter == true) {
|
|
||||||
battery2_holdPidCounter = false;
|
|
||||||
} else {
|
|
||||||
battery2_holdPidCounter = true;
|
|
||||||
if (battery2_poll_data_pid >= 6) { //polling one of six PIDs at 100ms*2, resolution = 1200ms
|
|
||||||
battery2_poll_data_pid = 0;
|
|
||||||
}
|
|
||||||
battery2_poll_data_pid++;
|
|
||||||
if (battery2_poll_data_pid == 1) {
|
|
||||||
transmit_can_frame(&KIA64_7E4_id1, can_config.battery_double);
|
|
||||||
} else if (battery2_poll_data_pid == 2) {
|
|
||||||
transmit_can_frame(&KIA64_7E4_id2, can_config.battery_double);
|
|
||||||
} else if (battery2_poll_data_pid == 3) {
|
|
||||||
transmit_can_frame(&KIA64_7E4_id3, can_config.battery_double);
|
|
||||||
} else if (battery2_poll_data_pid == 4) {
|
|
||||||
transmit_can_frame(&KIA64_7E4_id4, can_config.battery_double);
|
|
||||||
} else if (battery2_poll_data_pid == 5) {
|
|
||||||
transmit_can_frame(&KIA64_7E4_id5, can_config.battery_double);
|
|
||||||
} else if (battery2_poll_data_pid == 6) {
|
|
||||||
transmit_can_frame(&KIA64_7E4_id6, can_config.battery_double);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x7EC: //Data From polled PID group, BigEndian
|
|
||||||
switch (rx_frame.data.u8[0]) {
|
|
||||||
case 0x10: //"PID Header"
|
|
||||||
if (rx_frame.data.u8[4] == battery2_poll_data_pid) {
|
|
||||||
transmit_can_frame(&KIA64_7E4_ack,
|
|
||||||
can_config.battery_double); //Send ack to BMS if the same frame is sent as polled
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x21: //First frame in PID group
|
|
||||||
if (battery2_poll_data_pid == 1) {
|
|
||||||
battery2_batteryRelay = rx_frame.data.u8[7];
|
|
||||||
} else if (battery2_poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[0] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[1] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[2] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[3] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[4] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[5] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[32] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[33] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[34] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[35] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[36] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[37] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[64] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[65] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[66] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[67] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[68] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[69] = (rx_frame.data.u8[7] * 20);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x22: //Second datarow in PID group
|
|
||||||
if (battery2_poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[6] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[7] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[8] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[9] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[10] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[11] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[12] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[38] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[39] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[40] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[41] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[42] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[43] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[44] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[70] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[71] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[72] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[73] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[74] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[75] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[76] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 6) {
|
|
||||||
battery2_batteryManagementMode = rx_frame.data.u8[5];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x23: //Third datarow in PID group
|
|
||||||
if (battery2_poll_data_pid == 1) {
|
|
||||||
battery2_temperature_water_inlet = rx_frame.data.u8[6];
|
|
||||||
battery2_CellVoltMax_mV = (rx_frame.data.u8[7] * 20); //(volts *50) *20 =mV
|
|
||||||
} else if (battery2_poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[13] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[14] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[15] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[16] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[17] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[18] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[19] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[45] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[46] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[47] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[48] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[49] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[50] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[51] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[77] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[78] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[79] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[80] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[81] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[82] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[83] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 5) {
|
|
||||||
battery2_heatertemp = rx_frame.data.u8[7];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x24: //Fourth datarow in PID group
|
|
||||||
if (battery2_poll_data_pid == 1) {
|
|
||||||
battery2_CellVmaxNo = rx_frame.data.u8[1];
|
|
||||||
battery2_CellVminNo = rx_frame.data.u8[3];
|
|
||||||
battery2_CellVoltMin_mV = (rx_frame.data.u8[2] * 20); //(volts *50) *20 =mV
|
|
||||||
} else if (battery2_poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[20] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[21] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[22] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[23] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[24] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[25] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[26] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[52] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[53] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[54] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[55] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[56] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[57] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[58] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[84] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[85] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[86] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[87] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[88] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[89] = (rx_frame.data.u8[6] * 20);
|
|
||||||
if (rx_frame.data.u8[7] > 4) { // Data only valid on 98S
|
|
||||||
battery2_cellvoltages_mv[90] = (rx_frame.data.u8[7] * 20); // Perform extra checks
|
|
||||||
}
|
|
||||||
} else if (battery2_poll_data_pid == 5) {
|
|
||||||
battery2_batterySOH = ((rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x25: //Fifth datarow in PID group
|
|
||||||
if (battery2_poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[27] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[28] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[29] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[30] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[31] = (rx_frame.data.u8[5] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[59] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[60] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[61] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[62] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[63] = (rx_frame.data.u8[5] * 20);
|
|
||||||
} else if (battery2_poll_data_pid == 4) { // Data only valid on 98S
|
|
||||||
if (rx_frame.data.u8[1] > 4) { // Perform extra checks
|
|
||||||
battery2_cellvoltages_mv[91] = (rx_frame.data.u8[1] * 20);
|
|
||||||
}
|
|
||||||
if (rx_frame.data.u8[2] > 4) { // Perform extra checks
|
|
||||||
battery2_cellvoltages_mv[92] = (rx_frame.data.u8[2] * 20);
|
|
||||||
}
|
|
||||||
if (rx_frame.data.u8[3] > 4) { // Perform extra checks
|
|
||||||
battery2_cellvoltages_mv[93] = (rx_frame.data.u8[3] * 20);
|
|
||||||
}
|
|
||||||
if (rx_frame.data.u8[4] > 4) { // Perform extra checks
|
|
||||||
battery2_cellvoltages_mv[94] = (rx_frame.data.u8[4] * 20);
|
|
||||||
}
|
|
||||||
if (rx_frame.data.u8[5] > 4) { // Perform extra checks
|
|
||||||
battery2_cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20);
|
|
||||||
}
|
|
||||||
} else if (battery2_poll_data_pid == 5) { // Data only valid on 98S
|
|
||||||
if (rx_frame.data.u8[4] > 4) { // Perform extra checks
|
|
||||||
battery2_cellvoltages_mv[96] = (rx_frame.data.u8[4] * 20);
|
|
||||||
}
|
|
||||||
if (rx_frame.data.u8[5] > 4) { // Perform extra checks
|
|
||||||
battery2_cellvoltages_mv[97] = (rx_frame.data.u8[5] * 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x26: //Sixth datarow in PID group
|
|
||||||
//We have read all cells, check that content is valid:
|
|
||||||
for (uint8_t i = 85; i < 97; ++i) {
|
|
||||||
if (battery2_cellvoltages_mv[i] < 300) { // Zero the value if it's below 300
|
|
||||||
battery2_cellvoltages_mv[i] = 0; // Some packs incorrectly report the last unpopulated cells as 20-60mV
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Map all cell voltages to the global array
|
|
||||||
memcpy(datalayer.battery2.status.cell_voltages_mV, battery2_cellvoltages_mv, 98 * sizeof(uint16_t));
|
|
||||||
//Update number of cells
|
|
||||||
update_number_of_cells_battery2();
|
|
||||||
break;
|
|
||||||
case 0x27: //Seventh datarow in PID group
|
|
||||||
if (battery2_poll_data_pid == 1) {
|
|
||||||
battery2_BMS_ign = rx_frame.data.u8[6];
|
|
||||||
battery2_inverterVoltageFrameHigh = rx_frame.data.u8[7];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x28: //Eighth datarow in PID group
|
|
||||||
if (battery2_poll_data_pid == 1) {
|
|
||||||
battery2_inverterVoltage = (battery2_inverterVoltageFrameHigh << 8) + rx_frame.data.u8[1];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
|
|
||||||
void transmit_can_battery(unsigned long currentMillis) {
|
|
||||||
|
|
||||||
if (!startedUp) {
|
if (!startedUp) {
|
||||||
return; // Don't send any CAN messages towards battery until it has started up
|
return; // Don't send any CAN messages towards battery until it has started up
|
||||||
|
@ -934,136 +403,77 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||||
previousMillis100 = currentMillis;
|
previousMillis100 = currentMillis;
|
||||||
|
|
||||||
transmit_can_frame(&KIA64_553, can_config.battery);
|
if (contactor_closing_allowed == nullptr || *contactor_closing_allowed) {
|
||||||
transmit_can_frame(&KIA64_57F, can_config.battery);
|
transmit_can_frame(&KIA64_553, can_interface);
|
||||||
transmit_can_frame(&KIA64_2A1, can_config.battery);
|
transmit_can_frame(&KIA64_57F, can_interface);
|
||||||
#ifdef DOUBLE_BATTERY
|
transmit_can_frame(&KIA64_2A1, can_interface);
|
||||||
if (battery2_startedUp && datalayer.system.status.battery2_allows_contactor_closing) {
|
|
||||||
transmit_can_frame(&KIA64_553, can_config.battery_double);
|
|
||||||
transmit_can_frame(&KIA64_57F, can_config.battery_double);
|
|
||||||
transmit_can_frame(&KIA64_2A1, can_config.battery_double);
|
|
||||||
}
|
}
|
||||||
#endif // DOUBLE_BATTERY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send 10ms CAN Message
|
// Send 10ms CAN Message
|
||||||
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
|
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
|
||||||
previousMillis10 = currentMillis;
|
previousMillis10 = currentMillis;
|
||||||
|
|
||||||
switch (counter_200) {
|
if (contactor_closing_allowed == nullptr || *contactor_closing_allowed) {
|
||||||
case 0:
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0x17;
|
|
||||||
++counter_200;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0x57;
|
|
||||||
++counter_200;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0x97;
|
|
||||||
++counter_200;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0xD7;
|
|
||||||
++counter_200;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
KIA_HYUNDAI_200.data.u8[3] = 0x10;
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0xFF;
|
|
||||||
++counter_200;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0x3B;
|
|
||||||
++counter_200;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0x7B;
|
|
||||||
++counter_200;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0xBB;
|
|
||||||
++counter_200;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
KIA_HYUNDAI_200.data.u8[5] = 0xFB;
|
|
||||||
counter_200 = 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
transmit_can_frame(&KIA_HYUNDAI_200, can_config.battery);
|
switch (counter_200) {
|
||||||
|
|
||||||
transmit_can_frame(&KIA_HYUNDAI_523, can_config.battery);
|
|
||||||
|
|
||||||
transmit_can_frame(&KIA_HYUNDAI_524, can_config.battery);
|
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
|
||||||
|
|
||||||
if (battery2_startedUp && datalayer.system.status.battery2_allows_contactor_closing) {
|
|
||||||
switch (counter_200_2) {
|
|
||||||
case 0:
|
case 0:
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0x17;
|
KIA_HYUNDAI_200.data.u8[5] = 0x17;
|
||||||
++counter_200_2;
|
++counter_200;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0x57;
|
KIA_HYUNDAI_200.data.u8[5] = 0x57;
|
||||||
++counter_200_2;
|
++counter_200;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0x97;
|
KIA_HYUNDAI_200.data.u8[5] = 0x97;
|
||||||
++counter_200_2;
|
++counter_200;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0xD7;
|
KIA_HYUNDAI_200.data.u8[5] = 0xD7;
|
||||||
++counter_200_2;
|
++counter_200;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
KIA_HYUNDAI_200_2.data.u8[3] = 0x10;
|
KIA_HYUNDAI_200.data.u8[3] = 0x10;
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0xFF;
|
KIA_HYUNDAI_200.data.u8[5] = 0xFF;
|
||||||
++counter_200_2;
|
++counter_200;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0x3B;
|
KIA_HYUNDAI_200.data.u8[5] = 0x3B;
|
||||||
++counter_200_2;
|
++counter_200;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0x7B;
|
KIA_HYUNDAI_200.data.u8[5] = 0x7B;
|
||||||
++counter_200_2;
|
++counter_200;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0xBB;
|
KIA_HYUNDAI_200.data.u8[5] = 0xBB;
|
||||||
++counter_200_2;
|
++counter_200;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
KIA_HYUNDAI_200_2.data.u8[5] = 0xFB;
|
KIA_HYUNDAI_200.data.u8[5] = 0xFB;
|
||||||
counter_200_2 = 5;
|
counter_200 = 5;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
transmit_can_frame(&KIA_HYUNDAI_200_2, can_config.battery_double);
|
transmit_can_frame(&KIA_HYUNDAI_200, can_interface);
|
||||||
|
transmit_can_frame(&KIA_HYUNDAI_523, can_interface);
|
||||||
transmit_can_frame(&KIA_HYUNDAI_523, can_config.battery_double);
|
transmit_can_frame(&KIA_HYUNDAI_524, can_interface);
|
||||||
|
|
||||||
transmit_can_frame(&KIA_HYUNDAI_524, can_config.battery_double);
|
|
||||||
}
|
}
|
||||||
#endif // DOUBLE_BATTERY
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_battery(void) { // Performs one time setup at startup
|
void KiaHyundai64Battery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai 64/40kWh battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai 64/40kWh battery", 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
if (allows_contactor_closing) {
|
||||||
#ifdef DOUBLE_BATTERY
|
*allows_contactor_closing = true;
|
||||||
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 = datalayer.battery.info.max_cell_voltage_deviation_mV;
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,19 +1,164 @@
|
||||||
#ifndef KIA_HYUNDAI_64_BATTERY_H
|
#ifndef KIA_HYUNDAI_64_BATTERY_H
|
||||||
#define KIA_HYUNDAI_64_BATTERY_H
|
#define KIA_HYUNDAI_64_BATTERY_H
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
#define MAX_PACK_VOLTAGE_98S_DV 4110 //5000 = 500.0V
|
#define SELECTED_BATTERY_CLASS KiaHyundai64Battery
|
||||||
#define MIN_PACK_VOLTAGE_98S_DV 2800
|
|
||||||
#define MAX_PACK_VOLTAGE_90S_DV 3870
|
|
||||||
#define MIN_PACK_VOLTAGE_90S_DV 2250
|
|
||||||
#define MAX_CELL_DEVIATION_MV 150
|
|
||||||
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_MV 2950 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
|
|
||||||
void setup_battery(void);
|
class KiaHyundai64Battery : public CanBattery {
|
||||||
void update_number_of_cells();
|
public:
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
// Use this constructor for the second battery.
|
||||||
|
KiaHyundai64Battery(DATALAYER_BATTERY_TYPE* datalayer_ptr, DATALAYER_INFO_KIAHYUNDAI64* extended_ptr,
|
||||||
|
bool* contactor_closing_allowed_ptr, int targetCan) {
|
||||||
|
datalayer_battery = datalayer_ptr;
|
||||||
|
contactor_closing_allowed = contactor_closing_allowed_ptr;
|
||||||
|
allows_contactor_closing = nullptr;
|
||||||
|
can_interface = targetCan;
|
||||||
|
datalayer_battery_extended = extended_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the default constructor to create the first or single battery.
|
||||||
|
KiaHyundai64Battery() {
|
||||||
|
datalayer_battery = &datalayer.battery;
|
||||||
|
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||||
|
contactor_closing_allowed = nullptr;
|
||||||
|
can_interface = can_config.battery;
|
||||||
|
datalayer_battery_extended = &datalayer_extended.KiaHyundai64;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_KIAHYUNDAI64* datalayer_battery_extended;
|
||||||
|
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
|
// If not null, this battery listens to this boolean to determine whether contactor closing is allowed
|
||||||
|
bool* contactor_closing_allowed;
|
||||||
|
|
||||||
|
int can_interface;
|
||||||
|
|
||||||
|
void update_number_of_cells();
|
||||||
|
|
||||||
|
static const int MAX_PACK_VOLTAGE_98S_DV = 4110; //5000 = 500.0V
|
||||||
|
static const int MIN_PACK_VOLTAGE_98S_DV = 2800;
|
||||||
|
static const int MAX_PACK_VOLTAGE_90S_DV = 3870;
|
||||||
|
static const int MIN_PACK_VOLTAGE_90S_DV = 2250;
|
||||||
|
static const int MAX_CELL_DEVIATION_MV = 150;
|
||||||
|
static const int MAX_CELL_VOLTAGE_MV = 4250; //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
static const int MIN_CELL_VOLTAGE_MV = 2950; //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
|
||||||
|
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||||
|
unsigned long previousMillis10 = 0; // will store last time a 10s CAN Message was send
|
||||||
|
|
||||||
|
uint16_t soc_calculated = 0;
|
||||||
|
uint16_t SOC_BMS = 0;
|
||||||
|
uint16_t SOC_Display = 0;
|
||||||
|
uint16_t batterySOH = 1000;
|
||||||
|
uint16_t CellVoltMax_mV = 3700;
|
||||||
|
uint16_t CellVoltMin_mV = 3700;
|
||||||
|
uint16_t allowedDischargePower = 0;
|
||||||
|
uint16_t allowedChargePower = 0;
|
||||||
|
uint16_t batteryVoltage = 0;
|
||||||
|
uint16_t inverterVoltageFrameHigh = 0;
|
||||||
|
uint16_t inverterVoltage = 0;
|
||||||
|
uint16_t cellvoltages_mv[98];
|
||||||
|
int16_t leadAcidBatteryVoltage = 120;
|
||||||
|
int16_t batteryAmps = 0;
|
||||||
|
int16_t temperatureMax = 0;
|
||||||
|
int16_t temperatureMin = 0;
|
||||||
|
int16_t poll_data_pid = 0;
|
||||||
|
bool holdPidCounter = false;
|
||||||
|
uint8_t CellVmaxNo = 0;
|
||||||
|
uint8_t CellVminNo = 0;
|
||||||
|
uint8_t batteryManagementMode = 0;
|
||||||
|
uint8_t BMS_ign = 0;
|
||||||
|
uint8_t batteryRelay = 0;
|
||||||
|
uint8_t waterleakageSensor = 164;
|
||||||
|
uint8_t counter_200 = 0;
|
||||||
|
int8_t temperature_water_inlet = 0;
|
||||||
|
int8_t heatertemp = 0;
|
||||||
|
int8_t powerRelayTemperature = 0;
|
||||||
|
bool startedUp = false;
|
||||||
|
|
||||||
|
CAN_frame KIA_HYUNDAI_200 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x200,
|
||||||
|
.data = {0x00, 0x80, 0xD8, 0x04, 0x00, 0x17, 0xD0, 0x00}};
|
||||||
|
CAN_frame KIA_HYUNDAI_523 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x523,
|
||||||
|
.data = {0x08, 0x38, 0x36, 0x36, 0x33, 0x34, 0x00, 0x01}};
|
||||||
|
CAN_frame KIA_HYUNDAI_524 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x524,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
//553 Needed frame 200ms
|
||||||
|
CAN_frame KIA64_553 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x553,
|
||||||
|
.data = {0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00}};
|
||||||
|
//57F Needed frame 100ms
|
||||||
|
CAN_frame KIA64_57F = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x57F,
|
||||||
|
.data = {0x80, 0x0A, 0x72, 0x00, 0x00, 0x00, 0x00, 0x72}};
|
||||||
|
//Needed frame 100ms
|
||||||
|
CAN_frame KIA64_2A1 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x2A1,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame KIA64_7E4_id1 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4,
|
||||||
|
.data = {0x03, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 01
|
||||||
|
CAN_frame KIA64_7E4_id2 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4,
|
||||||
|
.data = {0x03, 0x22, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 02
|
||||||
|
CAN_frame KIA64_7E4_id3 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4,
|
||||||
|
.data = {0x03, 0x22, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 03
|
||||||
|
CAN_frame KIA64_7E4_id4 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4,
|
||||||
|
.data = {0x03, 0x22, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 04
|
||||||
|
CAN_frame KIA64_7E4_id5 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4,
|
||||||
|
.data = {0x03, 0x22, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 05
|
||||||
|
CAN_frame KIA64_7E4_id6 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4,
|
||||||
|
.data = {0x03, 0x22, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 06
|
||||||
|
CAN_frame KIA64_7E4_ack = {
|
||||||
|
.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4,
|
||||||
|
.data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Ack frame, correct PID is returned
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -74,7 +74,7 @@ void NissanLeafBattery::
|
||||||
datalayer_battery->status.max_charge_power_W = (battery_Charge_Power_Limit * 1000); //kW to W
|
datalayer_battery->status.max_charge_power_W = (battery_Charge_Power_Limit * 1000); //kW to W
|
||||||
|
|
||||||
//Allow contactors to close
|
//Allow contactors to close
|
||||||
if (battery_can_alive) {
|
if (battery_can_alive && allows_contactor_closing) {
|
||||||
*allows_contactor_closing = true;
|
*allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,9 @@
|
||||||
class NissanLeafBattery : public CanBattery {
|
class NissanLeafBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
// Use this constructor for the second battery.
|
// Use this constructor for the second battery.
|
||||||
NissanLeafBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* allows_contactor_closing_ptr,
|
NissanLeafBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, DATALAYER_INFO_NISSAN_LEAF* extended, int targetCan) {
|
||||||
DATALAYER_INFO_NISSAN_LEAF* extended, int targetCan) {
|
|
||||||
datalayer_battery = datalayer_ptr;
|
datalayer_battery = datalayer_ptr;
|
||||||
allows_contactor_closing = allows_contactor_closing_ptr;
|
allows_contactor_closing = nullptr;
|
||||||
datalayer_nissan = extended;
|
datalayer_nissan = extended;
|
||||||
can_interface = targetCan;
|
can_interface = targetCan;
|
||||||
|
|
||||||
|
@ -48,6 +47,8 @@ class NissanLeafBattery : public CanBattery {
|
||||||
|
|
||||||
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||||
DATALAYER_INFO_NISSAN_LEAF* datalayer_nissan;
|
DATALAYER_INFO_NISSAN_LEAF* datalayer_nissan;
|
||||||
|
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
bool* allows_contactor_closing;
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
int can_interface;
|
int can_interface;
|
||||||
|
|
|
@ -1,89 +1,44 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#ifdef PYLON_BATTERY
|
#ifdef PYLON_BATTERY
|
||||||
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "PYLON-BATTERY.h"
|
#include "PYLON-BATTERY.h"
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
void PylonBattery::update_values() {
|
||||||
static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent
|
|
||||||
|
|
||||||
//Actual content messages
|
datalayer_battery->status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00
|
||||||
CAN_frame PYLON_3010 = {.FD = false,
|
|
||||||
.ext_ID = true,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x3010,
|
|
||||||
.data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
CAN_frame PYLON_8200 = {.FD = false,
|
|
||||||
.ext_ID = true,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x8200,
|
|
||||||
.data = {0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
CAN_frame PYLON_8210 = {.FD = false,
|
|
||||||
.ext_ID = true,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x8210,
|
|
||||||
.data = {0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
CAN_frame PYLON_4200 = {.FD = false,
|
|
||||||
.ext_ID = true,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x4200,
|
|
||||||
.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
|
|
||||||
static int16_t celltemperature_max_dC = 0;
|
datalayer_battery->status.soh_pptt = (SOH * 100); //Increase decimals from 100% -> 100.00%
|
||||||
static int16_t celltemperature_min_dC = 0;
|
|
||||||
static int16_t current_dA = 0;
|
|
||||||
static uint16_t voltage_dV = 0;
|
|
||||||
static uint16_t cellvoltage_max_mV = 3700;
|
|
||||||
static uint16_t cellvoltage_min_mV = 3700;
|
|
||||||
static uint16_t charge_cutoff_voltage = 0;
|
|
||||||
static uint16_t discharge_cutoff_voltage = 0;
|
|
||||||
static int16_t max_charge_current = 0;
|
|
||||||
static int16_t max_discharge_current = 0;
|
|
||||||
static uint8_t ensemble_info_ack = 0;
|
|
||||||
static uint8_t battery_module_quantity = 0;
|
|
||||||
static uint8_t battery_modules_in_series = 0;
|
|
||||||
static uint8_t cell_quantity_in_module = 0;
|
|
||||||
static uint8_t voltage_level = 0;
|
|
||||||
static uint8_t ah_number = 0;
|
|
||||||
static uint8_t SOC = 50;
|
|
||||||
static uint8_t SOH = 100;
|
|
||||||
static uint8_t charge_forbidden = 0;
|
|
||||||
static uint8_t discharge_forbidden = 0;
|
|
||||||
|
|
||||||
void update_values_battery() {
|
datalayer_battery->status.voltage_dV = voltage_dV; //value is *10 (3700 = 370.0)
|
||||||
|
|
||||||
datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00
|
datalayer_battery->status.current_dA = current_dA; //value is *10 (150 = 15.0) , invert the sign
|
||||||
|
|
||||||
datalayer.battery.status.soh_pptt = (SOH * 100); //Increase decimals from 100% -> 100.00%
|
datalayer_battery->status.max_charge_power_W = (max_charge_current * (voltage_dV / 10));
|
||||||
|
|
||||||
datalayer.battery.status.voltage_dV = voltage_dV; //value is *10 (3700 = 370.0)
|
datalayer_battery->status.max_discharge_power_W = (-max_discharge_current * (voltage_dV / 10));
|
||||||
|
|
||||||
datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) , invert the sign
|
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_charge_power_W = (max_charge_current * (voltage_dV / 10));
|
datalayer_battery->status.cell_max_voltage_mV = cellvoltage_max_mV;
|
||||||
|
datalayer_battery->status.cell_voltages_mV[0] = cellvoltage_max_mV;
|
||||||
|
|
||||||
datalayer.battery.status.max_discharge_power_W = (-max_discharge_current * (voltage_dV / 10));
|
datalayer_battery->status.cell_min_voltage_mV = cellvoltage_min_mV;
|
||||||
|
datalayer_battery->status.cell_voltages_mV[1] = cellvoltage_min_mV;
|
||||||
|
|
||||||
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
datalayer_battery->status.temperature_min_dC = celltemperature_min_dC;
|
||||||
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
|
|
||||||
|
|
||||||
datalayer.battery.status.cell_max_voltage_mV = cellvoltage_max_mV;
|
datalayer_battery->status.temperature_max_dC = celltemperature_max_dC;
|
||||||
datalayer.battery.status.cell_voltages_mV[0] = cellvoltage_max_mV;
|
|
||||||
|
|
||||||
datalayer.battery.status.cell_min_voltage_mV = cellvoltage_min_mV;
|
datalayer_battery->info.max_design_voltage_dV = charge_cutoff_voltage;
|
||||||
datalayer.battery.status.cell_voltages_mV[1] = cellvoltage_min_mV;
|
|
||||||
|
|
||||||
datalayer.battery.status.temperature_min_dC = celltemperature_min_dC;
|
datalayer_battery->info.min_design_voltage_dV = discharge_cutoff_voltage;
|
||||||
|
|
||||||
datalayer.battery.status.temperature_max_dC = celltemperature_max_dC;
|
|
||||||
|
|
||||||
datalayer.battery.info.max_design_voltage_dV = charge_cutoff_voltage;
|
|
||||||
|
|
||||||
datalayer.battery.info.min_design_voltage_dV = discharge_cutoff_voltage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
void PylonBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
switch (rx_frame.ID) {
|
switch (rx_frame.ID) {
|
||||||
case 0x7310:
|
case 0x7310:
|
||||||
case 0x7311:
|
case 0x7311:
|
||||||
|
@ -158,7 +113,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void transmit_can_battery(unsigned long currentMillis) {
|
void PylonBattery::transmit_can(unsigned long currentMillis) {
|
||||||
// Send 1s CAN Message
|
// Send 1s CAN Message
|
||||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||||
previousMillis1000 = currentMillis;
|
previousMillis1000 = currentMillis;
|
||||||
|
@ -168,170 +123,26 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
transmit_can_frame(&PYLON_8200, can_config.battery); // Control device quit sleep status
|
transmit_can_frame(&PYLON_8200, can_config.battery); // Control device quit sleep status
|
||||||
transmit_can_frame(&PYLON_8210, can_config.battery); // Charge command
|
transmit_can_frame(&PYLON_8210, can_config.battery); // Charge command
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
|
||||||
transmit_can_frame(&PYLON_3010, can_config.battery_double); // Heartbeat
|
|
||||||
transmit_can_frame(&PYLON_4200, can_config.battery_double); // Ensemble OR System equipment info, depends on frame0
|
|
||||||
transmit_can_frame(&PYLON_8200, can_config.battery_double); // Control device quit sleep status
|
|
||||||
transmit_can_frame(&PYLON_8210, can_config.battery_double); // Charge command
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
|
|
||||||
if (ensemble_info_ack) {
|
if (ensemble_info_ack) {
|
||||||
PYLON_4200.data.u8[0] = 0x00; //Request system equipment info
|
PYLON_4200.data.u8[0] = 0x00; //Request system equipment info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
void PylonBattery::setup(void) { // Performs one time setup at startup
|
||||||
|
|
||||||
static int16_t battery2_celltemperature_max_dC = 0;
|
|
||||||
static int16_t battery2_celltemperature_min_dC = 0;
|
|
||||||
static int16_t battery2_current_dA = 0;
|
|
||||||
static uint16_t battery2_voltage_dV = 0;
|
|
||||||
static uint16_t battery2_cellvoltage_max_mV = 3700;
|
|
||||||
static uint16_t battery2_cellvoltage_min_mV = 3700;
|
|
||||||
static uint16_t battery2_charge_cutoff_voltage = 0;
|
|
||||||
static uint16_t battery2_discharge_cutoff_voltage = 0;
|
|
||||||
static int16_t battery2_max_charge_current = 0;
|
|
||||||
static int16_t battery2_max_discharge_current = 0;
|
|
||||||
static uint8_t battery2_ensemble_info_ack = 0;
|
|
||||||
static uint8_t battery2_module_quantity = 0;
|
|
||||||
static uint8_t battery2_modules_in_series = 0;
|
|
||||||
static uint8_t battery2_cell_quantity_in_module = 0;
|
|
||||||
static uint8_t battery2_voltage_level = 0;
|
|
||||||
static uint8_t battery2_ah_number = 0;
|
|
||||||
static uint8_t battery2_SOC = 0;
|
|
||||||
static uint8_t battery2_SOH = 0;
|
|
||||||
static uint8_t battery2_charge_forbidden = 0;
|
|
||||||
static uint8_t battery2_discharge_forbidden = 0;
|
|
||||||
|
|
||||||
void update_values_battery2() {
|
|
||||||
|
|
||||||
datalayer.battery2.status.real_soc = (battery2_SOC * 100); //increase SOC range from 0-100 -> 100.00
|
|
||||||
|
|
||||||
datalayer.battery2.status.soh_pptt = (battery2_SOH * 100); //Increase decimals from 100% -> 100.00%
|
|
||||||
|
|
||||||
datalayer.battery2.status.voltage_dV = battery2_voltage_dV; //value is *10 (3700 = 370.0)
|
|
||||||
|
|
||||||
datalayer.battery2.status.current_dA = battery2_current_dA; //value is *10 (150 = 15.0) , invert the sign
|
|
||||||
|
|
||||||
datalayer.battery2.status.max_charge_power_W = (battery2_max_charge_current * (battery2_voltage_dV / 10));
|
|
||||||
|
|
||||||
datalayer.battery2.status.max_discharge_power_W = (-battery2_max_discharge_current * (battery2_voltage_dV / 10));
|
|
||||||
|
|
||||||
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.cell_max_voltage_mV = battery2_cellvoltage_max_mV;
|
|
||||||
datalayer.battery2.status.cell_voltages_mV[0] = battery2_cellvoltage_max_mV;
|
|
||||||
|
|
||||||
datalayer.battery2.status.cell_min_voltage_mV = battery2_cellvoltage_min_mV;
|
|
||||||
datalayer.battery2.status.cell_voltages_mV[1] = battery2_cellvoltage_min_mV;
|
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_min_dC = battery2_celltemperature_min_dC;
|
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_max_dC = battery2_celltemperature_max_dC;
|
|
||||||
|
|
||||||
datalayer.battery2.info.max_design_voltage_dV = battery2_charge_cutoff_voltage;
|
|
||||||
|
|
||||||
datalayer.battery2.info.min_design_voltage_dV = battery2_discharge_cutoff_voltage;
|
|
||||||
|
|
||||||
datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells;
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
switch (rx_frame.ID) {
|
|
||||||
case 0x7310:
|
|
||||||
case 0x7311:
|
|
||||||
battery2_ensemble_info_ack = true;
|
|
||||||
// This message contains software/hardware version info. No interest to us
|
|
||||||
break;
|
|
||||||
case 0x7320:
|
|
||||||
case 0x7321:
|
|
||||||
battery2_ensemble_info_ack = true;
|
|
||||||
battery2_module_quantity = rx_frame.data.u8[0];
|
|
||||||
battery2_modules_in_series = rx_frame.data.u8[2];
|
|
||||||
battery2_cell_quantity_in_module = rx_frame.data.u8[3];
|
|
||||||
battery2_voltage_level = rx_frame.data.u8[4];
|
|
||||||
battery2_ah_number = rx_frame.data.u8[6];
|
|
||||||
break;
|
|
||||||
case 0x4210:
|
|
||||||
case 0x4211:
|
|
||||||
battery2_voltage_dV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
|
|
||||||
battery2_current_dA = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) - 30000;
|
|
||||||
battery2_SOC = rx_frame.data.u8[6];
|
|
||||||
battery2_SOH = rx_frame.data.u8[7];
|
|
||||||
break;
|
|
||||||
case 0x4220:
|
|
||||||
case 0x4221:
|
|
||||||
battery2_charge_cutoff_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
|
|
||||||
battery2_discharge_cutoff_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
|
|
||||||
battery2_max_charge_current = (((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * 0.1) - 3000;
|
|
||||||
battery2_max_discharge_current = (((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) * 0.1) - 3000;
|
|
||||||
break;
|
|
||||||
case 0x4230:
|
|
||||||
case 0x4231:
|
|
||||||
battery2_cellvoltage_max_mV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
|
|
||||||
battery2_cellvoltage_min_mV = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
|
|
||||||
break;
|
|
||||||
case 0x4240:
|
|
||||||
case 0x4241:
|
|
||||||
battery2_celltemperature_max_dC = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) - 1000;
|
|
||||||
battery2_celltemperature_min_dC = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) - 1000;
|
|
||||||
break;
|
|
||||||
case 0x4250:
|
|
||||||
case 0x4251:
|
|
||||||
//Byte0 Basic Status
|
|
||||||
//Byte1-2 Cycle Period
|
|
||||||
//Byte3 Error
|
|
||||||
//Byte4-5 Alarm
|
|
||||||
//Byte6-7 Protection
|
|
||||||
break;
|
|
||||||
case 0x4260:
|
|
||||||
case 0x4261:
|
|
||||||
//Byte0-1 Module Max Voltage
|
|
||||||
//Byte2-3 Module Min Voltage
|
|
||||||
//Byte4-5 Module Max. Voltage Number
|
|
||||||
//Byte6-7 Module Min. Voltage Number
|
|
||||||
break;
|
|
||||||
case 0x4270:
|
|
||||||
case 0x4271:
|
|
||||||
//Byte0-1 Module Max. Temperature
|
|
||||||
//Byte2-3 Module Min. Temperature
|
|
||||||
//Byte4-5 Module Max. Temperature Number
|
|
||||||
//Byte6-7 Module Min. Temperature Number
|
|
||||||
break;
|
|
||||||
case 0x4280:
|
|
||||||
case 0x4281:
|
|
||||||
battery2_charge_forbidden = rx_frame.data.u8[0];
|
|
||||||
battery2_discharge_forbidden = rx_frame.data.u8[1];
|
|
||||||
break;
|
|
||||||
case 0x4290:
|
|
||||||
case 0x4291:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
|
|
||||||
void setup_battery(void) { // Performs one time setup at startup
|
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Pylon compatible battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, "Pylon compatible battery", 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 2;
|
datalayer_battery->info.number_of_cells = 2;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
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.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
|
||||||
#ifdef DOUBLE_BATTERY
|
datalayer.battery2.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
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;
|
if (allows_contactor_closing) {
|
||||||
datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV;
|
*allows_contactor_closing = true;
|
||||||
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 = datalayer.battery.info.max_cell_voltage_deviation_mV;
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,18 +1,99 @@
|
||||||
#ifndef PYLON_BATTERY_H
|
#ifndef PYLON_BATTERY_H
|
||||||
#define PYLON_BATTERY_H
|
#define PYLON_BATTERY_H
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define SELECTED_BATTERY_CLASS PylonBattery
|
||||||
|
|
||||||
/* Change the following to suit your battery */
|
class PylonBattery : public CanBattery {
|
||||||
#define MAX_PACK_VOLTAGE_DV 5000 //5000 = 500.0V
|
public:
|
||||||
#define MIN_PACK_VOLTAGE_DV 1500
|
// Use this constructor for the second battery.
|
||||||
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
PylonBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* contactor_closing_allowed_ptr, int targetCan) {
|
||||||
#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
|
datalayer_battery = datalayer_ptr;
|
||||||
#define MAX_CELL_DEVIATION_MV 150
|
contactor_closing_allowed = contactor_closing_allowed_ptr;
|
||||||
|
allows_contactor_closing = nullptr;
|
||||||
|
can_interface = targetCan;
|
||||||
|
}
|
||||||
|
|
||||||
void setup_battery(void);
|
// Use the default constructor to create the first or single battery.
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
PylonBattery() {
|
||||||
|
datalayer_battery = &datalayer.battery;
|
||||||
|
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||||
|
contactor_closing_allowed = nullptr;
|
||||||
|
can_interface = can_config.battery;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
/* Change the following to suit your battery */
|
||||||
|
static const int MAX_PACK_VOLTAGE_DV = 5000; //5000 = 500.0V
|
||||||
|
static const int MIN_PACK_VOLTAGE_DV = 1500;
|
||||||
|
static const int MAX_CELL_VOLTAGE_MV = 4250; //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
static const int MAX_CELL_DEVIATION_MV = 150;
|
||||||
|
|
||||||
|
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||||
|
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
|
// If not null, this battery listens to this boolean to determine whether contactor closing is allowed
|
||||||
|
bool* contactor_closing_allowed;
|
||||||
|
|
||||||
|
int can_interface;
|
||||||
|
|
||||||
|
unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent
|
||||||
|
|
||||||
|
//Actual content messages
|
||||||
|
CAN_frame PYLON_3010 = {.FD = false,
|
||||||
|
.ext_ID = true,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x3010,
|
||||||
|
.data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame PYLON_8200 = {.FD = false,
|
||||||
|
.ext_ID = true,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x8200,
|
||||||
|
.data = {0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame PYLON_8210 = {.FD = false,
|
||||||
|
.ext_ID = true,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x8210,
|
||||||
|
.data = {0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame PYLON_4200 = {.FD = false,
|
||||||
|
.ext_ID = true,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x4200,
|
||||||
|
.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
|
||||||
|
int16_t celltemperature_max_dC = 0;
|
||||||
|
int16_t celltemperature_min_dC = 0;
|
||||||
|
int16_t current_dA = 0;
|
||||||
|
uint16_t voltage_dV = 0;
|
||||||
|
uint16_t cellvoltage_max_mV = 3700;
|
||||||
|
uint16_t cellvoltage_min_mV = 3700;
|
||||||
|
uint16_t charge_cutoff_voltage = 0;
|
||||||
|
uint16_t discharge_cutoff_voltage = 0;
|
||||||
|
int16_t max_charge_current = 0;
|
||||||
|
int16_t max_discharge_current = 0;
|
||||||
|
uint8_t ensemble_info_ack = 0;
|
||||||
|
uint8_t battery_module_quantity = 0;
|
||||||
|
uint8_t battery_modules_in_series = 0;
|
||||||
|
uint8_t cell_quantity_in_module = 0;
|
||||||
|
uint8_t voltage_level = 0;
|
||||||
|
uint8_t ah_number = 0;
|
||||||
|
uint8_t SOC = 50;
|
||||||
|
uint8_t SOH = 100;
|
||||||
|
uint8_t charge_forbidden = 0;
|
||||||
|
uint8_t discharge_forbidden = 0;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#ifdef SANTA_FE_PHEV_BATTERY
|
#ifdef SANTA_FE_PHEV_BATTERY
|
||||||
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "SANTA-FE-PHEV-BATTERY.h"
|
#include "SANTA-FE-PHEV-BATTERY.h"
|
||||||
|
@ -13,113 +14,58 @@ TODO: Tweak temperature values once more data is known about them
|
||||||
TODO: Check if CRC function works like it should. This enables checking for corrupt messages
|
TODO: Check if CRC function works like it should. This enables checking for corrupt messages
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
static uint8_t CalculateCRC8(CAN_frame rx_frame) {
|
||||||
static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
|
int crc = 0;
|
||||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
|
||||||
static unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was send
|
|
||||||
static uint8_t poll_data_pid = 0;
|
|
||||||
static uint8_t counter_200 = 0;
|
|
||||||
static uint8_t checksum_200 = 0;
|
|
||||||
|
|
||||||
static uint16_t SOC_Display = 0;
|
for (uint8_t framepos = 0; framepos < 8; framepos++) {
|
||||||
static uint16_t batterySOH = 100;
|
crc ^= rx_frame.data.u8[framepos];
|
||||||
static uint16_t CellVoltMax_mV = 3700;
|
|
||||||
static uint16_t CellVoltMin_mV = 3700;
|
|
||||||
static uint8_t CellVmaxNo = 0;
|
|
||||||
static uint8_t CellVminNo = 0;
|
|
||||||
static uint16_t allowedDischargePower = 0;
|
|
||||||
static uint16_t allowedChargePower = 0;
|
|
||||||
static uint16_t batteryVoltage = 0;
|
|
||||||
static int16_t leadAcidBatteryVoltage = 120;
|
|
||||||
static int8_t temperatureMax = 0;
|
|
||||||
static int8_t temperatureMin = 0;
|
|
||||||
static int16_t batteryAmps = 0;
|
|
||||||
static uint8_t StatusBattery = 0;
|
|
||||||
static uint16_t cellvoltages_mv[96];
|
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
for (uint8_t j = 0; j < 8; j++) {
|
||||||
static uint16_t battery2_SOC_Display = 0;
|
if ((crc & 0x80) != 0) {
|
||||||
static uint16_t battery2_SOH = 100;
|
crc = (crc << 1) ^ 0x1;
|
||||||
static uint16_t battery2_CellVoltMax_mV = 3700;
|
} else {
|
||||||
static uint16_t battery2_CellVoltMin_mV = 3700;
|
crc <<= 1;
|
||||||
static uint8_t battery2_CellVmaxNo = 0;
|
}
|
||||||
static uint8_t battery2_CellVminNo = 0;
|
}
|
||||||
static uint16_t battery2_allowedDischargePower = 0;
|
}
|
||||||
static uint16_t battery2_allowedChargePower = 0;
|
return (uint8_t)crc;
|
||||||
static uint16_t battery2_batteryVoltage = 0;
|
}
|
||||||
static int16_t battery2_leadAcidBatteryVoltage = 120;
|
|
||||||
static int8_t battery2_temperatureMax = 0;
|
|
||||||
static int8_t battery2_temperatureMin = 0;
|
|
||||||
static int16_t battery2_batteryAmps = 0;
|
|
||||||
static uint8_t battery2_StatusBattery = 0;
|
|
||||||
static uint16_t battery2_cellvoltages_mv[96];
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
|
|
||||||
CAN_frame SANTAFE_200 = {.FD = false,
|
void SantaFePhevBattery::
|
||||||
.ext_ID = false,
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x200,
|
|
||||||
.data = {0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00}};
|
|
||||||
CAN_frame SANTAFE_2A1 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x2A1,
|
|
||||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x02}};
|
|
||||||
CAN_frame SANTAFE_2F0 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x2F0,
|
|
||||||
.data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}};
|
|
||||||
CAN_frame SANTAFE_523 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x523,
|
|
||||||
.data = {0x60, 0x00, 0x60, 0, 0, 0, 0, 0}};
|
|
||||||
CAN_frame SANTAFE_7E4_poll = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4, //Polling frame, 0x22 01 0X
|
|
||||||
.data = {0x03, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
CAN_frame SANTAFE_7E4_ack = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x7E4, //Ack frame, correct PID is returned. Flow control message
|
|
||||||
.data = {0x30, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
|
|
||||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
datalayer_battery->status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
||||||
|
|
||||||
datalayer.battery.status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
datalayer_battery->status.soh_pptt = (batterySOH * 100); //Increase decimals from 100% -> 100.00%
|
||||||
|
|
||||||
datalayer.battery.status.soh_pptt = (batterySOH * 100); //Increase decimals from 100% -> 100.00%
|
datalayer_battery->status.voltage_dV = batteryVoltage;
|
||||||
|
|
||||||
datalayer.battery.status.voltage_dV = batteryVoltage;
|
datalayer_battery->status.current_dA = -batteryAmps;
|
||||||
|
|
||||||
datalayer.battery.status.current_dA = -batteryAmps;
|
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>(
|
datalayer_battery->status.max_discharge_power_W = allowedDischargePower * 10;
|
||||||
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
|
|
||||||
|
|
||||||
datalayer.battery.status.max_discharge_power_W = allowedDischargePower * 10;
|
datalayer_battery->status.max_charge_power_W = allowedChargePower * 10;
|
||||||
|
|
||||||
datalayer.battery.status.max_charge_power_W = allowedChargePower * 10;
|
datalayer_battery->status.cell_max_voltage_mV = CellVoltMax_mV;
|
||||||
|
|
||||||
datalayer.battery.status.cell_max_voltage_mV = CellVoltMax_mV;
|
datalayer_battery->status.cell_min_voltage_mV = CellVoltMin_mV;
|
||||||
|
|
||||||
datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV;
|
datalayer_battery->status.temperature_min_dC = temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
||||||
|
|
||||||
datalayer.battery.status.temperature_min_dC = temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
datalayer_battery->status.temperature_max_dC = temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
||||||
|
|
||||||
datalayer.battery.status.temperature_max_dC = temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
|
||||||
|
|
||||||
if (leadAcidBatteryVoltage < 110) {
|
if (leadAcidBatteryVoltage < 110) {
|
||||||
set_event(EVENT_12V_LOW, leadAcidBatteryVoltage);
|
set_event(EVENT_12V_LOW, leadAcidBatteryVoltage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
void SantaFePhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
switch (rx_frame.ID) {
|
switch (rx_frame.ID) {
|
||||||
case 0x1FF:
|
case 0x1FF:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
StatusBattery = (rx_frame.data.u8[0] & 0x0F);
|
StatusBattery = (rx_frame.data.u8[0] & 0x0F);
|
||||||
break;
|
break;
|
||||||
case 0x4D5:
|
case 0x4D5:
|
||||||
|
@ -127,16 +73,16 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
case 0x4DD:
|
case 0x4DD:
|
||||||
break;
|
break;
|
||||||
case 0x4DE:
|
case 0x4DE:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
break;
|
break;
|
||||||
case 0x4E0:
|
case 0x4E0:
|
||||||
break;
|
break;
|
||||||
case 0x542:
|
case 0x542:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
SOC_Display = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]) / 2;
|
SOC_Display = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]) / 2;
|
||||||
break;
|
break;
|
||||||
case 0x588:
|
case 0x588:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
batteryVoltage = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]);
|
batteryVoltage = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]);
|
||||||
break;
|
break;
|
||||||
case 0x597:
|
case 0x597:
|
||||||
|
@ -146,7 +92,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
case 0x5A7:
|
case 0x5A7:
|
||||||
break;
|
break;
|
||||||
case 0x5AD:
|
case 0x5AD:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
batteryAmps = (rx_frame.data.u8[3] << 8) + rx_frame.data.u8[2];
|
batteryAmps = (rx_frame.data.u8[3] << 8) + rx_frame.data.u8[2];
|
||||||
break;
|
break;
|
||||||
case 0x5AE:
|
case 0x5AE:
|
||||||
|
@ -154,25 +100,25 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
case 0x5F1:
|
case 0x5F1:
|
||||||
break;
|
break;
|
||||||
case 0x620:
|
case 0x620:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
leadAcidBatteryVoltage = rx_frame.data.u8[1];
|
leadAcidBatteryVoltage = rx_frame.data.u8[1];
|
||||||
temperatureMin = rx_frame.data.u8[6]; //Lowest temp in battery
|
temperatureMin = rx_frame.data.u8[6]; //Lowest temp in battery
|
||||||
temperatureMax = rx_frame.data.u8[7]; //Highest temp in battery
|
temperatureMax = rx_frame.data.u8[7]; //Highest temp in battery
|
||||||
break;
|
break;
|
||||||
case 0x670:
|
case 0x670:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
allowedChargePower = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
|
allowedChargePower = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
|
||||||
allowedDischargePower = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
|
allowedDischargePower = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
|
||||||
break;
|
break;
|
||||||
case 0x671:
|
case 0x671:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
break;
|
break;
|
||||||
case 0x7EC: //Data From polled PID group, BigEndian
|
case 0x7EC: //Data From polled PID group, BigEndian
|
||||||
switch (rx_frame.data.u8[0]) {
|
switch (rx_frame.data.u8[0]) {
|
||||||
case 0x10: //"PID Header"
|
case 0x10: //"PID Header"
|
||||||
if (rx_frame.data.u8[4] == poll_data_pid) {
|
if (rx_frame.data.u8[4] == poll_data_pid) {
|
||||||
transmit_can_frame(&SANTAFE_7E4_ack,
|
transmit_can_frame(&SANTAFE_7E4_ack,
|
||||||
can_config.battery); //Send ack to BMS if the same frame is sent as polled
|
can_interface); //Send ack to BMS if the same frame is sent as polled
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x21: //First frame in PID group
|
case 0x21: //First frame in PID group
|
||||||
|
@ -317,7 +263,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20);
|
cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20);
|
||||||
|
|
||||||
//Map all cell voltages to the global array, we have sampled them all!
|
//Map all cell voltages to the global array, we have sampled them all!
|
||||||
memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages_mv, 96 * sizeof(uint16_t));
|
memcpy(datalayer_battery->status.cell_voltages_mV, cellvoltages_mv, 96 * sizeof(uint16_t));
|
||||||
} else if (poll_data_pid == 5) {
|
} else if (poll_data_pid == 5) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -333,7 +279,8 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void transmit_can_battery(unsigned long currentMillis) {
|
|
||||||
|
void SantaFePhevBattery::transmit_can(unsigned long currentMillis) {
|
||||||
//Send 10ms message
|
//Send 10ms message
|
||||||
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
|
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
|
||||||
previousMillis10 = currentMillis;
|
previousMillis10 = currentMillis;
|
||||||
|
@ -344,14 +291,9 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
|
|
||||||
SANTAFE_200.data.u8[7] = checksum_200;
|
SANTAFE_200.data.u8[7] = checksum_200;
|
||||||
|
|
||||||
transmit_can_frame(&SANTAFE_200, can_config.battery);
|
transmit_can_frame(&SANTAFE_200, can_interface);
|
||||||
transmit_can_frame(&SANTAFE_2A1, can_config.battery);
|
transmit_can_frame(&SANTAFE_2A1, can_interface);
|
||||||
transmit_can_frame(&SANTAFE_2F0, can_config.battery);
|
transmit_can_frame(&SANTAFE_2F0, can_interface);
|
||||||
#ifdef DOUBLE_BATTERY
|
|
||||||
transmit_can_frame(&SANTAFE_200, can_config.battery_double);
|
|
||||||
transmit_can_frame(&SANTAFE_2A1, can_config.battery_double);
|
|
||||||
transmit_can_frame(&SANTAFE_2F0, can_config.battery_double);
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
|
|
||||||
counter_200++;
|
counter_200++;
|
||||||
if (counter_200 > 0xF) {
|
if (counter_200 > 0xF) {
|
||||||
|
@ -363,10 +305,7 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||||
previousMillis100 = currentMillis;
|
previousMillis100 = currentMillis;
|
||||||
|
|
||||||
transmit_can_frame(&SANTAFE_523, can_config.battery);
|
transmit_can_frame(&SANTAFE_523, can_interface);
|
||||||
#ifdef DOUBLE_BATTERY
|
|
||||||
transmit_can_frame(&SANTAFE_523, can_config.battery_double);
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send 500ms CAN Message
|
// Send 500ms CAN Message
|
||||||
|
@ -376,302 +315,23 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
// PID data is polled after last message sent from battery:
|
// PID data is polled after last message sent from battery:
|
||||||
poll_data_pid = (poll_data_pid % 5) + 1;
|
poll_data_pid = (poll_data_pid % 5) + 1;
|
||||||
SANTAFE_7E4_poll.data.u8[3] = (uint8_t)poll_data_pid;
|
SANTAFE_7E4_poll.data.u8[3] = (uint8_t)poll_data_pid;
|
||||||
transmit_can_frame(&SANTAFE_7E4_poll, can_config.battery);
|
transmit_can_frame(&SANTAFE_7E4_poll, can_interface);
|
||||||
#ifdef DOUBLE_BATTERY
|
|
||||||
transmit_can_frame(&SANTAFE_7E4_poll, can_config.battery_double);
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
void SantaFePhevBattery::setup(void) { // Performs one time setup at startup
|
||||||
void update_values_battery2() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
|
||||||
|
|
||||||
datalayer.battery2.status.real_soc = (battery2_SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
|
||||||
|
|
||||||
datalayer.battery2.status.soh_pptt = (battery2_SOH * 100); //Increase decimals from 100% -> 100.00%
|
|
||||||
|
|
||||||
datalayer.battery2.status.voltage_dV = battery2_batteryVoltage;
|
|
||||||
|
|
||||||
datalayer.battery2.status.current_dA = -battery2_batteryAmps;
|
|
||||||
|
|
||||||
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 = battery2_allowedDischargePower * 10;
|
|
||||||
|
|
||||||
datalayer.battery2.status.max_charge_power_W = battery2_allowedChargePower * 10;
|
|
||||||
|
|
||||||
//Power in watts, Negative = charging batt
|
|
||||||
datalayer.battery2.status.active_power_W =
|
|
||||||
((datalayer.battery2.status.voltage_dV * datalayer.battery2.status.current_dA) / 100);
|
|
||||||
|
|
||||||
datalayer.battery2.status.cell_max_voltage_mV = battery2_CellVoltMax_mV;
|
|
||||||
|
|
||||||
datalayer.battery2.status.cell_min_voltage_mV = battery2_CellVoltMin_mV;
|
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_min_dC = battery2_temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_max_dC = battery2_temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
|
||||||
|
|
||||||
if (battery2_leadAcidBatteryVoltage < 110) {
|
|
||||||
set_event(EVENT_12V_LOW, battery2_leadAcidBatteryVoltage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
|
||||||
switch (rx_frame.ID) {
|
|
||||||
case 0x1FF:
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
battery2_StatusBattery = (rx_frame.data.u8[0] & 0x0F);
|
|
||||||
break;
|
|
||||||
case 0x4D5:
|
|
||||||
break;
|
|
||||||
case 0x4DD:
|
|
||||||
break;
|
|
||||||
case 0x4DE:
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
break;
|
|
||||||
case 0x4E0:
|
|
||||||
break;
|
|
||||||
case 0x542:
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
battery2_SOC_Display = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]) / 2;
|
|
||||||
break;
|
|
||||||
case 0x588:
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
battery2_batteryVoltage = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]);
|
|
||||||
break;
|
|
||||||
case 0x597:
|
|
||||||
break;
|
|
||||||
case 0x5A6:
|
|
||||||
break;
|
|
||||||
case 0x5A7:
|
|
||||||
break;
|
|
||||||
case 0x5AD:
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
battery2_batteryAmps = (rx_frame.data.u8[3] << 8) + rx_frame.data.u8[2];
|
|
||||||
break;
|
|
||||||
case 0x5AE:
|
|
||||||
break;
|
|
||||||
case 0x5F1:
|
|
||||||
break;
|
|
||||||
case 0x620:
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
battery2_leadAcidBatteryVoltage = rx_frame.data.u8[1];
|
|
||||||
battery2_temperatureMin = rx_frame.data.u8[6]; //Lowest temp in battery
|
|
||||||
battery2_temperatureMax = rx_frame.data.u8[7]; //Highest temp in battery
|
|
||||||
break;
|
|
||||||
case 0x670:
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
battery2_allowedChargePower = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
|
|
||||||
battery2_allowedDischargePower = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
|
|
||||||
break;
|
|
||||||
case 0x671:
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
break;
|
|
||||||
case 0x7EC: //Data From polled PID group, BigEndian
|
|
||||||
switch (rx_frame.data.u8[0]) {
|
|
||||||
case 0x10: //"PID Header"
|
|
||||||
if (rx_frame.data.u8[4] == poll_data_pid) {
|
|
||||||
transmit_can_frame(&SANTAFE_7E4_ack,
|
|
||||||
can_config.battery_double); //Send ack to BMS if the same frame is sent as polled
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x21: //First frame in PID group
|
|
||||||
if (poll_data_pid == 1) {
|
|
||||||
} else if (poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[0] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[1] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[2] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[3] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[4] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[5] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[32] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[33] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[34] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[35] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[36] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[37] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[64] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[65] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[66] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[67] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[68] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[69] = (rx_frame.data.u8[7] * 20);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x22: //Second datarow in PID group
|
|
||||||
if (poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[6] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[7] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[8] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[9] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[10] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[11] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[12] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[38] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[39] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[40] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[41] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[42] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[43] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[44] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[70] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[71] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[72] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[73] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[74] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[75] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[76] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 6) {
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x23: //Third datarow in PID group
|
|
||||||
if (poll_data_pid == 1) {
|
|
||||||
battery2_CellVoltMax_mV = (rx_frame.data.u8[7] * 20); //(volts *50) *20 =mV
|
|
||||||
} else if (poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[13] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[14] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[15] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[16] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[17] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[18] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[19] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[45] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[46] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[47] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[48] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[49] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[50] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[51] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[77] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[78] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[79] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[80] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[81] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[82] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[83] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 5) {
|
|
||||||
if (rx_frame.data.u8[6] > 0) {
|
|
||||||
battery2_SOH = rx_frame.data.u8[6];
|
|
||||||
}
|
|
||||||
if (battery2_SOH > 100) {
|
|
||||||
battery2_SOH = 100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x24: //Fourth datarow in PID group
|
|
||||||
if (poll_data_pid == 1) {
|
|
||||||
battery2_CellVmaxNo = rx_frame.data.u8[1];
|
|
||||||
battery2_CellVminNo = rx_frame.data.u8[3];
|
|
||||||
CellVoltMin_mV = (rx_frame.data.u8[2] * 20); //(volts *50) *20 =mV
|
|
||||||
} else if (poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[20] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[21] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[22] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[23] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[24] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[25] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[26] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[52] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[53] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[54] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[55] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[56] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[57] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[58] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[84] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[85] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[86] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[87] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[88] = (rx_frame.data.u8[5] * 20);
|
|
||||||
battery2_cellvoltages_mv[89] = (rx_frame.data.u8[6] * 20);
|
|
||||||
battery2_cellvoltages_mv[90] = (rx_frame.data.u8[7] * 20);
|
|
||||||
} else if (poll_data_pid == 5) {
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x25: //Fifth datarow in PID group
|
|
||||||
if (poll_data_pid == 2) {
|
|
||||||
battery2_cellvoltages_mv[27] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[28] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[29] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[30] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[31] = (rx_frame.data.u8[5] * 20);
|
|
||||||
} else if (poll_data_pid == 3) {
|
|
||||||
battery2_cellvoltages_mv[59] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[60] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[61] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[62] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[63] = (rx_frame.data.u8[5] * 20);
|
|
||||||
} else if (poll_data_pid == 4) {
|
|
||||||
battery2_cellvoltages_mv[91] = (rx_frame.data.u8[1] * 20);
|
|
||||||
battery2_cellvoltages_mv[92] = (rx_frame.data.u8[2] * 20);
|
|
||||||
battery2_cellvoltages_mv[93] = (rx_frame.data.u8[3] * 20);
|
|
||||||
battery2_cellvoltages_mv[94] = (rx_frame.data.u8[4] * 20);
|
|
||||||
battery2_cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20);
|
|
||||||
|
|
||||||
//Map all cell voltages to the global array, we have sampled them all!
|
|
||||||
memcpy(datalayer.battery2.status.cell_voltages_mV, battery2_cellvoltages_mv, 96 * sizeof(uint16_t));
|
|
||||||
} else if (poll_data_pid == 5) {
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x26: //Sixth datarow in PID group
|
|
||||||
break;
|
|
||||||
case 0x27: //Seventh datarow in PID group
|
|
||||||
break;
|
|
||||||
case 0x28: //Eighth datarow in PID group
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
|
|
||||||
uint8_t CalculateCRC8(CAN_frame rx_frame) {
|
|
||||||
int crc = 0;
|
|
||||||
|
|
||||||
for (uint8_t framepos = 0; framepos < 8; framepos++) {
|
|
||||||
crc ^= rx_frame.data.u8[framepos];
|
|
||||||
|
|
||||||
for (uint8_t j = 0; j < 8; j++) {
|
|
||||||
if ((crc & 0x80) != 0) {
|
|
||||||
crc = (crc << 1) ^ 0x1;
|
|
||||||
} else {
|
|
||||||
crc <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (uint8_t)crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_battery(void) { // Performs one time setup at startup
|
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Santa Fe PHEV", 63);
|
strncpy(datalayer.system.info.battery_protocol, "Santa Fe PHEV", 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 96;
|
datalayer_battery->info.number_of_cells = 96;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
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.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
|
||||||
#ifdef DOUBLE_BATTERY
|
if (allows_contactor_closing) {
|
||||||
datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells;
|
*allows_contactor_closing = true;
|
||||||
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 = datalayer.battery.info.max_cell_voltage_deviation_mV;
|
|
||||||
#endif //DOUBLE_BATTERY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,17 +1,101 @@
|
||||||
#ifndef SANTA_FE_PHEV_BATTERY_H
|
#ifndef SANTA_FE_PHEV_BATTERY_H
|
||||||
#define SANTA_FE_PHEV_BATTERY_H
|
#define SANTA_FE_PHEV_BATTERY_H
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
#define MAX_PACK_VOLTAGE_DV 4040 //5000 = 500.0V
|
#define SELECTED_BATTERY_CLASS SantaFePhevBattery
|
||||||
#define MIN_PACK_VOLTAGE_DV 2880
|
|
||||||
#define MAX_CELL_DEVIATION_MV 250
|
|
||||||
#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
|
|
||||||
|
|
||||||
uint8_t CalculateCRC8(CAN_frame rx_frame);
|
class SantaFePhevBattery : public CanBattery {
|
||||||
void setup_battery(void);
|
public:
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
// Use this constructor for the second battery.
|
||||||
|
SantaFePhevBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, int targetCan) {
|
||||||
|
datalayer_battery = datalayer_ptr;
|
||||||
|
allows_contactor_closing = nullptr;
|
||||||
|
can_interface = targetCan;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the default constructor to create the first or single battery.
|
||||||
|
SantaFePhevBattery() {
|
||||||
|
datalayer_battery = &datalayer.battery;
|
||||||
|
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||||
|
can_interface = can_config.battery;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
|
int can_interface;
|
||||||
|
|
||||||
|
static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V
|
||||||
|
static const int MIN_PACK_VOLTAGE_DV = 2880;
|
||||||
|
static const int MAX_CELL_DEVIATION_MV = 250;
|
||||||
|
static const int MAX_CELL_VOLTAGE_MV = 4250; //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
|
||||||
|
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
|
||||||
|
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||||
|
unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was send
|
||||||
|
uint8_t poll_data_pid = 0;
|
||||||
|
uint8_t counter_200 = 0;
|
||||||
|
uint8_t checksum_200 = 0;
|
||||||
|
|
||||||
|
uint16_t SOC_Display = 0;
|
||||||
|
uint16_t batterySOH = 100;
|
||||||
|
uint16_t CellVoltMax_mV = 3700;
|
||||||
|
uint16_t CellVoltMin_mV = 3700;
|
||||||
|
uint8_t CellVmaxNo = 0;
|
||||||
|
uint8_t CellVminNo = 0;
|
||||||
|
uint16_t allowedDischargePower = 0;
|
||||||
|
uint16_t allowedChargePower = 0;
|
||||||
|
uint16_t batteryVoltage = 0;
|
||||||
|
int16_t leadAcidBatteryVoltage = 120;
|
||||||
|
int8_t temperatureMax = 0;
|
||||||
|
int8_t temperatureMin = 0;
|
||||||
|
int16_t batteryAmps = 0;
|
||||||
|
uint8_t StatusBattery = 0;
|
||||||
|
uint16_t cellvoltages_mv[96];
|
||||||
|
|
||||||
|
CAN_frame SANTAFE_200 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x200,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00}};
|
||||||
|
CAN_frame SANTAFE_2A1 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x2A1,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x02}};
|
||||||
|
CAN_frame SANTAFE_2F0 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x2F0,
|
||||||
|
.data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}};
|
||||||
|
CAN_frame SANTAFE_523 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x523,
|
||||||
|
.data = {0x60, 0x00, 0x60, 0, 0, 0, 0, 0}};
|
||||||
|
CAN_frame SANTAFE_7E4_poll = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4, //Polling frame, 0x22 01 0X
|
||||||
|
.data = {0x03, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
CAN_frame SANTAFE_7E4_ack = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x7E4, //Ack frame, correct PID is returned. Flow control message
|
||||||
|
.data = {0x30, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,453 +1,13 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#ifdef TESLA_BATTERY
|
#ifdef TESLA_BATTERY
|
||||||
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For Advanced Battery Insights webpage
|
#include "../datalayer/datalayer_extended.h" //For Advanced Battery Insights webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "TESLA-BATTERY.h"
|
#include "TESLA-BATTERY.h"
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
|
||||||
/* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */
|
/* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */
|
||||||
|
|
||||||
static unsigned long previousMillis10 = 0; // will store last time a 50ms CAN Message was sent
|
|
||||||
static unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was sent
|
|
||||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
|
|
||||||
static unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was sent
|
|
||||||
static unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was sent
|
|
||||||
static bool alternate243 = false;
|
|
||||||
//0x221 545 VCFRONT_LVPowerState: "GenMsgCycleTime" 50ms
|
|
||||||
CAN_frame TESLA_221_1 = {
|
|
||||||
.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x221,
|
|
||||||
.data = {0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96}}; //Contactor frame 221 - close contactors
|
|
||||||
CAN_frame TESLA_221_2 = {
|
|
||||||
.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x221,
|
|
||||||
.data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive
|
|
||||||
//0x241 VCFRONT_coolant 100ms
|
|
||||||
CAN_frame TESLA_241 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 7,
|
|
||||||
.ID = 0x241,
|
|
||||||
.data = {0x3C, 0x78, 0x2C, 0x0F, 0x1E, 0x5B, 0x00}};
|
|
||||||
//0x242 VCLEFT_LVPowerState 100ms
|
|
||||||
CAN_frame TESLA_242 = {.FD = false, .ext_ID = false, .DLC = 2, .ID = 0x242, .data = {0x10, 0x95}};
|
|
||||||
//0x243 VCRIGHT_hvacStatus 50ms
|
|
||||||
CAN_frame TESLA_243_1 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x243,
|
|
||||||
.data = {0xC9, 0x00, 0xEB, 0xD4, 0x31, 0x32, 0x02, 0x00}};
|
|
||||||
CAN_frame TESLA_243_2 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x243,
|
|
||||||
.data = {0x08, 0x81, 0x42, 0x60, 0x92, 0x2C, 0x0E, 0x09}};
|
|
||||||
//0x129 SteeringAngle 10ms
|
|
||||||
CAN_frame TESLA_129 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x129,
|
|
||||||
.data = {0x21, 0x24, 0x36, 0x5F, 0x00, 0x20, 0xFF, 0x3F}};
|
|
||||||
//0x612 UDS diagnostic requests - on demand
|
|
||||||
CAN_frame TESLA_602 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x602,
|
|
||||||
.data = {0x02, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
static uint8_t stateMachineClearIsolationFault = 0xFF;
|
|
||||||
static uint8_t stateMachineBMSReset = 0xFF;
|
|
||||||
static uint16_t sendContactorClosingMessagesStill = 300;
|
|
||||||
static uint16_t battery_cell_max_v = 3300;
|
|
||||||
static uint16_t battery_cell_min_v = 3300;
|
|
||||||
static uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
|
|
||||||
static bool cellvoltagesRead = false;
|
|
||||||
//0x3d2: 978 BMS_kwhCounter
|
|
||||||
static uint32_t battery_total_discharge = 0;
|
|
||||||
static uint32_t battery_total_charge = 0;
|
|
||||||
//0x352: 850 BMS_energyStatus
|
|
||||||
static bool BMS352_mux = false; // variable to store when 0x352 mux is present
|
|
||||||
static uint16_t battery_energy_buffer = 0; // kWh
|
|
||||||
static uint16_t battery_energy_buffer_m1 = 0; // kWh
|
|
||||||
static uint16_t battery_energy_to_charge_complete = 0; // kWh
|
|
||||||
static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh
|
|
||||||
static uint16_t battery_expected_energy_remaining = 0; // kWh
|
|
||||||
static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh
|
|
||||||
static bool battery_full_charge_complete = false; // Changed to bool
|
|
||||||
static bool battery_fully_charged = false; // Changed to bool
|
|
||||||
static uint16_t battery_ideal_energy_remaining = 0; // kWh
|
|
||||||
static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh
|
|
||||||
static uint16_t battery_nominal_energy_remaining = 0; // kWh
|
|
||||||
static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh
|
|
||||||
static uint16_t battery_nominal_full_pack_energy = 0; // Kwh
|
|
||||||
static uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh
|
|
||||||
//0x132 306 HVBattAmpVolt
|
|
||||||
static uint16_t battery_volts = 0; // V
|
|
||||||
static int16_t battery_amps = 0; // A
|
|
||||||
static int16_t battery_raw_amps = 0; // A
|
|
||||||
static uint16_t battery_charge_time_remaining = 0; // Minutes
|
|
||||||
//0x252 594 BMS_powerAvailable
|
|
||||||
static uint16_t BMS_maxRegenPower = 0; //rename from battery_regenerative_limit
|
|
||||||
static uint16_t BMS_maxDischargePower = 0; // rename from battery_discharge_limit
|
|
||||||
static uint16_t BMS_maxStationaryHeatPower = 0; //rename from battery_max_heat_park
|
|
||||||
static uint16_t BMS_hvacPowerBudget = 0; //rename from battery_hvac_max_power
|
|
||||||
static uint8_t BMS_notEnoughPowerForHeatPump = 0;
|
|
||||||
static uint8_t BMS_powerLimitState = 0;
|
|
||||||
static uint8_t BMS_inverterTQF = 0;
|
|
||||||
//0x2d2: 722 BMSVAlimits
|
|
||||||
static uint16_t battery_max_discharge_current = 0;
|
|
||||||
static uint16_t battery_max_charge_current = 0;
|
|
||||||
static uint16_t battery_bms_max_voltage = 0;
|
|
||||||
static uint16_t battery_bms_min_voltage = 0;
|
|
||||||
//0x2b4: 692 PCS_dcdcRailStatus
|
|
||||||
static uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt
|
|
||||||
static uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt
|
|
||||||
static uint16_t battery_dcdcLvOutputCurrent =
|
|
||||||
0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent
|
|
||||||
//0x292: 658 BMS_socStatus
|
|
||||||
static uint16_t battery_beginning_of_life = 0; // kWh
|
|
||||||
static uint16_t battery_soc_min = 0;
|
|
||||||
static uint16_t battery_soc_max = 0;
|
|
||||||
static uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui
|
|
||||||
static uint16_t battery_soc_ave = 0;
|
|
||||||
static uint8_t battery_battTempPct = 0;
|
|
||||||
//0x392: BMS_packConfig
|
|
||||||
static uint32_t battery_packMass = 0;
|
|
||||||
static uint32_t battery_platformMaxBusVoltage = 0;
|
|
||||||
static uint32_t battery_packConfigMultiplexer = 0;
|
|
||||||
static uint32_t battery_moduleType = 0;
|
|
||||||
static uint32_t battery_reservedConfig = 0;
|
|
||||||
//0x332: 818 BattBrickMinMax:BMS_bmbMinMax
|
|
||||||
static int16_t battery_max_temp = 0; // C*
|
|
||||||
static int16_t battery_min_temp = 0; // C*
|
|
||||||
static uint16_t battery_BrickVoltageMax = 0;
|
|
||||||
static uint16_t battery_BrickVoltageMin = 0;
|
|
||||||
static uint8_t battery_BrickTempMaxNum = 0;
|
|
||||||
static uint8_t battery_BrickTempMinNum = 0;
|
|
||||||
static uint8_t battery_BrickModelTMax = 0;
|
|
||||||
static uint8_t battery_BrickModelTMin = 0;
|
|
||||||
static uint8_t battery_BrickVoltageMaxNum = 0; //rename from battery_max_vno
|
|
||||||
static uint8_t battery_BrickVoltageMinNum = 0; //rename from battery_min_vno
|
|
||||||
//0x20A: 522 HVP_contactorState
|
|
||||||
static uint8_t battery_contactor = 0; //State of contactor
|
|
||||||
static uint8_t battery_hvil_status = 0;
|
|
||||||
static uint8_t battery_packContNegativeState = 0;
|
|
||||||
static uint8_t battery_packContPositiveState = 0;
|
|
||||||
static uint8_t battery_packContactorSetState = 0;
|
|
||||||
static bool battery_packCtrsClosingAllowed = false; // Change to bool
|
|
||||||
static bool battery_pyroTestInProgress = false; // Change to bool
|
|
||||||
static bool battery_packCtrsOpenNowRequested = false; // Change to bool
|
|
||||||
static bool battery_packCtrsOpenRequested = false; // Change to bool
|
|
||||||
static uint8_t battery_packCtrsRequestStatus = 0;
|
|
||||||
static bool battery_packCtrsResetRequestRequired = false; // Change to bool
|
|
||||||
static bool battery_dcLinkAllowedToEnergize = false; // Change to bool
|
|
||||||
static bool battery_fcContNegativeAuxOpen = false; // Change to bool
|
|
||||||
static uint8_t battery_fcContNegativeState = 0;
|
|
||||||
static bool battery_fcContPositiveAuxOpen = false; // Change to bool
|
|
||||||
static uint8_t battery_fcContPositiveState = 0;
|
|
||||||
static uint8_t battery_fcContactorSetState = 0;
|
|
||||||
static bool battery_fcCtrsClosingAllowed = false; // Change to bool
|
|
||||||
static bool battery_fcCtrsOpenNowRequested = false; // Change to bool
|
|
||||||
static bool battery_fcCtrsOpenRequested = false; // Change to bool
|
|
||||||
static uint8_t battery_fcCtrsRequestStatus = 0;
|
|
||||||
static bool battery_fcCtrsResetRequestRequired = false; // Change to bool
|
|
||||||
static bool battery_fcLinkAllowedToEnergize = false; // Change to bool
|
|
||||||
//0x72A: BMS_serialNumber
|
|
||||||
static uint8_t BMS_SerialNumber[14] = {0}; // Stores raw HEX values for ASCII chars
|
|
||||||
//0x212: 530 BMS_status
|
|
||||||
static bool battery_BMS_hvacPowerRequest = false; //Change to bool
|
|
||||||
static bool battery_BMS_notEnoughPowerForDrive = false; //Change to bool
|
|
||||||
static bool battery_BMS_notEnoughPowerForSupport = false; //Change to bool
|
|
||||||
static bool battery_BMS_preconditionAllowed = false; //Change to bool
|
|
||||||
static bool battery_BMS_updateAllowed = false; //Change to bool
|
|
||||||
static bool battery_BMS_activeHeatingWorthwhile = false; //Change to bool
|
|
||||||
static bool battery_BMS_cpMiaOnHvs = false; //Change to bool
|
|
||||||
static uint8_t battery_BMS_contactorState = 0;
|
|
||||||
static uint8_t battery_BMS_state = 0;
|
|
||||||
static uint8_t battery_BMS_hvState = 0;
|
|
||||||
static uint16_t battery_BMS_isolationResistance = 0;
|
|
||||||
static bool battery_BMS_chargeRequest = false; //Change to bool
|
|
||||||
static bool battery_BMS_keepWarmRequest = false; //Change to bool
|
|
||||||
static uint8_t battery_BMS_uiChargeStatus = 0;
|
|
||||||
static bool battery_BMS_diLimpRequest = false; //Change to bool
|
|
||||||
static bool battery_BMS_okToShipByAir = false; //Change to bool
|
|
||||||
static bool battery_BMS_okToShipByLand = false; //Change to bool
|
|
||||||
static uint32_t battery_BMS_chgPowerAvailable = 0;
|
|
||||||
static uint8_t battery_BMS_chargeRetryCount = 0;
|
|
||||||
static bool battery_BMS_pcsPwmEnabled = false; //Change to bool
|
|
||||||
static bool battery_BMS_ecuLogUploadRequest = false; //Change to bool
|
|
||||||
static uint8_t battery_BMS_minPackTemperature = 0;
|
|
||||||
// 0x224:548 PCS_dcdcStatus
|
|
||||||
static uint8_t battery_PCS_dcdcPrechargeStatus = 0;
|
|
||||||
static uint8_t battery_PCS_dcdc12VSupportStatus = 0;
|
|
||||||
static uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0;
|
|
||||||
static uint16_t battery_PCS_dcdcMainState = 0;
|
|
||||||
static uint8_t battery_PCS_dcdcSubState = 0;
|
|
||||||
static bool battery_PCS_dcdcFaulted = false; //Change to bool
|
|
||||||
static bool battery_PCS_dcdcOutputIsLimited = false; //Change to bool
|
|
||||||
static uint32_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0;
|
|
||||||
static uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0;
|
|
||||||
static uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0;
|
|
||||||
static uint8_t battery_PCS_dcdcDischargeRtyCnt = 0;
|
|
||||||
static uint8_t battery_PCS_dcdcPwmEnableLine = 0;
|
|
||||||
static uint8_t battery_PCS_dcdcSupportingFixedLvTarget = 0;
|
|
||||||
static uint8_t battery_PCS_ecuLogUploadRequest = 0;
|
|
||||||
static uint8_t battery_PCS_dcdcPrechargeRestartCnt = 0;
|
|
||||||
static uint8_t battery_PCS_dcdcInitialPrechargeSubState = 0;
|
|
||||||
//0x312: 786 BMS_thermalStatus
|
|
||||||
static uint16_t BMS_powerDissipation = 0;
|
|
||||||
static uint16_t BMS_flowRequest = 0;
|
|
||||||
static uint16_t BMS_inletActiveCoolTargetT = 0;
|
|
||||||
static uint16_t BMS_inletPassiveTargetT = 0;
|
|
||||||
static uint16_t BMS_inletActiveHeatTargetT = 0;
|
|
||||||
static uint16_t BMS_packTMin = 0;
|
|
||||||
static uint16_t BMS_packTMax = 0;
|
|
||||||
static bool BMS_pcsNoFlowRequest = false;
|
|
||||||
static bool BMS_noFlowRequest = false;
|
|
||||||
//0x2A4; 676 PCS_thermalStatus
|
|
||||||
static int16_t PCS_chgPhATemp = 0;
|
|
||||||
static int16_t PCS_chgPhBTemp = 0;
|
|
||||||
static int16_t PCS_chgPhCTemp = 0;
|
|
||||||
static int16_t PCS_dcdcTemp = 0;
|
|
||||||
static int16_t PCS_ambientTemp = 0;
|
|
||||||
//0x2C4; 708 PCS_logging
|
|
||||||
static uint16_t PCS_logMessageSelect = 0;
|
|
||||||
static uint16_t PCS_dcdcMaxLvOutputCurrent = 0;
|
|
||||||
static uint16_t PCS_dcdcCurrentLimit = 0;
|
|
||||||
static uint16_t PCS_dcdcLvOutputCurrentTempLimit = 0;
|
|
||||||
static uint16_t PCS_dcdcUnifiedCommand = 0;
|
|
||||||
static uint16_t PCS_dcdcCLAControllerOutput = 0;
|
|
||||||
static int16_t PCS_dcdcTankVoltage = 0;
|
|
||||||
static uint16_t PCS_dcdcTankVoltageTarget = 0;
|
|
||||||
static uint16_t PCS_dcdcClaCurrentFreq = 0;
|
|
||||||
static int16_t PCS_dcdcTCommMeasured = 0;
|
|
||||||
static uint16_t PCS_dcdcShortTimeUs = 0;
|
|
||||||
static uint16_t PCS_dcdcHalfPeriodUs = 0;
|
|
||||||
static uint16_t PCS_dcdcIntervalMaxFrequency = 0;
|
|
||||||
static uint16_t PCS_dcdcIntervalMaxHvBusVolt = 0;
|
|
||||||
static uint16_t PCS_dcdcIntervalMaxLvBusVolt = 0;
|
|
||||||
static uint16_t PCS_dcdcIntervalMaxLvOutputCurr = 0;
|
|
||||||
static uint16_t PCS_dcdcIntervalMinFrequency = 0;
|
|
||||||
static uint16_t PCS_dcdcIntervalMinHvBusVolt = 0;
|
|
||||||
static uint16_t PCS_dcdcIntervalMinLvBusVolt = 0;
|
|
||||||
static uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0;
|
|
||||||
static uint32_t PCS_dcdc12vSupportLifetimekWh = 0;
|
|
||||||
//0x7AA: //1962 HVP_debugMessage:
|
|
||||||
static uint8_t HVP_debugMessageMultiplexer = 0;
|
|
||||||
static bool HVP_gpioPassivePyroDepl = false; //Change to bool
|
|
||||||
static bool HVP_gpioPyroIsoEn = false; //Change to bool
|
|
||||||
static bool HVP_gpioCpFaultIn = false; //Change to bool
|
|
||||||
static bool HVP_gpioPackContPowerEn = false; //Change to bool
|
|
||||||
static bool HVP_gpioHvCablesOk = false; //Change to bool
|
|
||||||
static bool HVP_gpioHvpSelfEnable = false; //Change to bool
|
|
||||||
static bool HVP_gpioLed = false; //Change to bool
|
|
||||||
static bool HVP_gpioCrashSignal = false; //Change to bool
|
|
||||||
static bool HVP_gpioShuntDataReady = false; //Change to bool
|
|
||||||
static bool HVP_gpioFcContPosAux = false; //Change to bool
|
|
||||||
static bool HVP_gpioFcContNegAux = false; //Change to bool
|
|
||||||
static bool HVP_gpioBmsEout = false; //Change to bool
|
|
||||||
static bool HVP_gpioCpFaultOut = false; //Change to bool
|
|
||||||
static bool HVP_gpioPyroPor = false; //Change to bool
|
|
||||||
static bool HVP_gpioShuntEn = false; //Change to bool
|
|
||||||
static bool HVP_gpioHvpVerEn = false; //Change to bool
|
|
||||||
static bool HVP_gpioPackCoontPosFlywheel = false; //Change to bool
|
|
||||||
static bool HVP_gpioCpLatchEnable = false; //Change to bool
|
|
||||||
static bool HVP_gpioPcsEnable = false; //Change to bool
|
|
||||||
static bool HVP_gpioPcsDcdcPwmEnable = false; //Change to bool
|
|
||||||
static bool HVP_gpioPcsChargePwmEnable = false; //Change to bool
|
|
||||||
static bool HVP_gpioFcContPowerEnable = false; //Change to bool
|
|
||||||
static bool HVP_gpioHvilEnable = false; //Change to bool
|
|
||||||
static bool HVP_gpioSecDrdy = false; //Change to bool
|
|
||||||
static uint16_t HVP_hvp1v5Ref = 0;
|
|
||||||
static int16_t HVP_shuntCurrentDebug = 0;
|
|
||||||
static bool HVP_packCurrentMia = false; //Change to bool
|
|
||||||
static bool HVP_auxCurrentMia = false; //Change to bool
|
|
||||||
static bool HVP_currentSenseMia = false; //Change to bool
|
|
||||||
static bool HVP_shuntRefVoltageMismatch = false; //Change to bool
|
|
||||||
static bool HVP_shuntThermistorMia = false; //Change to bool
|
|
||||||
static bool HVP_shuntHwMia = false; //Change to bool
|
|
||||||
static int16_t HVP_dcLinkVoltage = 0;
|
|
||||||
static int16_t HVP_packVoltage = 0;
|
|
||||||
static int16_t HVP_fcLinkVoltage = 0;
|
|
||||||
static uint16_t HVP_packContVoltage = 0;
|
|
||||||
static int16_t HVP_packNegativeV = 0;
|
|
||||||
static int16_t HVP_packPositiveV = 0;
|
|
||||||
static uint16_t HVP_pyroAnalog = 0;
|
|
||||||
static int16_t HVP_dcLinkNegativeV = 0;
|
|
||||||
static int16_t HVP_dcLinkPositiveV = 0;
|
|
||||||
static int16_t HVP_fcLinkNegativeV = 0;
|
|
||||||
static uint16_t HVP_fcContCoilCurrent = 0;
|
|
||||||
static uint16_t HVP_fcContVoltage = 0;
|
|
||||||
static uint16_t HVP_hvilInVoltage = 0;
|
|
||||||
static uint16_t HVP_hvilOutVoltage = 0;
|
|
||||||
static int16_t HVP_fcLinkPositiveV = 0;
|
|
||||||
static uint16_t HVP_packContCoilCurrent = 0;
|
|
||||||
static uint16_t HVP_battery12V = 0;
|
|
||||||
static int16_t HVP_shuntRefVoltageDbg = 0;
|
|
||||||
static int16_t HVP_shuntAuxCurrentDbg = 0;
|
|
||||||
static int16_t HVP_shuntBarTempDbg = 0;
|
|
||||||
static int16_t HVP_shuntAsicTempDbg = 0;
|
|
||||||
static uint8_t HVP_shuntAuxCurrentStatus = 0;
|
|
||||||
static uint8_t HVP_shuntBarTempStatus = 0;
|
|
||||||
static uint8_t HVP_shuntAsicTempStatus = 0;
|
|
||||||
//0x3aa: HVP_alertMatrix1 Fault codes // Change to bool
|
|
||||||
static bool battery_WatchdogReset = false; //Warns if the processor has experienced a reset due to watchdog reset.
|
|
||||||
static bool battery_PowerLossReset = false; //Warns if the processor has experienced a reset due to power loss.
|
|
||||||
static bool battery_SwAssertion = false; //An internal software assertion has failed.
|
|
||||||
static bool battery_CrashEvent = false; //Warns if the crash signal is detected by HVP
|
|
||||||
static bool battery_OverDchgCurrentFault = false; //Warns if the pack discharge is above max discharge current limit
|
|
||||||
static bool battery_OverChargeCurrentFault =
|
|
||||||
false; //Warns if the pack discharge current is above max charge current limit
|
|
||||||
static bool battery_OverCurrentFault =
|
|
||||||
false; //Warns if the pack current (discharge or charge) is above max current limit.
|
|
||||||
static bool battery_OverTemperatureFault = false; //A pack module temperature is above maximum temperature limit
|
|
||||||
static bool battery_OverVoltageFault = false; //A brick voltage is above maximum voltage limit
|
|
||||||
static bool battery_UnderVoltageFault = false; //A brick voltage is below minimum voltage limit
|
|
||||||
static bool battery_PrimaryBmbMiaFault =
|
|
||||||
false; //Warns if the voltage and temperature readings from primary BMB chain are mia
|
|
||||||
static bool battery_SecondaryBmbMiaFault =
|
|
||||||
false; //Warns if the voltage and temperature readings from secondary BMB chain are mia
|
|
||||||
static bool battery_BmbMismatchFault =
|
|
||||||
false; //Warns if the primary and secondary BMB chain readings don't match with each other
|
|
||||||
static bool battery_BmsHviMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN
|
|
||||||
static bool battery_CpMiaFault = false; //Warns if the CP node is mia on HVS CAN
|
|
||||||
static bool battery_PcsMiaFault = false; //The PCS node is mia on HVS CAN
|
|
||||||
static bool battery_BmsFault = false; //Warns if the BMS ECU has faulted
|
|
||||||
static bool battery_PcsFault = false; //Warns if the PCS ECU has faulted
|
|
||||||
static bool battery_CpFault = false; //Warns if the CP ECU has faulted
|
|
||||||
static bool battery_ShuntHwMiaFault = false; //Warns if the shunt current reading is not available
|
|
||||||
static bool battery_PyroMiaFault = false; //Warns if the pyro squib is not connected
|
|
||||||
static bool battery_hvsMiaFault = false; //Warns if the pack contactor hw fault
|
|
||||||
static bool battery_hviMiaFault = false; //Warns if the FC contactor hw fault
|
|
||||||
static bool battery_Supply12vFault = false; //Warns if the low voltage (12V) battery is below minimum voltage threshold
|
|
||||||
static bool battery_VerSupplyFault =
|
|
||||||
false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold
|
|
||||||
static bool battery_HvilFault = false; //Warn if a High Voltage Inter Lock fault is detected
|
|
||||||
static bool battery_BmsHvsMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN
|
|
||||||
static bool battery_PackVoltMismatchFault =
|
|
||||||
false; //Warns if the pack voltage doesn't match approximately with sum of brick voltages
|
|
||||||
static bool battery_EnsMiaFault = false; //Warns if the ENS line is not connected to HVC
|
|
||||||
static bool battery_PackPosCtrArcFault = false; //Warns if the HVP detectes series arc at pack contactor
|
|
||||||
static bool battery_packNegCtrArcFault = false; //Warns if the HVP detectes series arc at FC contactor
|
|
||||||
static bool battery_ShuntHwAndBmsMiaFault = false;
|
|
||||||
static bool battery_fcContHwFault = false;
|
|
||||||
static bool battery_robinOverVoltageFault = false;
|
|
||||||
static bool battery_packContHwFault = false;
|
|
||||||
static bool battery_pyroFuseBlown = false;
|
|
||||||
static bool battery_pyroFuseFailedToBlow = false;
|
|
||||||
static bool battery_CpilFault = false;
|
|
||||||
static bool battery_PackContactorFellOpen = false;
|
|
||||||
static bool battery_FcContactorFellOpen = false;
|
|
||||||
static bool battery_packCtrCloseBlocked = false;
|
|
||||||
static bool battery_fcCtrCloseBlocked = false;
|
|
||||||
static bool battery_packContactorForceOpen = false;
|
|
||||||
static bool battery_fcContactorForceOpen = false;
|
|
||||||
static bool battery_dcLinkOverVoltage = false;
|
|
||||||
static bool battery_shuntOverTemperature = false;
|
|
||||||
static bool battery_passivePyroDeploy = false;
|
|
||||||
static bool battery_logUploadRequest = false;
|
|
||||||
static bool battery_packCtrCloseFailed = false;
|
|
||||||
static bool battery_fcCtrCloseFailed = false;
|
|
||||||
static bool battery_shuntThermistorMia = false;
|
|
||||||
//0x320: 800 BMS_alertMatrix
|
|
||||||
static uint8_t battery_BMS_matrixIndex = 0; // Changed to bool
|
|
||||||
static bool battery_BMS_a061_robinBrickOverVoltage = false;
|
|
||||||
static bool battery_BMS_a062_SW_BrickV_Imbalance = false;
|
|
||||||
static bool battery_BMS_a063_SW_ChargePort_Fault = false;
|
|
||||||
static bool battery_BMS_a064_SW_SOC_Imbalance = false;
|
|
||||||
static bool battery_BMS_a127_SW_shunt_SNA = false;
|
|
||||||
static bool battery_BMS_a128_SW_shunt_MIA = false;
|
|
||||||
static bool battery_BMS_a069_SW_Low_Power = false;
|
|
||||||
static bool battery_BMS_a130_IO_CAN_Error = false;
|
|
||||||
static bool battery_BMS_a071_SW_SM_TransCon_Not_Met = false;
|
|
||||||
static bool battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = false;
|
|
||||||
static bool battery_BMS_a134_SW_Delayed_Ctr_Off = false;
|
|
||||||
static bool battery_BMS_a075_SW_Chg_Disable_Failure = false;
|
|
||||||
static bool battery_BMS_a076_SW_Dch_While_Charging = false;
|
|
||||||
static bool battery_BMS_a017_SW_Brick_OV = false;
|
|
||||||
static bool battery_BMS_a018_SW_Brick_UV = false;
|
|
||||||
static bool battery_BMS_a019_SW_Module_OT = false;
|
|
||||||
static bool battery_BMS_a021_SW_Dr_Limits_Regulation = false;
|
|
||||||
static bool battery_BMS_a022_SW_Over_Current = false;
|
|
||||||
static bool battery_BMS_a023_SW_Stack_OV = false;
|
|
||||||
static bool battery_BMS_a024_SW_Islanded_Brick = false;
|
|
||||||
static bool battery_BMS_a025_SW_PwrBalance_Anomaly = false;
|
|
||||||
static bool battery_BMS_a026_SW_HFCurrent_Anomaly = false;
|
|
||||||
static bool battery_BMS_a087_SW_Feim_Test_Blocked = false;
|
|
||||||
static bool battery_BMS_a088_SW_VcFront_MIA_InDrive = false;
|
|
||||||
static bool battery_BMS_a089_SW_VcFront_MIA = false;
|
|
||||||
static bool battery_BMS_a090_SW_Gateway_MIA = false;
|
|
||||||
static bool battery_BMS_a091_SW_ChargePort_MIA = false;
|
|
||||||
static bool battery_BMS_a092_SW_ChargePort_Mia_On_Hv = false;
|
|
||||||
static bool battery_BMS_a034_SW_Passive_Isolation = false;
|
|
||||||
static bool battery_BMS_a035_SW_Isolation = false;
|
|
||||||
static bool battery_BMS_a036_SW_HvpHvilFault = false;
|
|
||||||
static bool battery_BMS_a037_SW_Flood_Port_Open = false;
|
|
||||||
static bool battery_BMS_a158_SW_HVP_HVI_Comms = false;
|
|
||||||
static bool battery_BMS_a039_SW_DC_Link_Over_Voltage = false;
|
|
||||||
static bool battery_BMS_a041_SW_Power_On_Reset = false;
|
|
||||||
static bool battery_BMS_a042_SW_MPU_Error = false;
|
|
||||||
static bool battery_BMS_a043_SW_Watch_Dog_Reset = false;
|
|
||||||
static bool battery_BMS_a044_SW_Assertion = false;
|
|
||||||
static bool battery_BMS_a045_SW_Exception = false;
|
|
||||||
static bool battery_BMS_a046_SW_Task_Stack_Usage = false;
|
|
||||||
static bool battery_BMS_a047_SW_Task_Stack_Overflow = false;
|
|
||||||
static bool battery_BMS_a048_SW_Log_Upload_Request = false;
|
|
||||||
static bool battery_BMS_a169_SW_FC_Pack_Weld = false;
|
|
||||||
static bool battery_BMS_a050_SW_Brick_Voltage_MIA = false;
|
|
||||||
static bool battery_BMS_a051_SW_HVC_Vref_Bad = false;
|
|
||||||
static bool battery_BMS_a052_SW_PCS_MIA = false;
|
|
||||||
static bool battery_BMS_a053_SW_ThermalModel_Sanity = false;
|
|
||||||
static bool battery_BMS_a054_SW_Ver_Supply_Fault = false;
|
|
||||||
static bool battery_BMS_a176_SW_GracefulPowerOff = false;
|
|
||||||
static bool battery_BMS_a059_SW_Pack_Voltage_Sensing = false;
|
|
||||||
static bool battery_BMS_a060_SW_Leakage_Test_Failure = false;
|
|
||||||
static bool battery_BMS_a077_SW_Charger_Regulation = false;
|
|
||||||
static bool battery_BMS_a081_SW_Ctr_Close_Blocked = false;
|
|
||||||
static bool battery_BMS_a082_SW_Ctr_Force_Open = false;
|
|
||||||
static bool battery_BMS_a083_SW_Ctr_Close_Failure = false;
|
|
||||||
static bool battery_BMS_a084_SW_Sleep_Wake_Aborted = false;
|
|
||||||
static bool battery_BMS_a094_SW_Drive_Inverter_MIA = false;
|
|
||||||
static bool battery_BMS_a099_SW_BMB_Communication = false;
|
|
||||||
static bool battery_BMS_a105_SW_One_Module_Tsense = false;
|
|
||||||
static bool battery_BMS_a106_SW_All_Module_Tsense = false;
|
|
||||||
static bool battery_BMS_a107_SW_Stack_Voltage_MIA = false;
|
|
||||||
static bool battery_BMS_a121_SW_NVRAM_Config_Error = false;
|
|
||||||
static bool battery_BMS_a122_SW_BMS_Therm_Irrational = false;
|
|
||||||
static bool battery_BMS_a123_SW_Internal_Isolation = false;
|
|
||||||
static bool battery_BMS_a129_SW_VSH_Failure = false;
|
|
||||||
static bool battery_BMS_a131_Bleed_FET_Failure = false;
|
|
||||||
static bool battery_BMS_a136_SW_Module_OT_Warning = false;
|
|
||||||
static bool battery_BMS_a137_SW_Brick_UV_Warning = false;
|
|
||||||
static bool battery_BMS_a138_SW_Brick_OV_Warning = false;
|
|
||||||
static bool battery_BMS_a139_SW_DC_Link_V_Irrational = false;
|
|
||||||
static bool battery_BMS_a141_SW_BMB_Status_Warning = false;
|
|
||||||
static bool battery_BMS_a144_Hvp_Config_Mismatch = false;
|
|
||||||
static bool battery_BMS_a145_SW_SOC_Change = false;
|
|
||||||
static bool battery_BMS_a146_SW_Brick_Overdischarged = false;
|
|
||||||
static bool battery_BMS_a149_SW_Missing_Config_Block = false;
|
|
||||||
static bool battery_BMS_a151_SW_external_isolation = false;
|
|
||||||
static bool battery_BMS_a156_SW_BMB_Vref_bad = false;
|
|
||||||
static bool battery_BMS_a157_SW_HVP_HVS_Comms = false;
|
|
||||||
static bool battery_BMS_a159_SW_HVP_ECU_Error = false;
|
|
||||||
static bool battery_BMS_a161_SW_DI_Open_Request = false;
|
|
||||||
static bool battery_BMS_a162_SW_No_Power_For_Support = false;
|
|
||||||
static bool battery_BMS_a163_SW_Contactor_Mismatch = false;
|
|
||||||
static bool battery_BMS_a164_SW_Uncontrolled_Regen = false;
|
|
||||||
static bool battery_BMS_a165_SW_Pack_Partial_Weld = false;
|
|
||||||
static bool battery_BMS_a166_SW_Pack_Full_Weld = false;
|
|
||||||
static bool battery_BMS_a167_SW_FC_Partial_Weld = false;
|
|
||||||
static bool battery_BMS_a168_SW_FC_Full_Weld = false;
|
|
||||||
static bool battery_BMS_a170_SW_Limp_Mode = false;
|
|
||||||
static bool battery_BMS_a171_SW_Stack_Voltage_Sense = false;
|
|
||||||
static bool battery_BMS_a174_SW_Charge_Failure = false;
|
|
||||||
static bool battery_BMS_a179_SW_Hvp_12V_Fault = false;
|
|
||||||
static bool battery_BMS_a180_SW_ECU_reset_blocked = false;
|
|
||||||
|
|
||||||
// Function definitions
|
|
||||||
inline const char* getContactorText(int index) {
|
inline const char* getContactorText(int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -767,7 +327,8 @@ inline const char* getFault(bool value) {
|
||||||
return value ? "ACTIVE" : "NOT_ACTIVE";
|
return value ? "ACTIVE" : "NOT_ACTIVE";
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
void TeslaBattery::
|
||||||
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
//After values are mapped, we perform some safety checks, and do some serial printouts
|
//After values are mapped, we perform some safety checks, and do some serial printouts
|
||||||
|
|
||||||
datalayer.battery.status.soh_pptt = 9900; //Tesla batteries do not send a SOH% value on bus. Hardcode to 99%
|
datalayer.battery.status.soh_pptt = 9900; //Tesla batteries do not send a SOH% value on bus. Hardcode to 99%
|
||||||
|
@ -1138,7 +699,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
#endif //DEBUG_LOG
|
#endif //DEBUG_LOG
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
static uint8_t mux = 0;
|
static uint8_t mux = 0;
|
||||||
static uint16_t temp = 0;
|
static uint16_t temp = 0;
|
||||||
static bool mux0_read = false;
|
static bool mux0_read = false;
|
||||||
|
@ -1828,7 +1389,6 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL)
|
|
||||||
CAN_frame can_msg_1CF[] = {
|
CAN_frame can_msg_1CF[] = {
|
||||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0x60, 0x69}},
|
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0x60, 0x69}},
|
||||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0x80, 0x89}},
|
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0x80, 0x89}},
|
||||||
|
@ -1862,9 +1422,8 @@ unsigned long lastSend118 = 0;
|
||||||
|
|
||||||
int index_1CF = 0;
|
int index_1CF = 0;
|
||||||
int index_118 = 0;
|
int index_118 = 0;
|
||||||
#endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL)
|
|
||||||
|
|
||||||
void transmit_can_battery(unsigned long currentMillis) {
|
void TeslaBattery::transmit_can(unsigned long currentMillis) {
|
||||||
/*From bielec: My fist 221 message, to close the contactors is 0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96 and then,
|
/*From bielec: My fist 221 message, to close the contactors is 0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96 and then,
|
||||||
to cause "hv_up_for_drive" I send an additional 221 message 0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA so
|
to cause "hv_up_for_drive" I send an additional 221 message 0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA so
|
||||||
two 221 messages are being continuously transmitted. When I want to shut down, I stop the second message and only send
|
two 221 messages are being continuously transmitted. When I want to shut down, I stop the second message and only send
|
||||||
|
@ -1874,26 +1433,26 @@ the first, for a few cycles, then stop all messages which causes the contactor
|
||||||
return; //All cellvoltages not read yet, do not proceed with contactor closing
|
return; //All cellvoltages not read yet, do not proceed with contactor closing
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL)
|
if (operate_contactors) {
|
||||||
if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) {
|
if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) {
|
||||||
if (currentMillis - lastSend1CF >= 10) {
|
if (currentMillis - lastSend1CF >= 10) {
|
||||||
transmit_can_frame(&can_msg_1CF[index_1CF], can_config.battery);
|
transmit_can_frame(&can_msg_1CF[index_1CF], can_config.battery);
|
||||||
|
|
||||||
index_1CF = (index_1CF + 1) % 8;
|
index_1CF = (index_1CF + 1) % 8;
|
||||||
lastSend1CF = currentMillis;
|
lastSend1CF = currentMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentMillis - lastSend118 >= 10) {
|
||||||
|
transmit_can_frame(&can_msg_118[index_118], can_config.battery);
|
||||||
|
|
||||||
|
index_118 = (index_118 + 1) % 16;
|
||||||
|
lastSend118 = currentMillis;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index_1CF = 0;
|
||||||
|
index_118 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentMillis - lastSend118 >= 10) {
|
|
||||||
transmit_can_frame(&can_msg_118[index_118], can_config.battery);
|
|
||||||
|
|
||||||
index_118 = (index_118 + 1) % 16;
|
|
||||||
lastSend118 = currentMillis;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
index_1CF = 0;
|
|
||||||
index_118 = 0;
|
|
||||||
}
|
}
|
||||||
#endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL)
|
|
||||||
|
|
||||||
//Send 10ms message
|
//Send 10ms message
|
||||||
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
|
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
|
||||||
|
@ -2032,6 +1591,12 @@ the first, for a few cycles, then stop all messages which causes the contactor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printDebugIfActive(uint8_t symbol, const char* message) {
|
||||||
|
if (symbol == 1) {
|
||||||
|
logging.println(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void print_int_with_units(char* header, int value, char* units) {
|
void print_int_with_units(char* header, int value, char* units) {
|
||||||
logging.print(header);
|
logging.print(header);
|
||||||
logging.print(value);
|
logging.print(value);
|
||||||
|
@ -2049,7 +1614,7 @@ void print_SOC(char* header, int SOC) {
|
||||||
logging.println("%");
|
logging.println("%");
|
||||||
}
|
}
|
||||||
|
|
||||||
void printFaultCodesIfActive() {
|
void TeslaBattery::printFaultCodesIfActive() {
|
||||||
if (battery_packCtrsClosingAllowed == 0) {
|
if (battery_packCtrsClosingAllowed == 0) {
|
||||||
logging.println(
|
logging.println(
|
||||||
"ERROR: Check high voltage connectors and interlock circuit! Closing contactor not allowed! Values: ");
|
"ERROR: Check high voltage connectors and interlock circuit! Closing contactor not allowed! Values: ");
|
||||||
|
@ -2217,24 +1782,11 @@ void printFaultCodesIfActive() {
|
||||||
printDebugIfActive(battery_BMS_a180_SW_ECU_reset_blocked, "ERROR: BMS_a180_SW_ECU_reset_blocked");
|
printDebugIfActive(battery_BMS_a180_SW_ECU_reset_blocked, "ERROR: BMS_a180_SW_ECU_reset_blocked");
|
||||||
}
|
}
|
||||||
|
|
||||||
void printDebugIfActive(uint8_t symbol, const char* message) {
|
void TeslaModel3YBattery::setup(void) { // Performs one time setup at startup
|
||||||
if (symbol == 1) {
|
|
||||||
logging.println(message);
|
if (allows_contactor_closing) {
|
||||||
|
*allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setup_battery(void) { // Performs one time setup at startup
|
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
|
||||||
|
|
||||||
#ifdef TESLA_MODEL_SX_BATTERY // Always use NCM/A mode on S/X packs
|
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Tesla Model S/X", 63);
|
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA;
|
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA;
|
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM;
|
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
|
||||||
#endif // TESLA_MODEL_SX_BATTERY
|
|
||||||
|
|
||||||
#ifdef TESLA_MODEL_3Y_BATTERY // Model 3/Y can be either LFP or NCM/A
|
#ifdef TESLA_MODEL_3Y_BATTERY // Model 3/Y can be either LFP or NCM/A
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Tesla Model 3/Y", 63);
|
strncpy(datalayer.system.info.battery_protocol, "Tesla Model 3/Y", 63);
|
||||||
|
@ -2256,4 +1808,18 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#endif // TESLA_MODEL_3Y_BATTERY
|
#endif // TESLA_MODEL_3Y_BATTERY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TeslaModelSXBattery::setup(void) {
|
||||||
|
if (allows_contactor_closing) {
|
||||||
|
*allows_contactor_closing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(datalayer.system.info.battery_protocol, "Tesla Model S/X", 63);
|
||||||
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA;
|
||||||
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA;
|
||||||
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // TESLA_BATTERY
|
#endif // TESLA_BATTERY
|
||||||
|
|
|
@ -1,43 +1,512 @@
|
||||||
#ifndef TESLA_BATTERY_H
|
#ifndef TESLA_BATTERY_H
|
||||||
#define TESLA_BATTERY_H
|
#define TESLA_BATTERY_H
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#ifdef TESLA_MODEL_3Y_BATTERY
|
||||||
/* Modify these if needed */
|
#define SELECTED_BATTERY_CLASS TeslaModel3YBattery
|
||||||
#define MAXCHARGEPOWERALLOWED 15000 // 15000W we use a define since the value supplied by Tesla is always 0
|
#endif
|
||||||
#define MAXDISCHARGEPOWERALLOWED 60000 // 60000W we use a define since the value supplied by Tesla is always 0
|
#ifdef TESLA_MODEL_SX_BATTERY
|
||||||
|
#define SELECTED_BATTERY_CLASS TeslaModelSXBattery
|
||||||
/* Do not change the defines below */
|
#endif
|
||||||
#define RAMPDOWN_SOC 900 // 90.0 SOC% to start ramping down from max charge power towards 0 at 100.00%
|
|
||||||
#define RAMPDOWNPOWERALLOWED 10000 // What power we ramp down from towards top balancing
|
|
||||||
#define FLOAT_MAX_POWER_W 200 // W, what power to allow for top balancing battery
|
|
||||||
#define FLOAT_START_MV 20 // mV, how many mV under overvoltage to start float charging
|
|
||||||
|
|
||||||
#define MAX_PACK_VOLTAGE_SX_NCMA 4600 // V+1, if pack voltage goes over this, charge stops
|
|
||||||
#define MIN_PACK_VOLTAGE_SX_NCMA 3100 // V+1, if pack voltage goes over this, charge stops
|
|
||||||
#define MAX_PACK_VOLTAGE_3Y_NCMA 4030 // V+1, if pack voltage goes over this, charge stops
|
|
||||||
#define MIN_PACK_VOLTAGE_3Y_NCMA 3100 // V+1, if pack voltage goes below this, discharge stops
|
|
||||||
#define MAX_PACK_VOLTAGE_3Y_LFP 3880 // V+1, if pack voltage goes over this, charge stops
|
|
||||||
#define MIN_PACK_VOLTAGE_3Y_LFP 2968 // V+1, if pack voltage goes below this, discharge stops
|
|
||||||
#define MAX_CELL_DEVIATION_NCA_NCM 500 //LED turns yellow on the board if mv delta exceeds this value
|
|
||||||
#define MAX_CELL_DEVIATION_LFP 400 //LED turns yellow on the board if mv delta exceeds this value
|
|
||||||
#define MAX_CELL_VOLTAGE_NCA_NCM 4250 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_NCA_NCM 2950 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
#define MAX_CELL_VOLTAGE_LFP 3650 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_LFP 2800 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
|
|
||||||
//#define EXP_TESLA_BMS_DIGITAL_HVIL // Experimental parameter. Forces the transmission of additional CAN frames for experimental purposes, to test potential HVIL issues in 3/Y packs with newer firmware.
|
//#define EXP_TESLA_BMS_DIGITAL_HVIL // Experimental parameter. Forces the transmission of additional CAN frames for experimental purposes, to test potential HVIL issues in 3/Y packs with newer firmware.
|
||||||
|
|
||||||
void printFaultCodesIfActive();
|
class TeslaBattery : public CanBattery {
|
||||||
void printDebugIfActive(uint8_t symbol, const char* message);
|
public:
|
||||||
void print_int_with_units(char* header, int value, char* units);
|
// Use the default constructor to create the first or single battery.
|
||||||
void print_SOC(char* header, int SOC);
|
TeslaBattery() { allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing; }
|
||||||
void setup_battery(void);
|
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
void printFaultCodesIfActive_battery2();
|
virtual void update_values();
|
||||||
#endif //DOUBLE_BATTERY
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/* Modify these if needed */
|
||||||
|
static const int MAXCHARGEPOWERALLOWED =
|
||||||
|
15000; // 15000W we use a define since the value supplied by Tesla is always 0
|
||||||
|
static const int MAXDISCHARGEPOWERALLOWED =
|
||||||
|
60000; // 60000W we use a define since the value supplied by Tesla is always 0
|
||||||
|
|
||||||
|
/* Do not change the defines below */
|
||||||
|
static const int RAMPDOWN_SOC = 900; // 90.0 SOC% to start ramping down from max charge power towards 0 at 100.00%
|
||||||
|
static const int RAMPDOWNPOWERALLOWED = 10000; // What power we ramp down from towards top balancing
|
||||||
|
static const int FLOAT_MAX_POWER_W = 200; // W, what power to allow for top balancing battery
|
||||||
|
static const int FLOAT_START_MV = 20; // mV, how many mV under overvoltage to start float charging
|
||||||
|
static const int MAX_PACK_VOLTAGE_SX_NCMA = 4600; // V+1, if pack voltage goes over this, charge stops
|
||||||
|
static const int MIN_PACK_VOLTAGE_SX_NCMA = 3100; // V+1, if pack voltage goes over this, charge stops
|
||||||
|
static const int MAX_PACK_VOLTAGE_3Y_NCMA = 4030; // V+1, if pack voltage goes over this, charge stops
|
||||||
|
static const int MIN_PACK_VOLTAGE_3Y_NCMA = 3100; // V+1, if pack voltage goes below this, discharge stops
|
||||||
|
static const int MAX_PACK_VOLTAGE_3Y_LFP = 3880; // V+1, if pack voltage goes over this, charge stops
|
||||||
|
static const int MIN_PACK_VOLTAGE_3Y_LFP = 2968; // V+1, if pack voltage goes below this, discharge stops
|
||||||
|
static const int MAX_CELL_DEVIATION_NCA_NCM = 500; //LED turns yellow on the board if mv delta exceeds this value
|
||||||
|
static const int MAX_CELL_DEVIATION_LFP = 400; //LED turns yellow on the board if mv delta exceeds this value
|
||||||
|
static const int MAX_CELL_VOLTAGE_NCA_NCM =
|
||||||
|
4250; //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
static const int MIN_CELL_VOLTAGE_NCA_NCM =
|
||||||
|
2950; //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
static const int MAX_CELL_VOLTAGE_LFP = 3650; //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
static const int MIN_CELL_VOLTAGE_LFP = 2800; //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
|
||||||
|
bool operate_contactors = false;
|
||||||
|
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
|
void printFaultCodesIfActive();
|
||||||
|
|
||||||
|
unsigned long previousMillis10 = 0; // will store last time a 50ms CAN Message was sent
|
||||||
|
unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was sent
|
||||||
|
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
|
||||||
|
unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was sent
|
||||||
|
unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was sent
|
||||||
|
bool alternate243 = false;
|
||||||
|
//0x221 545 VCFRONT_LVPowerState: "GenMsgCycleTime" 50ms
|
||||||
|
CAN_frame TESLA_221_1 = {
|
||||||
|
.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x221,
|
||||||
|
.data = {0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96}}; //Contactor frame 221 - close contactors
|
||||||
|
CAN_frame TESLA_221_2 = {
|
||||||
|
.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x221,
|
||||||
|
.data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive
|
||||||
|
//0x241 VCFRONT_coolant 100ms
|
||||||
|
CAN_frame TESLA_241 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 7,
|
||||||
|
.ID = 0x241,
|
||||||
|
.data = {0x3C, 0x78, 0x2C, 0x0F, 0x1E, 0x5B, 0x00}};
|
||||||
|
//0x242 VCLEFT_LVPowerState 100ms
|
||||||
|
CAN_frame TESLA_242 = {.FD = false, .ext_ID = false, .DLC = 2, .ID = 0x242, .data = {0x10, 0x95}};
|
||||||
|
//0x243 VCRIGHT_hvacStatus 50ms
|
||||||
|
CAN_frame TESLA_243_1 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x243,
|
||||||
|
.data = {0xC9, 0x00, 0xEB, 0xD4, 0x31, 0x32, 0x02, 0x00}};
|
||||||
|
CAN_frame TESLA_243_2 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x243,
|
||||||
|
.data = {0x08, 0x81, 0x42, 0x60, 0x92, 0x2C, 0x0E, 0x09}};
|
||||||
|
//0x129 SteeringAngle 10ms
|
||||||
|
CAN_frame TESLA_129 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x129,
|
||||||
|
.data = {0x21, 0x24, 0x36, 0x5F, 0x00, 0x20, 0xFF, 0x3F}};
|
||||||
|
//0x612 UDS diagnostic requests - on demand
|
||||||
|
CAN_frame TESLA_602 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x602,
|
||||||
|
.data = {0x02, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
uint8_t stateMachineClearIsolationFault = 0xFF;
|
||||||
|
uint8_t stateMachineBMSReset = 0xFF;
|
||||||
|
uint16_t sendContactorClosingMessagesStill = 300;
|
||||||
|
uint16_t battery_cell_max_v = 3300;
|
||||||
|
uint16_t battery_cell_min_v = 3300;
|
||||||
|
uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
|
||||||
|
bool cellvoltagesRead = false;
|
||||||
|
//0x3d2: 978 BMS_kwhCounter
|
||||||
|
uint32_t battery_total_discharge = 0;
|
||||||
|
uint32_t battery_total_charge = 0;
|
||||||
|
//0x352: 850 BMS_energyStatus
|
||||||
|
bool BMS352_mux = false; // variable to store when 0x352 mux is present
|
||||||
|
uint16_t battery_energy_buffer = 0; // kWh
|
||||||
|
uint16_t battery_energy_buffer_m1 = 0; // kWh
|
||||||
|
uint16_t battery_energy_to_charge_complete = 0; // kWh
|
||||||
|
uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh
|
||||||
|
uint16_t battery_expected_energy_remaining = 0; // kWh
|
||||||
|
uint16_t battery_expected_energy_remaining_m1 = 0; // kWh
|
||||||
|
bool battery_full_charge_complete = false; // Changed to bool
|
||||||
|
bool battery_fully_charged = false; // Changed to bool
|
||||||
|
uint16_t battery_ideal_energy_remaining = 0; // kWh
|
||||||
|
uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh
|
||||||
|
uint16_t battery_nominal_energy_remaining = 0; // kWh
|
||||||
|
uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh
|
||||||
|
uint16_t battery_nominal_full_pack_energy = 0; // Kwh
|
||||||
|
uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh
|
||||||
|
//0x132 306 HVBattAmpVolt
|
||||||
|
uint16_t battery_volts = 0; // V
|
||||||
|
int16_t battery_amps = 0; // A
|
||||||
|
int16_t battery_raw_amps = 0; // A
|
||||||
|
uint16_t battery_charge_time_remaining = 0; // Minutes
|
||||||
|
//0x252 594 BMS_powerAvailable
|
||||||
|
uint16_t BMS_maxRegenPower = 0; //rename from battery_regenerative_limit
|
||||||
|
uint16_t BMS_maxDischargePower = 0; // rename from battery_discharge_limit
|
||||||
|
uint16_t BMS_maxStationaryHeatPower = 0; //rename from battery_max_heat_park
|
||||||
|
uint16_t BMS_hvacPowerBudget = 0; //rename from battery_hvac_max_power
|
||||||
|
uint8_t BMS_notEnoughPowerForHeatPump = 0;
|
||||||
|
uint8_t BMS_powerLimitState = 0;
|
||||||
|
uint8_t BMS_inverterTQF = 0;
|
||||||
|
//0x2d2: 722 BMSVAlimits
|
||||||
|
uint16_t battery_max_discharge_current = 0;
|
||||||
|
uint16_t battery_max_charge_current = 0;
|
||||||
|
uint16_t battery_bms_max_voltage = 0;
|
||||||
|
uint16_t battery_bms_min_voltage = 0;
|
||||||
|
//0x2b4: 692 PCS_dcdcRailStatus
|
||||||
|
uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt
|
||||||
|
uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt
|
||||||
|
uint16_t battery_dcdcLvOutputCurrent = 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent
|
||||||
|
//0x292: 658 BMS_socStatus
|
||||||
|
uint16_t battery_beginning_of_life = 0; // kWh
|
||||||
|
uint16_t battery_soc_min = 0;
|
||||||
|
uint16_t battery_soc_max = 0;
|
||||||
|
uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui
|
||||||
|
uint16_t battery_soc_ave = 0;
|
||||||
|
uint8_t battery_battTempPct = 0;
|
||||||
|
//0x392: BMS_packConfig
|
||||||
|
uint32_t battery_packMass = 0;
|
||||||
|
uint32_t battery_platformMaxBusVoltage = 0;
|
||||||
|
uint32_t battery_packConfigMultiplexer = 0;
|
||||||
|
uint32_t battery_moduleType = 0;
|
||||||
|
uint32_t battery_reservedConfig = 0;
|
||||||
|
//0x332: 818 BattBrickMinMax:BMS_bmbMinMax
|
||||||
|
int16_t battery_max_temp = 0; // C*
|
||||||
|
int16_t battery_min_temp = 0; // C*
|
||||||
|
uint16_t battery_BrickVoltageMax = 0;
|
||||||
|
uint16_t battery_BrickVoltageMin = 0;
|
||||||
|
uint8_t battery_BrickTempMaxNum = 0;
|
||||||
|
uint8_t battery_BrickTempMinNum = 0;
|
||||||
|
uint8_t battery_BrickModelTMax = 0;
|
||||||
|
uint8_t battery_BrickModelTMin = 0;
|
||||||
|
uint8_t battery_BrickVoltageMaxNum = 0; //rename from battery_max_vno
|
||||||
|
uint8_t battery_BrickVoltageMinNum = 0; //rename from battery_min_vno
|
||||||
|
//0x20A: 522 HVP_contactorState
|
||||||
|
uint8_t battery_contactor = 0; //State of contactor
|
||||||
|
uint8_t battery_hvil_status = 0;
|
||||||
|
uint8_t battery_packContNegativeState = 0;
|
||||||
|
uint8_t battery_packContPositiveState = 0;
|
||||||
|
uint8_t battery_packContactorSetState = 0;
|
||||||
|
bool battery_packCtrsClosingAllowed = false; // Change to bool
|
||||||
|
bool battery_pyroTestInProgress = false; // Change to bool
|
||||||
|
bool battery_packCtrsOpenNowRequested = false; // Change to bool
|
||||||
|
bool battery_packCtrsOpenRequested = false; // Change to bool
|
||||||
|
uint8_t battery_packCtrsRequestStatus = 0;
|
||||||
|
bool battery_packCtrsResetRequestRequired = false; // Change to bool
|
||||||
|
bool battery_dcLinkAllowedToEnergize = false; // Change to bool
|
||||||
|
bool battery_fcContNegativeAuxOpen = false; // Change to bool
|
||||||
|
uint8_t battery_fcContNegativeState = 0;
|
||||||
|
bool battery_fcContPositiveAuxOpen = false; // Change to bool
|
||||||
|
uint8_t battery_fcContPositiveState = 0;
|
||||||
|
uint8_t battery_fcContactorSetState = 0;
|
||||||
|
bool battery_fcCtrsClosingAllowed = false; // Change to bool
|
||||||
|
bool battery_fcCtrsOpenNowRequested = false; // Change to bool
|
||||||
|
bool battery_fcCtrsOpenRequested = false; // Change to bool
|
||||||
|
uint8_t battery_fcCtrsRequestStatus = 0;
|
||||||
|
bool battery_fcCtrsResetRequestRequired = false; // Change to bool
|
||||||
|
bool battery_fcLinkAllowedToEnergize = false; // Change to bool
|
||||||
|
//0x72A: BMS_serialNumber
|
||||||
|
uint8_t BMS_SerialNumber[14] = {0}; // Stores raw HEX values for ASCII chars
|
||||||
|
//0x212: 530 BMS_status
|
||||||
|
bool battery_BMS_hvacPowerRequest = false; //Change to bool
|
||||||
|
bool battery_BMS_notEnoughPowerForDrive = false; //Change to bool
|
||||||
|
bool battery_BMS_notEnoughPowerForSupport = false; //Change to bool
|
||||||
|
bool battery_BMS_preconditionAllowed = false; //Change to bool
|
||||||
|
bool battery_BMS_updateAllowed = false; //Change to bool
|
||||||
|
bool battery_BMS_activeHeatingWorthwhile = false; //Change to bool
|
||||||
|
bool battery_BMS_cpMiaOnHvs = false; //Change to bool
|
||||||
|
uint8_t battery_BMS_contactorState = 0;
|
||||||
|
uint8_t battery_BMS_state = 0;
|
||||||
|
uint8_t battery_BMS_hvState = 0;
|
||||||
|
uint16_t battery_BMS_isolationResistance = 0;
|
||||||
|
bool battery_BMS_chargeRequest = false; //Change to bool
|
||||||
|
bool battery_BMS_keepWarmRequest = false; //Change to bool
|
||||||
|
uint8_t battery_BMS_uiChargeStatus = 0;
|
||||||
|
bool battery_BMS_diLimpRequest = false; //Change to bool
|
||||||
|
bool battery_BMS_okToShipByAir = false; //Change to bool
|
||||||
|
bool battery_BMS_okToShipByLand = false; //Change to bool
|
||||||
|
uint32_t battery_BMS_chgPowerAvailable = 0;
|
||||||
|
uint8_t battery_BMS_chargeRetryCount = 0;
|
||||||
|
bool battery_BMS_pcsPwmEnabled = false; //Change to bool
|
||||||
|
bool battery_BMS_ecuLogUploadRequest = false; //Change to bool
|
||||||
|
uint8_t battery_BMS_minPackTemperature = 0;
|
||||||
|
// 0x224:548 PCS_dcdcStatus
|
||||||
|
uint8_t battery_PCS_dcdcPrechargeStatus = 0;
|
||||||
|
uint8_t battery_PCS_dcdc12VSupportStatus = 0;
|
||||||
|
uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0;
|
||||||
|
uint16_t battery_PCS_dcdcMainState = 0;
|
||||||
|
uint8_t battery_PCS_dcdcSubState = 0;
|
||||||
|
bool battery_PCS_dcdcFaulted = false; //Change to bool
|
||||||
|
bool battery_PCS_dcdcOutputIsLimited = false; //Change to bool
|
||||||
|
uint32_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0;
|
||||||
|
uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0;
|
||||||
|
uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0;
|
||||||
|
uint8_t battery_PCS_dcdcDischargeRtyCnt = 0;
|
||||||
|
uint8_t battery_PCS_dcdcPwmEnableLine = 0;
|
||||||
|
uint8_t battery_PCS_dcdcSupportingFixedLvTarget = 0;
|
||||||
|
uint8_t battery_PCS_ecuLogUploadRequest = 0;
|
||||||
|
uint8_t battery_PCS_dcdcPrechargeRestartCnt = 0;
|
||||||
|
uint8_t battery_PCS_dcdcInitialPrechargeSubState = 0;
|
||||||
|
//0x312: 786 BMS_thermalStatus
|
||||||
|
uint16_t BMS_powerDissipation = 0;
|
||||||
|
uint16_t BMS_flowRequest = 0;
|
||||||
|
uint16_t BMS_inletActiveCoolTargetT = 0;
|
||||||
|
uint16_t BMS_inletPassiveTargetT = 0;
|
||||||
|
uint16_t BMS_inletActiveHeatTargetT = 0;
|
||||||
|
uint16_t BMS_packTMin = 0;
|
||||||
|
uint16_t BMS_packTMax = 0;
|
||||||
|
bool BMS_pcsNoFlowRequest = false;
|
||||||
|
bool BMS_noFlowRequest = false;
|
||||||
|
//0x2A4; 676 PCS_thermalStatus
|
||||||
|
int16_t PCS_chgPhATemp = 0;
|
||||||
|
int16_t PCS_chgPhBTemp = 0;
|
||||||
|
int16_t PCS_chgPhCTemp = 0;
|
||||||
|
int16_t PCS_dcdcTemp = 0;
|
||||||
|
int16_t PCS_ambientTemp = 0;
|
||||||
|
//0x2C4; 708 PCS_logging
|
||||||
|
uint16_t PCS_logMessageSelect = 0;
|
||||||
|
uint16_t PCS_dcdcMaxLvOutputCurrent = 0;
|
||||||
|
uint16_t PCS_dcdcCurrentLimit = 0;
|
||||||
|
uint16_t PCS_dcdcLvOutputCurrentTempLimit = 0;
|
||||||
|
uint16_t PCS_dcdcUnifiedCommand = 0;
|
||||||
|
uint16_t PCS_dcdcCLAControllerOutput = 0;
|
||||||
|
int16_t PCS_dcdcTankVoltage = 0;
|
||||||
|
uint16_t PCS_dcdcTankVoltageTarget = 0;
|
||||||
|
uint16_t PCS_dcdcClaCurrentFreq = 0;
|
||||||
|
int16_t PCS_dcdcTCommMeasured = 0;
|
||||||
|
uint16_t PCS_dcdcShortTimeUs = 0;
|
||||||
|
uint16_t PCS_dcdcHalfPeriodUs = 0;
|
||||||
|
uint16_t PCS_dcdcIntervalMaxFrequency = 0;
|
||||||
|
uint16_t PCS_dcdcIntervalMaxHvBusVolt = 0;
|
||||||
|
uint16_t PCS_dcdcIntervalMaxLvBusVolt = 0;
|
||||||
|
uint16_t PCS_dcdcIntervalMaxLvOutputCurr = 0;
|
||||||
|
uint16_t PCS_dcdcIntervalMinFrequency = 0;
|
||||||
|
uint16_t PCS_dcdcIntervalMinHvBusVolt = 0;
|
||||||
|
uint16_t PCS_dcdcIntervalMinLvBusVolt = 0;
|
||||||
|
uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0;
|
||||||
|
uint32_t PCS_dcdc12vSupportLifetimekWh = 0;
|
||||||
|
//0x7AA: //1962 HVP_debugMessage:
|
||||||
|
uint8_t HVP_debugMessageMultiplexer = 0;
|
||||||
|
bool HVP_gpioPassivePyroDepl = false; //Change to bool
|
||||||
|
bool HVP_gpioPyroIsoEn = false; //Change to bool
|
||||||
|
bool HVP_gpioCpFaultIn = false; //Change to bool
|
||||||
|
bool HVP_gpioPackContPowerEn = false; //Change to bool
|
||||||
|
bool HVP_gpioHvCablesOk = false; //Change to bool
|
||||||
|
bool HVP_gpioHvpSelfEnable = false; //Change to bool
|
||||||
|
bool HVP_gpioLed = false; //Change to bool
|
||||||
|
bool HVP_gpioCrashSignal = false; //Change to bool
|
||||||
|
bool HVP_gpioShuntDataReady = false; //Change to bool
|
||||||
|
bool HVP_gpioFcContPosAux = false; //Change to bool
|
||||||
|
bool HVP_gpioFcContNegAux = false; //Change to bool
|
||||||
|
bool HVP_gpioBmsEout = false; //Change to bool
|
||||||
|
bool HVP_gpioCpFaultOut = false; //Change to bool
|
||||||
|
bool HVP_gpioPyroPor = false; //Change to bool
|
||||||
|
bool HVP_gpioShuntEn = false; //Change to bool
|
||||||
|
bool HVP_gpioHvpVerEn = false; //Change to bool
|
||||||
|
bool HVP_gpioPackCoontPosFlywheel = false; //Change to bool
|
||||||
|
bool HVP_gpioCpLatchEnable = false; //Change to bool
|
||||||
|
bool HVP_gpioPcsEnable = false; //Change to bool
|
||||||
|
bool HVP_gpioPcsDcdcPwmEnable = false; //Change to bool
|
||||||
|
bool HVP_gpioPcsChargePwmEnable = false; //Change to bool
|
||||||
|
bool HVP_gpioFcContPowerEnable = false; //Change to bool
|
||||||
|
bool HVP_gpioHvilEnable = false; //Change to bool
|
||||||
|
bool HVP_gpioSecDrdy = false; //Change to bool
|
||||||
|
uint16_t HVP_hvp1v5Ref = 0;
|
||||||
|
int16_t HVP_shuntCurrentDebug = 0;
|
||||||
|
bool HVP_packCurrentMia = false; //Change to bool
|
||||||
|
bool HVP_auxCurrentMia = false; //Change to bool
|
||||||
|
bool HVP_currentSenseMia = false; //Change to bool
|
||||||
|
bool HVP_shuntRefVoltageMismatch = false; //Change to bool
|
||||||
|
bool HVP_shuntThermistorMia = false; //Change to bool
|
||||||
|
bool HVP_shuntHwMia = false; //Change to bool
|
||||||
|
int16_t HVP_dcLinkVoltage = 0;
|
||||||
|
int16_t HVP_packVoltage = 0;
|
||||||
|
int16_t HVP_fcLinkVoltage = 0;
|
||||||
|
uint16_t HVP_packContVoltage = 0;
|
||||||
|
int16_t HVP_packNegativeV = 0;
|
||||||
|
int16_t HVP_packPositiveV = 0;
|
||||||
|
uint16_t HVP_pyroAnalog = 0;
|
||||||
|
int16_t HVP_dcLinkNegativeV = 0;
|
||||||
|
int16_t HVP_dcLinkPositiveV = 0;
|
||||||
|
int16_t HVP_fcLinkNegativeV = 0;
|
||||||
|
uint16_t HVP_fcContCoilCurrent = 0;
|
||||||
|
uint16_t HVP_fcContVoltage = 0;
|
||||||
|
uint16_t HVP_hvilInVoltage = 0;
|
||||||
|
uint16_t HVP_hvilOutVoltage = 0;
|
||||||
|
int16_t HVP_fcLinkPositiveV = 0;
|
||||||
|
uint16_t HVP_packContCoilCurrent = 0;
|
||||||
|
uint16_t HVP_battery12V = 0;
|
||||||
|
int16_t HVP_shuntRefVoltageDbg = 0;
|
||||||
|
int16_t HVP_shuntAuxCurrentDbg = 0;
|
||||||
|
int16_t HVP_shuntBarTempDbg = 0;
|
||||||
|
int16_t HVP_shuntAsicTempDbg = 0;
|
||||||
|
uint8_t HVP_shuntAuxCurrentStatus = 0;
|
||||||
|
uint8_t HVP_shuntBarTempStatus = 0;
|
||||||
|
uint8_t HVP_shuntAsicTempStatus = 0;
|
||||||
|
//0x3aa: HVP_alertMatrix1 Fault codes // Change to bool
|
||||||
|
bool battery_WatchdogReset = false; //Warns if the processor has experienced a reset due to watchdog reset.
|
||||||
|
bool battery_PowerLossReset = false; //Warns if the processor has experienced a reset due to power loss.
|
||||||
|
bool battery_SwAssertion = false; //An internal software assertion has failed.
|
||||||
|
bool battery_CrashEvent = false; //Warns if the crash signal is detected by HVP
|
||||||
|
bool battery_OverDchgCurrentFault = false; //Warns if the pack discharge is above max discharge current limit
|
||||||
|
bool battery_OverChargeCurrentFault = false; //Warns if the pack discharge current is above max charge current limit
|
||||||
|
bool battery_OverCurrentFault = false; //Warns if the pack current (discharge or charge) is above max current limit.
|
||||||
|
bool battery_OverTemperatureFault = false; //A pack module temperature is above maximum temperature limit
|
||||||
|
bool battery_OverVoltageFault = false; //A brick voltage is above maximum voltage limit
|
||||||
|
bool battery_UnderVoltageFault = false; //A brick voltage is below minimum voltage limit
|
||||||
|
bool battery_PrimaryBmbMiaFault =
|
||||||
|
false; //Warns if the voltage and temperature readings from primary BMB chain are mia
|
||||||
|
bool battery_SecondaryBmbMiaFault =
|
||||||
|
false; //Warns if the voltage and temperature readings from secondary BMB chain are mia
|
||||||
|
bool battery_BmbMismatchFault =
|
||||||
|
false; //Warns if the primary and secondary BMB chain readings don't match with each other
|
||||||
|
bool battery_BmsHviMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN
|
||||||
|
bool battery_CpMiaFault = false; //Warns if the CP node is mia on HVS CAN
|
||||||
|
bool battery_PcsMiaFault = false; //The PCS node is mia on HVS CAN
|
||||||
|
bool battery_BmsFault = false; //Warns if the BMS ECU has faulted
|
||||||
|
bool battery_PcsFault = false; //Warns if the PCS ECU has faulted
|
||||||
|
bool battery_CpFault = false; //Warns if the CP ECU has faulted
|
||||||
|
bool battery_ShuntHwMiaFault = false; //Warns if the shunt current reading is not available
|
||||||
|
bool battery_PyroMiaFault = false; //Warns if the pyro squib is not connected
|
||||||
|
bool battery_hvsMiaFault = false; //Warns if the pack contactor hw fault
|
||||||
|
bool battery_hviMiaFault = false; //Warns if the FC contactor hw fault
|
||||||
|
bool battery_Supply12vFault = false; //Warns if the low voltage (12V) battery is below minimum voltage threshold
|
||||||
|
bool battery_VerSupplyFault = false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold
|
||||||
|
bool battery_HvilFault = false; //Warn if a High Voltage Inter Lock fault is detected
|
||||||
|
bool battery_BmsHvsMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN
|
||||||
|
bool battery_PackVoltMismatchFault =
|
||||||
|
false; //Warns if the pack voltage doesn't match approximately with sum of brick voltages
|
||||||
|
bool battery_EnsMiaFault = false; //Warns if the ENS line is not connected to HVC
|
||||||
|
bool battery_PackPosCtrArcFault = false; //Warns if the HVP detectes series arc at pack contactor
|
||||||
|
bool battery_packNegCtrArcFault = false; //Warns if the HVP detectes series arc at FC contactor
|
||||||
|
bool battery_ShuntHwAndBmsMiaFault = false;
|
||||||
|
bool battery_fcContHwFault = false;
|
||||||
|
bool battery_robinOverVoltageFault = false;
|
||||||
|
bool battery_packContHwFault = false;
|
||||||
|
bool battery_pyroFuseBlown = false;
|
||||||
|
bool battery_pyroFuseFailedToBlow = false;
|
||||||
|
bool battery_CpilFault = false;
|
||||||
|
bool battery_PackContactorFellOpen = false;
|
||||||
|
bool battery_FcContactorFellOpen = false;
|
||||||
|
bool battery_packCtrCloseBlocked = false;
|
||||||
|
bool battery_fcCtrCloseBlocked = false;
|
||||||
|
bool battery_packContactorForceOpen = false;
|
||||||
|
bool battery_fcContactorForceOpen = false;
|
||||||
|
bool battery_dcLinkOverVoltage = false;
|
||||||
|
bool battery_shuntOverTemperature = false;
|
||||||
|
bool battery_passivePyroDeploy = false;
|
||||||
|
bool battery_logUploadRequest = false;
|
||||||
|
bool battery_packCtrCloseFailed = false;
|
||||||
|
bool battery_fcCtrCloseFailed = false;
|
||||||
|
bool battery_shuntThermistorMia = false;
|
||||||
|
//0x320: 800 BMS_alertMatrix
|
||||||
|
uint8_t battery_BMS_matrixIndex = 0; // Changed to bool
|
||||||
|
bool battery_BMS_a061_robinBrickOverVoltage = false;
|
||||||
|
bool battery_BMS_a062_SW_BrickV_Imbalance = false;
|
||||||
|
bool battery_BMS_a063_SW_ChargePort_Fault = false;
|
||||||
|
bool battery_BMS_a064_SW_SOC_Imbalance = false;
|
||||||
|
bool battery_BMS_a127_SW_shunt_SNA = false;
|
||||||
|
bool battery_BMS_a128_SW_shunt_MIA = false;
|
||||||
|
bool battery_BMS_a069_SW_Low_Power = false;
|
||||||
|
bool battery_BMS_a130_IO_CAN_Error = false;
|
||||||
|
bool battery_BMS_a071_SW_SM_TransCon_Not_Met = false;
|
||||||
|
bool battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = false;
|
||||||
|
bool battery_BMS_a134_SW_Delayed_Ctr_Off = false;
|
||||||
|
bool battery_BMS_a075_SW_Chg_Disable_Failure = false;
|
||||||
|
bool battery_BMS_a076_SW_Dch_While_Charging = false;
|
||||||
|
bool battery_BMS_a017_SW_Brick_OV = false;
|
||||||
|
bool battery_BMS_a018_SW_Brick_UV = false;
|
||||||
|
bool battery_BMS_a019_SW_Module_OT = false;
|
||||||
|
bool battery_BMS_a021_SW_Dr_Limits_Regulation = false;
|
||||||
|
bool battery_BMS_a022_SW_Over_Current = false;
|
||||||
|
bool battery_BMS_a023_SW_Stack_OV = false;
|
||||||
|
bool battery_BMS_a024_SW_Islanded_Brick = false;
|
||||||
|
bool battery_BMS_a025_SW_PwrBalance_Anomaly = false;
|
||||||
|
bool battery_BMS_a026_SW_HFCurrent_Anomaly = false;
|
||||||
|
bool battery_BMS_a087_SW_Feim_Test_Blocked = false;
|
||||||
|
bool battery_BMS_a088_SW_VcFront_MIA_InDrive = false;
|
||||||
|
bool battery_BMS_a089_SW_VcFront_MIA = false;
|
||||||
|
bool battery_BMS_a090_SW_Gateway_MIA = false;
|
||||||
|
bool battery_BMS_a091_SW_ChargePort_MIA = false;
|
||||||
|
bool battery_BMS_a092_SW_ChargePort_Mia_On_Hv = false;
|
||||||
|
bool battery_BMS_a034_SW_Passive_Isolation = false;
|
||||||
|
bool battery_BMS_a035_SW_Isolation = false;
|
||||||
|
bool battery_BMS_a036_SW_HvpHvilFault = false;
|
||||||
|
bool battery_BMS_a037_SW_Flood_Port_Open = false;
|
||||||
|
bool battery_BMS_a158_SW_HVP_HVI_Comms = false;
|
||||||
|
bool battery_BMS_a039_SW_DC_Link_Over_Voltage = false;
|
||||||
|
bool battery_BMS_a041_SW_Power_On_Reset = false;
|
||||||
|
bool battery_BMS_a042_SW_MPU_Error = false;
|
||||||
|
bool battery_BMS_a043_SW_Watch_Dog_Reset = false;
|
||||||
|
bool battery_BMS_a044_SW_Assertion = false;
|
||||||
|
bool battery_BMS_a045_SW_Exception = false;
|
||||||
|
bool battery_BMS_a046_SW_Task_Stack_Usage = false;
|
||||||
|
bool battery_BMS_a047_SW_Task_Stack_Overflow = false;
|
||||||
|
bool battery_BMS_a048_SW_Log_Upload_Request = false;
|
||||||
|
bool battery_BMS_a169_SW_FC_Pack_Weld = false;
|
||||||
|
bool battery_BMS_a050_SW_Brick_Voltage_MIA = false;
|
||||||
|
bool battery_BMS_a051_SW_HVC_Vref_Bad = false;
|
||||||
|
bool battery_BMS_a052_SW_PCS_MIA = false;
|
||||||
|
bool battery_BMS_a053_SW_ThermalModel_Sanity = false;
|
||||||
|
bool battery_BMS_a054_SW_Ver_Supply_Fault = false;
|
||||||
|
bool battery_BMS_a176_SW_GracefulPowerOff = false;
|
||||||
|
bool battery_BMS_a059_SW_Pack_Voltage_Sensing = false;
|
||||||
|
bool battery_BMS_a060_SW_Leakage_Test_Failure = false;
|
||||||
|
bool battery_BMS_a077_SW_Charger_Regulation = false;
|
||||||
|
bool battery_BMS_a081_SW_Ctr_Close_Blocked = false;
|
||||||
|
bool battery_BMS_a082_SW_Ctr_Force_Open = false;
|
||||||
|
bool battery_BMS_a083_SW_Ctr_Close_Failure = false;
|
||||||
|
bool battery_BMS_a084_SW_Sleep_Wake_Aborted = false;
|
||||||
|
bool battery_BMS_a094_SW_Drive_Inverter_MIA = false;
|
||||||
|
bool battery_BMS_a099_SW_BMB_Communication = false;
|
||||||
|
bool battery_BMS_a105_SW_One_Module_Tsense = false;
|
||||||
|
bool battery_BMS_a106_SW_All_Module_Tsense = false;
|
||||||
|
bool battery_BMS_a107_SW_Stack_Voltage_MIA = false;
|
||||||
|
bool battery_BMS_a121_SW_NVRAM_Config_Error = false;
|
||||||
|
bool battery_BMS_a122_SW_BMS_Therm_Irrational = false;
|
||||||
|
bool battery_BMS_a123_SW_Internal_Isolation = false;
|
||||||
|
bool battery_BMS_a129_SW_VSH_Failure = false;
|
||||||
|
bool battery_BMS_a131_Bleed_FET_Failure = false;
|
||||||
|
bool battery_BMS_a136_SW_Module_OT_Warning = false;
|
||||||
|
bool battery_BMS_a137_SW_Brick_UV_Warning = false;
|
||||||
|
bool battery_BMS_a138_SW_Brick_OV_Warning = false;
|
||||||
|
bool battery_BMS_a139_SW_DC_Link_V_Irrational = false;
|
||||||
|
bool battery_BMS_a141_SW_BMB_Status_Warning = false;
|
||||||
|
bool battery_BMS_a144_Hvp_Config_Mismatch = false;
|
||||||
|
bool battery_BMS_a145_SW_SOC_Change = false;
|
||||||
|
bool battery_BMS_a146_SW_Brick_Overdischarged = false;
|
||||||
|
bool battery_BMS_a149_SW_Missing_Config_Block = false;
|
||||||
|
bool battery_BMS_a151_SW_external_isolation = false;
|
||||||
|
bool battery_BMS_a156_SW_BMB_Vref_bad = false;
|
||||||
|
bool battery_BMS_a157_SW_HVP_HVS_Comms = false;
|
||||||
|
bool battery_BMS_a159_SW_HVP_ECU_Error = false;
|
||||||
|
bool battery_BMS_a161_SW_DI_Open_Request = false;
|
||||||
|
bool battery_BMS_a162_SW_No_Power_For_Support = false;
|
||||||
|
bool battery_BMS_a163_SW_Contactor_Mismatch = false;
|
||||||
|
bool battery_BMS_a164_SW_Uncontrolled_Regen = false;
|
||||||
|
bool battery_BMS_a165_SW_Pack_Partial_Weld = false;
|
||||||
|
bool battery_BMS_a166_SW_Pack_Full_Weld = false;
|
||||||
|
bool battery_BMS_a167_SW_FC_Partial_Weld = false;
|
||||||
|
bool battery_BMS_a168_SW_FC_Full_Weld = false;
|
||||||
|
bool battery_BMS_a170_SW_Limp_Mode = false;
|
||||||
|
bool battery_BMS_a171_SW_Stack_Voltage_Sense = false;
|
||||||
|
bool battery_BMS_a174_SW_Charge_Failure = false;
|
||||||
|
bool battery_BMS_a179_SW_Hvp_12V_Fault = false;
|
||||||
|
bool battery_BMS_a180_SW_ECU_reset_blocked = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TeslaModel3YBattery : public TeslaBattery {
|
||||||
|
public:
|
||||||
|
TeslaModel3YBattery() {
|
||||||
|
#ifdef EXP_TESLA_BMS_DIGITAL_HVIL
|
||||||
|
operate_contactors = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
virtual void setup(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TeslaModelSXBattery : public TeslaBattery {
|
||||||
|
public:
|
||||||
|
TeslaModelSXBattery() { operate_contactors = true; }
|
||||||
|
virtual void setup(void);
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,153 +3,89 @@
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "TEST-FAKE-BATTERY.h"
|
#include "TEST-FAKE-BATTERY.h"
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
|
||||||
static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
|
|
||||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
|
||||||
static unsigned long previousMillis10s = 0; // will store last time a 1s CAN Message was send
|
|
||||||
|
|
||||||
CAN_frame TEST = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x123,
|
|
||||||
.data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}};
|
|
||||||
|
|
||||||
void print_units(char* header, int value, char* units) {
|
void print_units(char* header, int value, char* units) {
|
||||||
logging.print(header);
|
logging.print(header);
|
||||||
logging.print(value);
|
logging.print(value);
|
||||||
logging.print(units);
|
logging.print(units);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_values_battery() { /* This function puts fake values onto the parameters sent towards the inverter */
|
void TestFakeBattery::
|
||||||
|
update_values() { /* This function puts fake values onto the parameters sent towards the inverter */
|
||||||
|
|
||||||
datalayer.battery.status.real_soc = 5000; // 50.00%
|
datalayer_battery->status.real_soc = 5000; // 50.00%
|
||||||
|
|
||||||
datalayer.battery.status.soh_pptt = 9900; // 99.00%
|
datalayer_battery->status.soh_pptt = 9900; // 99.00%
|
||||||
|
|
||||||
//datalayer.battery.status.voltage_dV = 3700; // 370.0V , value set in startup in .ino file, editable via webUI
|
//datalayer_battery->status.voltage_dV = 3700; // 370.0V , value set in startup in .ino file, editable via webUI
|
||||||
|
|
||||||
datalayer.battery.status.current_dA = 0; // 0 A
|
datalayer_battery->status.current_dA = 0; // 0 A
|
||||||
|
|
||||||
datalayer.battery.info.total_capacity_Wh = 30000; // 30kWh
|
datalayer_battery->info.total_capacity_Wh = 30000; // 30kWh
|
||||||
|
|
||||||
datalayer.battery.status.remaining_capacity_Wh = 15000; // 15kWh
|
datalayer_battery->status.remaining_capacity_Wh = 15000; // 15kWh
|
||||||
|
|
||||||
datalayer.battery.status.cell_max_voltage_mV = 3596;
|
datalayer_battery->status.cell_max_voltage_mV = 3596;
|
||||||
|
|
||||||
datalayer.battery.status.cell_min_voltage_mV = 3500;
|
datalayer_battery->status.cell_min_voltage_mV = 3500;
|
||||||
|
|
||||||
datalayer.battery.status.temperature_min_dC = 50; // 5.0*C
|
datalayer_battery->status.temperature_min_dC = 50; // 5.0*C
|
||||||
|
|
||||||
datalayer.battery.status.temperature_max_dC = 60; // 6.0*C
|
datalayer_battery->status.temperature_max_dC = 60; // 6.0*C
|
||||||
|
|
||||||
datalayer.battery.status.max_discharge_power_W = 5000; // 5kW
|
datalayer_battery->status.max_discharge_power_W = 5000; // 5kW
|
||||||
|
|
||||||
datalayer.battery.status.max_charge_power_W = 5000; // 5kW
|
datalayer_battery->status.max_charge_power_W = 5000; // 5kW
|
||||||
|
|
||||||
for (int i = 0; i < 97; ++i) {
|
for (int i = 0; i < 97; ++i) {
|
||||||
datalayer.battery.status.cell_voltages_mV[i] = 3700 + random(-20, 21);
|
datalayer_battery->status.cell_voltages_mV[i] = 3700 + random(-20, 21);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fake that we get CAN messages
|
//Fake that we get CAN messages
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
|
|
||||||
/*Finally print out values to serial if configured to do so*/
|
/*Finally print out values to serial if configured to do so*/
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.println("FAKE Values going to inverter");
|
logging.println("FAKE Values going to inverter");
|
||||||
print_units("SOH%: ", (datalayer.battery.status.soh_pptt * 0.01), "% ");
|
print_units("SOH%: ", (datalayer_battery->status.soh_pptt * 0.01), "% ");
|
||||||
print_units(", SOC%: ", (datalayer.battery.status.reported_soc * 0.01), "% ");
|
print_units(", SOC%: ", (datalayer_battery->status.reported_soc * 0.01), "% ");
|
||||||
print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V ");
|
print_units(", Voltage: ", (datalayer_battery->status.voltage_dV * 0.1), "V ");
|
||||||
print_units(", Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W ");
|
print_units(", Max discharge power: ", datalayer_battery->status.max_discharge_power_W, "W ");
|
||||||
print_units(", Max charge power: ", datalayer.battery.status.max_charge_power_W, "W ");
|
print_units(", Max charge power: ", datalayer_battery->status.max_charge_power_W, "W ");
|
||||||
print_units(", Max temp: ", (datalayer.battery.status.temperature_max_dC * 0.1), "°C ");
|
print_units(", Max temp: ", (datalayer_battery->status.temperature_max_dC * 0.1), "°C ");
|
||||||
print_units(", Min temp: ", (datalayer.battery.status.temperature_min_dC * 0.1), "°C ");
|
print_units(", Min temp: ", (datalayer_battery->status.temperature_min_dC * 0.1), "°C ");
|
||||||
print_units(", Max cell voltage: ", datalayer.battery.status.cell_max_voltage_mV, "mV ");
|
print_units(", Max cell voltage: ", datalayer_battery->status.cell_max_voltage_mV, "mV ");
|
||||||
print_units(", Min cell voltage: ", datalayer.battery.status.cell_min_voltage_mV, "mV ");
|
print_units(", Min cell voltage: ", datalayer_battery->status.cell_min_voltage_mV, "mV ");
|
||||||
logging.println("");
|
logging.println("");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
void TestFakeBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
void update_values_battery2() { // Handle the values coming in from battery #2
|
|
||||||
|
|
||||||
datalayer.battery2.info.number_of_cells = 96;
|
|
||||||
|
|
||||||
datalayer.battery2.status.real_soc = 5000; // 50.00%
|
|
||||||
|
|
||||||
datalayer.battery2.status.soh_pptt = 9900; // 99.00%
|
|
||||||
|
|
||||||
//datalayer.battery.status.voltage_dV = 3700; // 370.0V , value set in startup in .ino file, editable via webUI
|
|
||||||
|
|
||||||
datalayer.battery2.status.current_dA = 0; // 0 A
|
|
||||||
|
|
||||||
datalayer.battery2.info.total_capacity_Wh = 30000; // 30kWh
|
|
||||||
|
|
||||||
datalayer.battery2.status.remaining_capacity_Wh = 15000; // 15kWh
|
|
||||||
|
|
||||||
datalayer.battery2.status.cell_max_voltage_mV = 3596;
|
|
||||||
|
|
||||||
datalayer.battery2.status.cell_min_voltage_mV = 3500;
|
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_min_dC = 50; // 5.0*C
|
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_max_dC = 60; // 6.0*C
|
|
||||||
|
|
||||||
datalayer.battery2.status.max_discharge_power_W = 5000; // 5kW
|
|
||||||
|
|
||||||
datalayer.battery2.status.max_charge_power_W = 5000; // 5kW
|
|
||||||
|
|
||||||
for (int i = 0; i < 97; ++i) {
|
|
||||||
datalayer.battery2.status.cell_voltages_mV[i] = 3700 + random(-20, 21);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Fake that we get CAN messages
|
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
|
|
||||||
/*Finally print out values to serial if configured to do so*/
|
|
||||||
#ifdef DEBUG_LOG
|
|
||||||
logging.println("FAKE Values battery 2 going to inverter");
|
|
||||||
print_units("SOH 2 %: ", (datalayer.battery2.status.soh_pptt * 0.01), "% ");
|
|
||||||
print_units(", SOC 2 %: ", (datalayer.battery2.status.reported_soc * 0.01), "% ");
|
|
||||||
print_units(", Voltage 2: ", (datalayer.battery2.status.voltage_dV * 0.1), "V ");
|
|
||||||
print_units(", Max discharge power 2: ", datalayer.battery2.status.max_discharge_power_W, "W ");
|
|
||||||
print_units(", Max charge power 2: ", datalayer.battery2.status.max_charge_power_W, "W ");
|
|
||||||
print_units(", Max temp 2: ", (datalayer.battery2.status.temperature_max_dC * 0.1), "°C ");
|
|
||||||
print_units(", Min temp 2: ", (datalayer.battery2.status.temperature_min_dC * 0.1), "°C ");
|
|
||||||
print_units(", Max cell voltage 2: ", datalayer.battery2.status.cell_max_voltage_mV, "mV ");
|
|
||||||
print_units(", Min cell voltage 2: ", datalayer.battery2.status.cell_min_voltage_mV, "mV ");
|
|
||||||
logging.println("");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
void TestFakeBattery::transmit_can(unsigned long currentMillis) {
|
||||||
datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
}
|
|
||||||
#endif // DOUBLE_BATTERY
|
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
}
|
|
||||||
void transmit_can_battery(unsigned long currentMillis) {
|
|
||||||
// Send 100ms CAN Message
|
// Send 100ms CAN Message
|
||||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||||
previousMillis100 = currentMillis;
|
previousMillis100 = currentMillis;
|
||||||
// Put fake messages here incase you want to test sending CAN
|
// Put fake messages here incase you want to test sending CAN
|
||||||
//transmit_can_frame(&TEST, can_config.battery);
|
//transmit_can_frame(&TEST, can_interface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_battery(void) { // Performs one time setup at startup
|
void TestFakeBattery::setup(void) { // Performs one time setup at startup
|
||||||
randomSeed(analogRead(0));
|
randomSeed(analogRead(0));
|
||||||
|
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Fake battery for testing purposes", 63);
|
strncpy(datalayer.system.info.battery_protocol, "Fake battery for testing purposes", 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
|
|
||||||
datalayer.battery.info.max_design_voltage_dV =
|
datalayer_battery->info.max_design_voltage_dV =
|
||||||
4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||||
datalayer.battery.info.min_design_voltage_dV = 2450; // 245.0V under this, discharging further is disabled
|
datalayer_battery->info.min_design_voltage_dV = 2450; // 245.0V under this, discharging further is disabled
|
||||||
datalayer.battery.info.number_of_cells = 96;
|
datalayer_battery->info.number_of_cells = 96;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
|
||||||
|
if (allows_contactor_closing) {
|
||||||
|
*allows_contactor_closing = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,11 +1,50 @@
|
||||||
#ifndef TEST_FAKE_BATTERY_H
|
#ifndef TEST_FAKE_BATTERY_H
|
||||||
#define TEST_FAKE_BATTERY_H
|
#define TEST_FAKE_BATTERY_H
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
#define MAX_CELL_DEVIATION_MV 9999
|
#define SELECTED_BATTERY_CLASS TestFakeBattery
|
||||||
|
|
||||||
void setup_battery(void);
|
class TestFakeBattery : public CanBattery {
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
public:
|
||||||
|
// Use this constructor for the second battery.
|
||||||
|
TestFakeBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, int targetCan) {
|
||||||
|
datalayer_battery = datalayer_ptr;
|
||||||
|
can_interface = targetCan;
|
||||||
|
allows_contactor_closing = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the default constructor to create the first or single battery.
|
||||||
|
TestFakeBattery() {
|
||||||
|
datalayer_battery = &datalayer.battery;
|
||||||
|
can_interface = can_config.battery;
|
||||||
|
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void setup();
|
||||||
|
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;
|
||||||
|
int can_interface;
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
|
static const int MAX_CELL_DEVIATION_MV = 9999;
|
||||||
|
|
||||||
|
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
|
||||||
|
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||||
|
unsigned long previousMillis10s = 0; // will store last time a 1s CAN Message was send
|
||||||
|
|
||||||
|
CAN_frame TEST = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x123,
|
||||||
|
.data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}};
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -225,7 +225,7 @@ void handle_contactors() {
|
||||||
|
|
||||||
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
||||||
void handle_contactors_battery2() {
|
void handle_contactors_battery2() {
|
||||||
if ((contactorStatus == COMPLETED) && datalayer.system.status.battery2_allows_contactor_closing) {
|
if ((contactorStatus == COMPLETED) && datalayer.system.status.battery2_allowed_contactor_closing) {
|
||||||
set(SECOND_NEGATIVE_CONTACTOR_PIN, ON);
|
set(SECOND_NEGATIVE_CONTACTOR_PIN, ON);
|
||||||
set(SECOND_POSITIVE_CONTACTOR_PIN, ON);
|
set(SECOND_POSITIVE_CONTACTOR_PIN, ON);
|
||||||
datalayer.system.status.contactors_battery2_engaged = true;
|
datalayer.system.status.contactors_battery2_engaged = true;
|
||||||
|
|
|
@ -297,10 +297,12 @@ typedef struct {
|
||||||
* we report the inverter as missing entirely on the CAN bus.
|
* we report the inverter as missing entirely on the CAN bus.
|
||||||
*/
|
*/
|
||||||
uint8_t CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
uint8_t CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
||||||
/** True if the battery allows for the contactors to close */
|
/** True if the primary battery allows for the contactors to close */
|
||||||
bool battery_allows_contactor_closing = false;
|
bool battery_allows_contactor_closing = false;
|
||||||
/** True if the second battery allows for the contactors to close */
|
|
||||||
bool battery2_allows_contactor_closing = false;
|
/** True if the second battery is allowed to close the contactors */
|
||||||
|
bool battery2_allowed_contactor_closing = false;
|
||||||
|
|
||||||
/** True if the inverter allows for the contactors to close */
|
/** True if the inverter allows for the contactors to close */
|
||||||
bool inverter_allows_contactor_closing = true;
|
bool inverter_allows_contactor_closing = true;
|
||||||
#ifdef CONTACTOR_CONTROL
|
#ifdef CONTACTOR_CONTROL
|
||||||
|
|
|
@ -294,6 +294,33 @@ typedef struct {
|
||||||
uint64_t cumulative_energy_in_regen = 0;
|
uint64_t cumulative_energy_in_regen = 0;
|
||||||
} DATALAYER_INFO_CMFAEV;
|
} DATALAYER_INFO_CMFAEV;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/** uint8_t */
|
||||||
|
/** Battery software/hardware/serial versions, stores raw HEX values for ASCII chars */
|
||||||
|
uint8_t BatterySoftwareVersion[16] = {0};
|
||||||
|
uint8_t BatteryHardwareVersion[16] = {0};
|
||||||
|
uint8_t BatterySerialNumber[28] = {0};
|
||||||
|
/** int16_t */
|
||||||
|
/** Module temperatures 1-6 */
|
||||||
|
int16_t ModuleTemperatures[6] = {0};
|
||||||
|
/** uint16_t */
|
||||||
|
/** Various values polled via OBD2 PIDs */
|
||||||
|
uint16_t soc = 0;
|
||||||
|
uint16_t CC2voltage = 0;
|
||||||
|
uint16_t cellMaxVoltageNumber = 0;
|
||||||
|
uint16_t cellMinVoltageNumber = 0;
|
||||||
|
uint16_t cellTotalAmount = 0;
|
||||||
|
uint16_t specificialVoltage = 0;
|
||||||
|
uint16_t unknown1 = 0;
|
||||||
|
uint16_t rawSOCmax = 0;
|
||||||
|
uint16_t rawSOCmin = 0;
|
||||||
|
uint16_t unknown4 = 0;
|
||||||
|
uint16_t capModMax = 0;
|
||||||
|
uint16_t capModMin = 0;
|
||||||
|
uint16_t unknown7 = 0;
|
||||||
|
uint16_t unknown8 = 0;
|
||||||
|
} DATALAYER_INFO_GEELY_GEOMETRY_C;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t total_cell_count = 0;
|
uint8_t total_cell_count = 0;
|
||||||
int16_t battery_12V = 0;
|
int16_t battery_12V = 0;
|
||||||
|
@ -303,16 +330,6 @@ typedef struct {
|
||||||
uint8_t batteryManagementMode = 0;
|
uint8_t batteryManagementMode = 0;
|
||||||
uint8_t BMS_ign = 0;
|
uint8_t BMS_ign = 0;
|
||||||
uint8_t batteryRelay = 0;
|
uint8_t batteryRelay = 0;
|
||||||
#ifdef DOUBLE_BATTERY
|
|
||||||
uint8_t battery2_total_cell_count = 0;
|
|
||||||
int16_t battery2_battery_12V = 0;
|
|
||||||
uint8_t battery2_waterleakageSensor = 0;
|
|
||||||
int8_t battery2_temperature_water_inlet = 0;
|
|
||||||
int8_t battery2_powerRelayTemperature = 0;
|
|
||||||
uint8_t battery2_batteryManagementMode = 0;
|
|
||||||
uint8_t battery2_BMS_ign = 0;
|
|
||||||
uint8_t battery2_batteryRelay = 0;
|
|
||||||
#endif //DOUBLE BATTERY
|
|
||||||
} DATALAYER_INFO_KIAHYUNDAI64;
|
} DATALAYER_INFO_KIAHYUNDAI64;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -779,7 +796,9 @@ class DataLayerExtended {
|
||||||
DATALAYER_INFO_BYDATTO3 bydAtto3;
|
DATALAYER_INFO_BYDATTO3 bydAtto3;
|
||||||
DATALAYER_INFO_CELLPOWER cellpower;
|
DATALAYER_INFO_CELLPOWER cellpower;
|
||||||
DATALAYER_INFO_CMFAEV CMFAEV;
|
DATALAYER_INFO_CMFAEV CMFAEV;
|
||||||
|
DATALAYER_INFO_GEELY_GEOMETRY_C geometryC;
|
||||||
DATALAYER_INFO_KIAHYUNDAI64 KiaHyundai64;
|
DATALAYER_INFO_KIAHYUNDAI64 KiaHyundai64;
|
||||||
|
DATALAYER_INFO_KIAHYUNDAI64 KiaHyundai64_2;
|
||||||
DATALAYER_INFO_TESLA tesla;
|
DATALAYER_INFO_TESLA tesla;
|
||||||
DATALAYER_INFO_NISSAN_LEAF nissanleaf;
|
DATALAYER_INFO_NISSAN_LEAF nissanleaf;
|
||||||
DATALAYER_INFO_MEB meb;
|
DATALAYER_INFO_MEB meb;
|
||||||
|
|
|
@ -458,32 +458,67 @@ String advanced_battery_processor(const String& var) {
|
||||||
"<h4>Cumulative energy regen: " + String(datalayer_extended.CMFAEV.cumulative_energy_in_regen) + "Wh</h4>";
|
"<h4>Cumulative energy regen: " + String(datalayer_extended.CMFAEV.cumulative_energy_in_regen) + "Wh</h4>";
|
||||||
#endif //CMFA_EV_BATTERY
|
#endif //CMFA_EV_BATTERY
|
||||||
|
|
||||||
|
#ifdef GEELY_GEOMETRY_C_BATTERY
|
||||||
|
char readableSerialNumber[29]; // One extra space for null terminator
|
||||||
|
memcpy(readableSerialNumber, datalayer_extended.geometryC.BatterySerialNumber,
|
||||||
|
sizeof(datalayer_extended.geometryC.BatterySerialNumber));
|
||||||
|
readableSerialNumber[28] = '\0'; // Null terminate the string
|
||||||
|
char readableSoftwareVersion[17]; // One extra space for null terminator
|
||||||
|
memcpy(readableSoftwareVersion, datalayer_extended.geometryC.BatterySoftwareVersion,
|
||||||
|
sizeof(datalayer_extended.geometryC.BatterySoftwareVersion));
|
||||||
|
readableSoftwareVersion[16] = '\0'; // Null terminate the string
|
||||||
|
char readableHardwareVersion[17]; // One extra space for null terminator
|
||||||
|
memcpy(readableHardwareVersion, datalayer_extended.geometryC.BatteryHardwareVersion,
|
||||||
|
sizeof(datalayer_extended.geometryC.BatteryHardwareVersion));
|
||||||
|
readableHardwareVersion[16] = '\0'; // Null terminate the string
|
||||||
|
content += "<h4>Serial number: " + String(readableSoftwareVersion) + "</h4>";
|
||||||
|
content += "<h4>Software version: " + String(readableSerialNumber) + "</h4>";
|
||||||
|
content += "<h4>Hardware version: " + String(readableHardwareVersion) + "</h4>";
|
||||||
|
content += "<h4>SOC display: " + String(datalayer_extended.geometryC.soc) + "ppt</h4>";
|
||||||
|
content += "<h4>CC2 voltage: " + String(datalayer_extended.geometryC.CC2voltage) + "mV</h4>";
|
||||||
|
content += "<h4>Cell max voltage number: " + String(datalayer_extended.geometryC.cellMaxVoltageNumber) + "</h4>";
|
||||||
|
content += "<h4>Cell min voltage number: " + String(datalayer_extended.geometryC.cellMinVoltageNumber) + "</h4>";
|
||||||
|
content += "<h4>Cell total amount: " + String(datalayer_extended.geometryC.cellTotalAmount) + "S</h4>";
|
||||||
|
content += "<h4>Specificial Voltage: " + String(datalayer_extended.geometryC.specificialVoltage) + "dV</h4>";
|
||||||
|
content += "<h4>Unknown1: " + String(datalayer_extended.geometryC.unknown1) + "</h4>";
|
||||||
|
content += "<h4>Raw SOC max: " + String(datalayer_extended.geometryC.rawSOCmax) + "</h4>";
|
||||||
|
content += "<h4>Raw SOC min: " + String(datalayer_extended.geometryC.rawSOCmin) + "</h4>";
|
||||||
|
content += "<h4>Unknown4: " + String(datalayer_extended.geometryC.unknown4) + "</h4>";
|
||||||
|
content += "<h4>Capacity module max: " + String((datalayer_extended.geometryC.capModMax / 10)) + "Ah</h4>";
|
||||||
|
content += "<h4>Capacity module min: " + String((datalayer_extended.geometryC.capModMin / 10)) + "Ah</h4>";
|
||||||
|
content += "<h4>Unknown7: " + String(datalayer_extended.geometryC.unknown7) + "</h4>";
|
||||||
|
content += "<h4>Unknown8: " + String(datalayer_extended.geometryC.unknown8) + "</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 1 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[0]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 2 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[1]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 3 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[2]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 4 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[3]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 5 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[4]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 6 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[5]) + " °C</h4>";
|
||||||
|
#endif //GEELY_GEOMETRY_C_BATTERY
|
||||||
|
|
||||||
#ifdef KIA_HYUNDAI_64_BATTERY
|
#ifdef KIA_HYUNDAI_64_BATTERY
|
||||||
content += "<h4>Cells: " + String(datalayer_extended.KiaHyundai64.total_cell_count) + "S</h4>";
|
auto print_hyundai = [&content](DATALAYER_INFO_KIAHYUNDAI64& data) {
|
||||||
content += "<h4>12V voltage: " + String(datalayer_extended.KiaHyundai64.battery_12V / 10.0, 1) + "</h4>";
|
content += "<h4>Cells: " + String(data.total_cell_count) + "S</h4>";
|
||||||
content += "<h4>Waterleakage: " + String(datalayer_extended.KiaHyundai64.waterleakageSensor) + "</h4>";
|
content += "<h4>12V voltage: " + String(data.battery_12V / 10.0, 1) + "</h4>";
|
||||||
content +=
|
content += "<h4>Waterleakage: " + String(data.waterleakageSensor) + "</h4>";
|
||||||
"<h4>Temperature, water inlet: " + String(datalayer_extended.KiaHyundai64.temperature_water_inlet) + "</h4>";
|
content += "<h4>Temperature, water inlet: " + String(data.temperature_water_inlet) + "</h4>";
|
||||||
content +=
|
content += "<h4>Temperature, power relay: " + String(data.powerRelayTemperature) + "</h4>";
|
||||||
"<h4>Temperature, power relay: " + String(datalayer_extended.KiaHyundai64.powerRelayTemperature) + "</h4>";
|
content += "<h4>Batterymanagement mode: " + String(data.batteryManagementMode) + "</h4>";
|
||||||
content += "<h4>Batterymanagement mode: " + String(datalayer_extended.KiaHyundai64.batteryManagementMode) + "</h4>";
|
content += "<h4>BMS ignition: " + String(data.BMS_ign) + "</h4>";
|
||||||
content += "<h4>BMS ignition: " + String(datalayer_extended.KiaHyundai64.BMS_ign) + "</h4>";
|
content += "<h4>Battery relay: " + String(data.batteryRelay) + "</h4>";
|
||||||
content += "<h4>Battery relay: " + String(datalayer_extended.KiaHyundai64.batteryRelay) + "</h4>";
|
};
|
||||||
|
|
||||||
|
print_hyundai(datalayer_extended.KiaHyundai64);
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
content += "<h4>Values from battery 2</h4>";
|
content += "<h4>Values from battery 2</h4>";
|
||||||
content += "<h4>Cells: " + String(datalayer_extended.KiaHyundai64.battery2_total_cell_count) + "S</h4>";
|
print_hyundai(datalayer_extended.KiaHyundai64_2);
|
||||||
content += "<h4>12V voltage: " + String(datalayer_extended.KiaHyundai64.battery2_battery_12V / 10.0, 1) + "</h4>";
|
|
||||||
content += "<h4>Waterleakage: " + String(datalayer_extended.KiaHyundai64.battery2_waterleakageSensor) + "</h4>";
|
|
||||||
content +=
|
|
||||||
"<h4>Temperature, water inlet: " + String(datalayer_extended.KiaHyundai64.battery2_temperature_water_inlet) +
|
|
||||||
"</h4>";
|
|
||||||
content +=
|
|
||||||
"<h4>Temperature, power relay: " + String(datalayer_extended.KiaHyundai64.battery2_powerRelayTemperature) +
|
|
||||||
"</h4>";
|
|
||||||
content += "<h4>Batterymanagement mode: " + String(datalayer_extended.KiaHyundai64.battery2_batteryManagementMode) +
|
|
||||||
"</h4>";
|
|
||||||
content += "<h4>BMS ignition: " + String(datalayer_extended.KiaHyundai64.battery2_BMS_ign) + "</h4>";
|
|
||||||
content += "<h4>Battery relay: " + String(datalayer_extended.KiaHyundai64.battery2_batteryRelay) + "</h4>";
|
|
||||||
#endif //DOUBLE_BATTERY
|
#endif //DOUBLE_BATTERY
|
||||||
#endif //KIA_HYUNDAI_64_BATTERY
|
#endif //KIA_HYUNDAI_64_BATTERY
|
||||||
|
|
||||||
|
@ -1489,7 +1524,8 @@ String advanced_battery_processor(const String& var) {
|
||||||
!defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_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(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \
|
||||||
!defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \
|
!defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \
|
||||||
!defined(KIA_HYUNDAI_64_BATTERY) && !defined(CMFA_EV_BATTERY) //Only the listed types have extra info
|
!defined(KIA_HYUNDAI_64_BATTERY) && !defined(GEELY_GEOMETRY_C_BATTERY) && \
|
||||||
|
!defined(CMFA_EV_BATTERY) //Only the listed types have extra info
|
||||||
content += "No extra information available for this battery type";
|
content += "No extra information available for this battery type";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1379,7 +1379,7 @@ String processor(const String& var) {
|
||||||
|
|
||||||
content += "<h4>Automatic contactor closing allowed:</h4>";
|
content += "<h4>Automatic contactor closing allowed:</h4>";
|
||||||
content += "<h4>Battery: ";
|
content += "<h4>Battery: ";
|
||||||
if (datalayer.system.status.battery2_allows_contactor_closing == true) {
|
if (datalayer.system.status.battery2_allowed_contactor_closing == true) {
|
||||||
content += "<span>✓</span>";
|
content += "<span>✓</span>";
|
||||||
} else {
|
} else {
|
||||||
content += "<span style='color: red;'>✕</span>";
|
content += "<span style='color: red;'>✕</span>";
|
||||||
|
|
|
@ -73,7 +73,7 @@ void wifi_monitor() {
|
||||||
#endif
|
#endif
|
||||||
// Try WiFi.reconnect() if it was successfully connected at least once
|
// Try WiFi.reconnect() if it was successfully connected at least once
|
||||||
if (hasConnectedBefore) {
|
if (hasConnectedBefore) {
|
||||||
lastReconnectAttempt = millis(); // Reset reconnection attempt timer
|
lastReconnectAttempt = currentMillis; // Reset reconnection attempt timer
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.println("Wi-Fi reconnect attempt...");
|
logging.println("Wi-Fi reconnect attempt...");
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue