Battery-Emulator/Software/src/battery/TESLA-BATTERY.cpp
2025-09-04 20:26:17 +03:00

2640 lines
138 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "TESLA-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" //For Advanced Battery Insights webpage
#include "../devboard/utils/events.h"
#include "../devboard/utils/logging.h"
/* Credits: */
/* Some of the original CAN frame parsing code below comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */
/* Most of the additional CAN frame parsing/information/display comes from Josiah Higgs (https://github.com/josiahhiggs/) */
inline const char* getContactorText(int index) {
switch (index) {
case 0:
return "UNKNOWN(0)";
case 1:
return "OPEN";
case 2:
return "CLOSING";
case 3:
return "BLOCKED";
case 4:
return "OPENING";
case 5:
return "CLOSED";
case 6:
return "UNKNOWN(6)";
case 7:
return "WELDED";
case 8:
return "POS_CL";
case 9:
return "NEG_CL";
case 10:
return "UNKNOWN(10)";
case 11:
return "UNKNOWN(11)";
case 12:
return "UNKNOWN(12)";
default:
return "UNKNOWN";
}
}
inline const char* getContactorState(int index) {
switch (index) {
case 0:
return "SNA";
case 1:
return "OPEN";
case 2:
return "PRECHARGE";
case 3:
return "BLOCKED";
case 4:
return "PULLED_IN";
case 5:
return "OPENING";
case 6:
return "ECONOMIZED";
case 7:
return "WELDED";
case 8:
return "UNKNOWN(8)";
case 9:
return "UNKNOWN(9)";
case 10:
return "UNKNOWN(10)";
case 11:
return "UNKNOWN(11)";
default:
return "UNKNOWN";
}
}
inline const char* getHvilStatusState(int index) {
switch (index) {
case 0:
return "NOT OK";
case 1:
return "STATUS_OK";
case 2:
return "CURRENT_SOURCE_FAULT";
case 3:
return "INTERNAL_OPEN_FAULT";
case 4:
return "VEHICLE_OPEN_FAULT";
case 5:
return "PENTHOUSE_LID_OPEN_FAULT";
case 6:
return "UNKNOWN_LOCATION_OPEN_FAULT";
case 7:
return "VEHICLE_NODE_FAULT";
case 8:
return "NO_12V_SUPPLY";
case 9:
return "VEHICLE_OR_PENTHOUSE_LID_OPENFAULT";
case 10:
return "UNKNOWN(10)";
case 11:
return "UNKNOWN(11)";
case 12:
return "UNKNOWN(12)";
case 13:
return "UNKNOWN(13)";
case 14:
return "UNKNOWN(14)";
case 15:
return "UNKNOWN(15)";
default:
return "UNKNOWN";
}
}
inline const char* getBMSState(int index) {
switch (index) {
case 0:
return "STANDBY";
case 1:
return "DRIVE";
case 2:
return "SUPPORT";
case 3:
return "CHARGE";
case 4:
return "FEIM";
case 5:
return "CLEAR_FAULT";
case 6:
return "FAULT";
case 7:
return "WELD";
case 8:
return "TEST";
case 9:
return "SNA";
default:
return "UNKNOWN";
}
}
inline const char* getBMSContactorState(int index) {
switch (index) {
case 0:
return "SNA";
case 1:
return "OPEN";
case 2:
return "OPENING";
case 3:
return "CLOSING";
case 4:
return "CLOSED";
case 5:
return "WELDED";
case 6:
return "BLOCKED";
default:
return "UNKNOWN";
}
}
inline const char* getBMSHvState(int index) {
switch (index) {
case 0:
return "DOWN";
case 1:
return "COMING_UP";
case 2:
return "GOING_DOWN";
case 3:
return "UP_FOR_DRIVE";
case 4:
return "UP_FOR_CHARGE";
case 5:
return "UP_FOR_DC_CHARGE";
case 6:
return "UP";
default:
return "UNKNOWN";
}
}
inline const char* getBMSUiChargeStatus(int index) {
switch (index) {
case 0:
return "DISCONNECTED";
case 1:
return "NO_POWER";
case 2:
return "ABOUT_TO_CHARGE";
case 3:
return "CHARGING";
case 4:
return "CHARGE_COMPLETE";
case 5:
return "CHARGE_STOPPED";
default:
return "UNKNOWN";
}
}
inline const char* getPCS_DcdcStatus(int index) {
switch (index) {
case 0:
return "IDLE";
case 1:
return "ACTIVE";
case 2:
return "FAULTED";
default:
return "UNKNOWN";
}
}
inline const char* getPCS_DcdcMainState(int index) {
switch (index) {
case 0:
return "STANDBY";
case 1:
return "12V_SUPPORT_ACTIVE";
case 2:
return "PRECHARGE_STARTUP";
case 3:
return "PRECHARGE_ACTIVE";
case 4:
return "DIS_HVBUS_ACTIVE";
case 5:
return "SHUTDOWN";
case 6:
return "FAULTED";
default:
return "UNKNOWN";
}
}
inline const char* getPCS_DcdcSubState(int index) {
switch (index) {
case 0:
return "PWR_UP_INIT";
case 1:
return "STANDBY";
case 2:
return "12V_SUPPORT_ACTIVE";
case 3:
return "DIS_HVBUS";
case 4:
return "PCHG_FAST_DIS_HVBUS";
case 5:
return "PCHG_SLOW_DIS_HVBUS";
case 6:
return "PCHG_DWELL_CHARGE";
case 7:
return "PCHG_DWELL_WAIT";
case 8:
return "PCHG_DI_RECOVERY_WAIT";
case 9:
return "PCHG_ACTIVE";
case 10:
return "PCHG_FLT_FAST_DIS_HVBUS";
case 11:
return "SHUTDOWN";
case 12:
return "12V_SUPPORT_FAULTED";
case 13:
return "DIS_HVBUS_FAULTED";
case 14:
return "PCHG_FAULTED";
case 15:
return "CLEAR_FAULTS";
case 16:
return "FAULTED";
case 17:
return "NUM";
default:
return "UNKNOWN";
}
}
inline const char* getBMSPowerLimitState(int index) {
switch (index) {
case 0:
return "NOT_CALCULATED_FOR_DRIVE";
case 1:
return "CALCULATED_FOR_DRIVE";
default:
return "UNKNOWN";
}
}
inline const char* getHVPStatus(int index) {
switch (index) {
case 0:
return "INVALID";
case 1:
return "NOT_AVAILABLE";
case 2:
return "STALE";
case 3:
return "VALID";
default:
return "UNKNOWN";
}
}
inline const char* getHVPContactor(int index) {
switch (index) {
case 0:
return "NOT_ACTIVE";
case 1:
return "ACTIVE";
case 2:
return "COMPLETED";
default:
return "UNKNOWN";
}
}
inline const char* getFalseTrue(bool value) {
return value ? "True" : "False";
}
inline const char* getNoYes(bool value) {
return value ? "Yes" : "No";
}
inline const char* getFault(bool value) {
return value ? "ACTIVE" : "NOT_ACTIVE";
}
// Clamp DLC to 08 bytes for classic CAN
inline int getDataLen(uint8_t dlc) {
return std::min<int>(dlc, 8);
}
// Fast bitfield writer: writes 'bitLen' bits of 'value' starting at 'startBit'
inline void setBitField(uint8_t* data, int bytes, int startBit, int bitLen, uint64_t value) {
int bit = startBit;
for (int i = 0; i < bitLen && bit < bytes * 8; ++i, ++bit) {
uint8_t* p = data + (bit >> 3);
uint8_t m = uint8_t(1u << (bit & 7));
*p = (*p & ~m) | (uint8_t((value >> i) & 1) << (bit & 7));
}
}
/// Increment a counter field and recompute an 8bit checksum as part of a mux
void generateMuxFrameCounterChecksum(CAN_frame& f,
uint8_t frameCounter, // counter value
int ctrStartBit, // bit index of counter LSB
int ctrBitLength, // width of counter in bits
int csumStartBit, // bit index of checksum LSB
int csumBitLength // width of checksum in bits
) {
int bytes = getDataLen(f.DLC);
auto data = f.data.u8;
// Pack payload into a 64bit word
uint64_t w = 0;
for (uint8_t i = 0; i < bytes; ++i) {
w |= uint64_t(data[i]) << (8 * i);
}
// Increment the counter
{
uint64_t mask = (uint64_t(1) << ctrBitLength) - 1;
uint64_t ctr = frameCounter & mask; // External counter 0-15
w = (w & ~(mask << ctrStartBit)) | (ctr << ctrStartBit);
}
// Unpack back into the frame bytes
for (uint8_t i = 0; i < bytes; ++i) {
data[i] = uint8_t((w >> (8 * i)) & 0xFF);
}
// Build a small buffer and zero out the checksum bits
uint8_t buf[8];
for (uint8_t i = 0; i < bytes; ++i) {
buf[i] = data[i];
}
for (int bit = csumStartBit; bit < csumStartBit + csumBitLength; ++bit) {
int b = bit >> 3;
if (b >= bytes)
break;
buf[b] &= uint8_t(~(1u << (bit & 7)));
}
// Compute checksum offset from most significant hex digit of CAN ID
uint8_t checksum_offset = uint8_t((f.ID >> 8) & 0xF); // high nibble of top byte
// Sum the low byte of ID + buf[]
uint8_t sum = uint8_t(f.ID & 0xFF);
for (int i = 0; i < bytes; ++i) {
sum = uint8_t(sum + buf[i]);
}
uint8_t checksum = uint8_t(sum + checksum_offset);
// Write the checksum back into the frame
setBitField(data, bytes, csumStartBit, csumBitLength, checksum);
}
// Increment a counter field and recompute an 8bit checksum
void generateFrameCounterChecksum(CAN_frame& f,
int ctrStartBit, // bit index of counter LSB
int ctrBitLength, // width of counter in bits
int csumStartBit, // bit index of checksum LSB
int csumBitLength // width of checksum in bits
) {
int bytes = getDataLen(f.DLC);
auto data = f.data.u8;
// Pack payload into a 64bit word
uint64_t w = 0;
for (int i = 0; i < bytes; ++i) {
w |= uint64_t(data[i]) << (8 * i);
}
// Increment the counter by +1 modulo its width
{
uint64_t mask = (uint64_t(1) << ctrBitLength) - 1;
uint64_t ctr = ((w >> ctrStartBit) & mask) + 1;
ctr &= mask;
w = (w & ~(mask << ctrStartBit)) | (ctr << ctrStartBit);
}
// Unpack back into the frame bytes
for (int i = 0; i < bytes; ++i) {
data[i] = uint8_t((w >> (8 * i)) & 0xFF);
}
// Build a small buffer and zero out the checksum bits
uint8_t buf[8];
for (int i = 0; i < bytes; ++i) {
buf[i] = data[i];
}
for (int bit = csumStartBit; bit < csumStartBit + csumBitLength; ++bit) {
int b = bit >> 3;
if (b >= bytes)
break;
buf[b] &= uint8_t(~(1u << (bit & 7)));
}
// Compute checksum offset from most significant hex digit of CAN ID
uint8_t checksum_offset = uint8_t((f.ID >> 8) & 0xF); // high nibble of top byte
// Sum the low byte of ID + buf[]
uint8_t sum = uint8_t(f.ID & 0xFF);
for (int i = 0; i < bytes; ++i) {
sum = uint8_t(sum + buf[i]);
}
uint8_t checksum = uint8_t(sum + checksum_offset);
// Write the checksum back into the frame
setBitField(data, bytes, csumStartBit, csumBitLength, checksum);
}
// Function to extract raw bits/values from a given CAN frame signal
inline uint64_t extract_signal_value(const uint8_t* data, uint32_t start_bit, uint32_t bit_length) {
//
// Usage: uint8_t bms_state = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 31, 4));
//
// Calculate the starting byte and bit offset
uint32_t byte_index = start_bit / 8;
uint32_t bit_offset = start_bit % 8;
// Read up to 8 bytes starting from byte_index (need enough to cover bit_length + bit_offset)
uint64_t raw = 0;
for (int i = 0; i < 8 && (byte_index + i) < 64; ++i) {
raw |= (uint64_t)data[byte_index + i] << (8 * i);
}
// Shift and mask
raw >>= bit_offset;
if (bit_length == 64)
return raw;
return raw & ((1ULL << bit_length) - 1);
}
// Function to write a value to a given CAN frame signal
void write_signal_value(CAN_frame* frame, uint16_t start_bit, uint8_t bit_length, int64_t value, bool is_signed) {
if (bit_length == 0 || bit_length > 64 || frame == nullptr)
return;
uint64_t uvalue;
if (is_signed) {
int64_t min_val = -(1LL << (bit_length - 1));
int64_t max_val = (1LL << (bit_length - 1)) - 1;
// Clamp to valid range
if (value < min_val)
value = min_val;
if (value > max_val)
value = max_val;
// Two's complement encoding
uvalue = static_cast<uint64_t>(value) & ((1ULL << bit_length) - 1);
} else {
uvalue = static_cast<uint64_t>(value) & ((1ULL << bit_length) - 1);
}
// Write value into frame->data.u8 using little-endian bit layout
for (uint8_t i = 0; i < bit_length; ++i) {
uint8_t bit_val = (uvalue >> i) & 1;
uint16_t bit_pos = start_bit + i;
uint8_t byte_index = bit_pos / 8;
uint8_t bit_index = bit_pos % 8;
if (byte_index >= frame->DLC)
continue; // Prevent overrun
if (bit_val)
frame->data.u8[byte_index] |= (1 << bit_index);
else
frame->data.u8[byte_index] &= ~(1 << bit_index);
}
}
void generateTESLA_229(CAN_frame& f) {
static const uint8_t checksumLookup[16] = {0x46, 0x44, 0x52, 0x6D, 0x43, 0x41, 0xDD, 0xF9,
0x4C, 0xA5, 0xF6, 0x8C, 0x49, 0x2F, 0x31, 0x3B};
// Safety, only run if this is the right ID
if (f.ID != 0x229)
return;
const int ctrStartBit = 8;
const int ctrBitLength = 4;
const int csumStartBit = 0;
const int csumBitLength = 8;
int bytes = getDataLen(f.DLC);
auto data = f.data.u8;
// Pack the first few bytes into a word
uint64_t w = 0;
for (int i = 0; i < bytes; ++i) {
w |= uint64_t(data[i]) << (8 * i);
}
// Extract current counter
uint64_t mask = (uint64_t(1) << ctrBitLength) - 1;
uint8_t ctr = (w >> ctrStartBit) & mask;
// Increment counter mod 16
ctr = (ctr + 1) & 0xF;
// Write updated counter back
w = (w & ~(mask << ctrStartBit)) | (uint64_t(ctr) << ctrStartBit);
for (int i = 0; i < bytes; ++i) {
data[i] = uint8_t((w >> (8 * i)) & 0xFF);
}
// Look up and insert checksum
uint8_t checksum = checksumLookup[ctr];
setBitField(data, bytes, csumStartBit, csumBitLength, checksum);
}
void generateTESLA_213(CAN_frame& f) {
static uint8_t counter = 0;
// Increment counter (wrap at 16)
counter = (counter + 1) & 0xF;
// Safety, only modify if ID is 0x213 and DLC is at least 2
if (f.ID != 0x213 || f.DLC < 2)
return;
// Byte 0: counter in high nibble
uint8_t value = counter << 4;
// Byte 1: checksum = value + 0x15
uint8_t checksum = (value + 0x15) & 0xFF;
f.data.u8[0] = value;
f.data.u8[1] = checksum;
}
// Function to check if a year is a leap year
bool isLeapYear(int year) {
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
return true;
}
return false;
}
// Function to convert year and day of year (i.e. Julian date) into human readable date
char* dayOfYearToDate(int year, int dayOfYear) {
// Arrays to hold the number of days in each month for standard/leap years
int daysInMonthStandard[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int daysInMonthLeap[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// Select the appropriate array for the given year
int* daysInMonth = isLeapYear(year) ? daysInMonthLeap : daysInMonthStandard;
int month = 0;
// Find the month and the day within the month
while (dayOfYear > daysInMonth[month]) {
dayOfYear -= daysInMonth[month];
month++;
}
static char dateString[11]; // For "YYYY-MM-DD\0"
// Format the date string in "YYYY-MM-DD" format
snprintf(dateString, sizeof(dateString), "%d-%02d-%02d", year, month + 1, dayOfYear);
return dateString;
}
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
datalayer.battery.status.soh_pptt = 9900; //Tesla batteries do not send a SOH% value on bus. Hardcode to 99%
datalayer.battery.status.real_soc = (battery_soc_ui * 10); //increase SOC range from 0-100.0 -> 100.00
datalayer.battery.status.voltage_dV = battery_volts;
datalayer.battery.status.current_dA = battery_amps; //13.0A
//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);
// Define the allowed discharge power
datalayer.battery.status.max_discharge_power_W = (battery_max_discharge_current * (battery_volts / 10));
// Cap the allowed discharge power if higher than the maximum discharge power allowed
if (datalayer.battery.status.max_discharge_power_W > datalayer.battery.status.override_discharge_power_W) {
datalayer.battery.status.max_discharge_power_W = datalayer.battery.status.override_discharge_power_W;
}
//The allowed charge power behaves strangely. We instead estimate this value
if (battery_soc_ui > 990) {
datalayer.battery.status.max_charge_power_W = FLOAT_MAX_POWER_W;
} else if (battery_soc_ui >
RAMPDOWN_SOC) { // When real SOC is between RAMPDOWN_SOC-99%, ramp the value between Max<->0
datalayer.battery.status.max_charge_power_W =
RAMPDOWNPOWERALLOWED * (1 - (battery_soc_ui - RAMPDOWN_SOC) / (1000.0 - RAMPDOWN_SOC));
//If the cellvoltages start to reach overvoltage, only allow a small amount of power in
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
if (battery_cell_max_v > (MAX_CELL_VOLTAGE_LFP - FLOAT_START_MV)) {
datalayer.battery.status.max_charge_power_W = FLOAT_MAX_POWER_W;
}
} else { //NCM/A
if (battery_cell_max_v > (MAX_CELL_VOLTAGE_NCA_NCM - FLOAT_START_MV)) {
datalayer.battery.status.max_charge_power_W = FLOAT_MAX_POWER_W;
}
}
} else { // No limits, max charging power allowed
datalayer.battery.status.max_charge_power_W = datalayer.battery.status.override_charge_power_W;
}
datalayer.battery.status.temperature_min_dC = battery_min_temp;
datalayer.battery.status.temperature_max_dC = battery_max_temp;
datalayer.battery.status.cell_max_voltage_mV = battery_cell_max_v;
datalayer.battery.status.cell_min_voltage_mV = battery_cell_min_v;
battery_cell_deviation_mV = (battery_cell_max_v - battery_cell_min_v);
/* Value mapping is completed. Start to check all safeties */
//INTERNAL_OPEN_FAULT - Someone disconnected a high voltage cable while battery was in use
if (battery_hvil_status == 3) {
set_event(EVENT_INTERNAL_OPEN_FAULT, 0);
} else {
clear_event(EVENT_INTERNAL_OPEN_FAULT);
}
//Voltage between 0.5-5.0V, pyrofuse most likely blown
if (datalayer.battery.status.voltage_dV >= 5 && datalayer.battery.status.voltage_dV <= 50) {
set_event(EVENT_BATTERY_FUSE, 0);
} else {
clear_event(EVENT_BATTERY_FUSE);
}
if (user_selected_tesla_GTW_chassisType > 1) { //{{0, "Model S"}, {1, "Model X"}, {2, "Model 3"}, {3, "Model Y"}};
// Autodetect algoritm for chemistry on 3/Y packs.
// NCM/A batteries have 96s, LFP has 102-108s
// Drawback with this check is that it takes 3-5minutes before all cells have been counted!
if (datalayer.battery.info.number_of_cells > 101) {
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
}
//Once cell chemistry is determined, set maximum and minimum total pack voltage safety limits
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_LFP;
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_LFP;
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_LFP;
} else { // NCM/A chemistry
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_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;
}
// During forced balancing request via webserver, we allow the battery to exceed normal safety parameters
if (datalayer.battery.settings.user_requests_balancing) {
datalayer.battery.status.real_soc = 9900; //Force battery to show up as 99% when balancing
datalayer.battery.info.max_design_voltage_dV = datalayer.battery.settings.balancing_max_pack_voltage_dV;
datalayer.battery.info.max_cell_voltage_mV = datalayer.battery.settings.balancing_max_cell_voltage_mV;
datalayer.battery.info.max_cell_voltage_deviation_mV =
datalayer.battery.settings.balancing_max_deviation_cell_voltage_mV;
datalayer.battery.status.max_charge_power_W = datalayer.battery.settings.balancing_float_power_W;
}
}
// Check if user requests some action
if (datalayer.battery.settings.user_requests_tesla_isolation_clear) {
stateMachineClearIsolationFault = 0; //Start the isolation fault statemachine
datalayer.battery.settings.user_requests_tesla_isolation_clear = false;
}
if (datalayer.battery.settings.user_requests_tesla_bms_reset) {
if (battery_contactor == 1 && BMS_a180_SW_ECU_reset_blocked == false) {
//Start the BMS ECU reset statemachine, only if contactors are OPEN and BMS ECU allows it
stateMachineBMSReset = 0;
datalayer.battery.settings.user_requests_tesla_bms_reset = false;
logging.println("BMS reset requested");
} else {
logging.println("ERROR: BMS reset failed due to contactors not being open, or BMS ECU not allowing it");
stateMachineBMSReset = 0xFF;
datalayer.battery.settings.user_requests_tesla_bms_reset = false;
}
}
if (datalayer.battery.settings.user_requests_tesla_soc_reset) {
if (datalayer.battery.status.real_soc < 1500 || datalayer.battery.status.real_soc > 9000) {
//Start the SOC reset statemachine, only if SOC < 15% or > 90%
stateMachineSOCReset = 0;
datalayer.battery.settings.user_requests_tesla_soc_reset = false;
logging.println("SOC reset requested");
} else {
logging.println("ERROR: SOC reset failed due to SOC not being less than 15 or greater than 90");
stateMachineSOCReset = 0xFF;
datalayer.battery.settings.user_requests_tesla_soc_reset = false;
}
}
//Update 0x333 UI_chargeTerminationPct (bit 16, width 10) value to SOC max value - expose via UI?
//One firmware version this was seen at bit 17 width 11
write_signal_value(&TESLA_333, 16, 10, static_cast<int64_t>(datalayer.battery.settings.max_percentage / 10), false);
// Update webserver datalayer
//datalayer_extended.tesla.BMS_hvilFault = BMS_a036_SW_HvpHvilFault;
datalayer_extended.tesla.hvil_status = battery_hvil_status;
//0x20A
datalayer_extended.tesla.packContNegativeState = battery_packContNegativeState;
datalayer_extended.tesla.packContPositiveState = battery_packContPositiveState;
datalayer_extended.tesla.packContactorSetState = battery_packContactorSetState;
datalayer_extended.tesla.packCtrsClosingBlocked = battery_packCtrsClosingBlocked;
datalayer_extended.tesla.pyroTestInProgress = battery_pyroTestInProgress;
datalayer_extended.tesla.battery_packCtrsOpenNowRequested = battery_packCtrsOpenNowRequested;
datalayer_extended.tesla.battery_packCtrsOpenRequested = battery_packCtrsOpenRequested;
datalayer_extended.tesla.battery_packCtrsRequestStatus = battery_packCtrsRequestStatus;
datalayer_extended.tesla.battery_packCtrsResetRequestRequired = battery_packCtrsResetRequestRequired;
datalayer_extended.tesla.battery_dcLinkAllowedToEnergize = battery_dcLinkAllowedToEnergize;
//0x72A
if (parsed_battery_serialNumber && battery_serialNumber[13] != 0) {
memcpy(datalayer_extended.tesla.battery_serialNumber, battery_serialNumber, sizeof(battery_serialNumber));
datalayer_extended.tesla.battery_manufactureDate = battery_manufactureDate;
//We have valid data and comms with the battery, attempt to query part number
if (!parsed_battery_partNumber && stateMachineBMSQuery == 0xFF) {
stateMachineBMSQuery = 0;
}
}
//Via UDS
if (parsed_battery_partNumber && battery_partNumber[11] != 0) {
memcpy(datalayer_extended.tesla.battery_partNumber, battery_partNumber, sizeof(battery_partNumber));
}
//0x3C4
if (parsed_PCS_partNumber && PCS_partNumber[11] != 0) {
memcpy(datalayer_extended.tesla.PCS_partNumber, PCS_partNumber, sizeof(PCS_partNumber));
}
//0x2B4
datalayer_extended.tesla.battery_dcdcLvBusVolt = battery_dcdcLvBusVolt;
datalayer_extended.tesla.battery_dcdcHvBusVolt = battery_dcdcHvBusVolt;
datalayer_extended.tesla.battery_dcdcLvOutputCurrent = battery_dcdcLvOutputCurrent;
//0x352
datalayer_extended.tesla.BMS352_mux = BMS352_mux;
datalayer_extended.tesla.battery_nominal_full_pack_energy = battery_nominal_full_pack_energy;
datalayer_extended.tesla.battery_nominal_full_pack_energy_m0 = battery_nominal_full_pack_energy_m0;
datalayer_extended.tesla.battery_nominal_energy_remaining = battery_nominal_energy_remaining;
datalayer_extended.tesla.battery_nominal_energy_remaining_m0 = battery_nominal_energy_remaining_m0;
datalayer_extended.tesla.battery_ideal_energy_remaining = battery_ideal_energy_remaining;
datalayer_extended.tesla.battery_ideal_energy_remaining_m0 = battery_ideal_energy_remaining_m0;
datalayer_extended.tesla.battery_energy_to_charge_complete = battery_energy_to_charge_complete;
datalayer_extended.tesla.battery_energy_to_charge_complete_m1 = battery_energy_to_charge_complete_m1;
datalayer_extended.tesla.battery_energy_buffer = battery_energy_buffer;
datalayer_extended.tesla.battery_energy_buffer_m1 = battery_energy_buffer_m1;
datalayer_extended.tesla.battery_expected_energy_remaining_m1 = battery_expected_energy_remaining_m1;
datalayer_extended.tesla.battery_full_charge_complete = battery_full_charge_complete;
datalayer_extended.tesla.battery_fully_charged = battery_fully_charged;
//0x3D2
datalayer.battery.status.total_discharged_battery_Wh = battery_total_discharge;
datalayer.battery.status.total_charged_battery_Wh = battery_total_charge;
//0x392
datalayer_extended.tesla.battery_moduleType = battery_moduleType;
datalayer_extended.tesla.battery_packMass = battery_packMass;
datalayer_extended.tesla.battery_platformMaxBusVoltage = battery_platformMaxBusVoltage;
//0x2D2
datalayer_extended.tesla.BMS_min_voltage = BMS_min_voltage;
datalayer_extended.tesla.BMS_max_voltage = BMS_max_voltage;
datalayer_extended.tesla.battery_max_charge_current = battery_max_charge_current;
datalayer_extended.tesla.battery_max_discharge_current = battery_max_discharge_current;
//0x292
datalayer_extended.tesla.battery_beginning_of_life = battery_beginning_of_life;
datalayer_extended.tesla.battery_battTempPct = battery_battTempPct;
datalayer_extended.tesla.battery_soc_ave = battery_soc_ave;
datalayer_extended.tesla.battery_soc_max = battery_soc_max;
datalayer_extended.tesla.battery_soc_min = battery_soc_min;
datalayer_extended.tesla.battery_soc_ui = battery_soc_ui;
//0x332
datalayer_extended.tesla.battery_BrickVoltageMax = battery_BrickVoltageMax;
datalayer_extended.tesla.battery_BrickVoltageMin = battery_BrickVoltageMin;
datalayer_extended.tesla.battery_BrickTempMaxNum = battery_BrickTempMaxNum;
datalayer_extended.tesla.battery_BrickTempMinNum = battery_BrickTempMinNum;
datalayer_extended.tesla.battery_BrickModelTMax = battery_BrickModelTMax;
datalayer_extended.tesla.battery_BrickModelTMin = battery_BrickModelTMin;
//0x212
datalayer_extended.tesla.BMS_isolationResistance = BMS_isolationResistance;
datalayer_extended.tesla.BMS_contactorState = BMS_contactorState;
datalayer_extended.tesla.BMS_state = BMS_state;
datalayer_extended.tesla.BMS_hvState = BMS_hvState;
datalayer_extended.tesla.BMS_uiChargeStatus = BMS_uiChargeStatus;
datalayer_extended.tesla.BMS_diLimpRequest = BMS_diLimpRequest;
datalayer_extended.tesla.BMS_chgPowerAvailable = BMS_chgPowerAvailable;
datalayer_extended.tesla.BMS_pcsPwmEnabled = BMS_pcsPwmEnabled;
//0x224
datalayer_extended.tesla.PCS_dcdcPrechargeStatus = PCS_dcdcPrechargeStatus;
datalayer_extended.tesla.PCS_dcdc12VSupportStatus = PCS_dcdc12VSupportStatus;
datalayer_extended.tesla.PCS_dcdcHvBusDischargeStatus = PCS_dcdcHvBusDischargeStatus;
datalayer_extended.tesla.PCS_dcdcMainState = PCS_dcdcMainState;
datalayer_extended.tesla.PCS_dcdcSubState = PCS_dcdcSubState;
datalayer_extended.tesla.PCS_dcdcFaulted = PCS_dcdcFaulted;
datalayer_extended.tesla.PCS_dcdcOutputIsLimited = PCS_dcdcOutputIsLimited;
datalayer_extended.tesla.PCS_dcdcMaxOutputCurrentAllowed = PCS_dcdcMaxOutputCurrentAllowed;
datalayer_extended.tesla.PCS_dcdcPrechargeRtyCnt = PCS_dcdcPrechargeRtyCnt;
datalayer_extended.tesla.PCS_dcdc12VSupportRtyCnt = PCS_dcdc12VSupportRtyCnt;
datalayer_extended.tesla.PCS_dcdcDischargeRtyCnt = PCS_dcdcDischargeRtyCnt;
datalayer_extended.tesla.PCS_dcdcPwmEnableLine = PCS_dcdcPwmEnableLine;
datalayer_extended.tesla.PCS_dcdcSupportingFixedLvTarget = PCS_dcdcSupportingFixedLvTarget;
datalayer_extended.tesla.PCS_dcdcPrechargeRestartCnt = PCS_dcdcPrechargeRestartCnt;
datalayer_extended.tesla.PCS_dcdcInitialPrechargeSubState = PCS_dcdcInitialPrechargeSubState;
//0x252
datalayer_extended.tesla.BMS_maxRegenPower = BMS_maxRegenPower;
datalayer_extended.tesla.BMS_maxDischargePower = BMS_maxDischargePower;
datalayer_extended.tesla.BMS_maxStationaryHeatPower = BMS_maxStationaryHeatPower;
datalayer_extended.tesla.BMS_hvacPowerBudget = BMS_hvacPowerBudget;
datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump = BMS_notEnoughPowerForHeatPump;
datalayer_extended.tesla.BMS_powerLimitState = BMS_powerLimitState;
datalayer_extended.tesla.BMS_inverterTQF = BMS_inverterTQF;
//Via UDS
//datalayer_extended.tesla.BMS_info_buildConfigId = BMS_info_buildConfigId;
//0x300
datalayer_extended.tesla.BMS_info_buildConfigId = BMS_info_buildConfigId;
datalayer_extended.tesla.BMS_info_hardwareId = BMS_info_hardwareId;
datalayer_extended.tesla.BMS_info_componentId = BMS_info_componentId;
datalayer_extended.tesla.BMS_info_pcbaId = BMS_info_pcbaId;
datalayer_extended.tesla.BMS_info_assemblyId = BMS_info_assemblyId;
datalayer_extended.tesla.BMS_info_usageId = BMS_info_usageId;
datalayer_extended.tesla.BMS_info_subUsageId = BMS_info_subUsageId;
datalayer_extended.tesla.BMS_info_platformType = BMS_info_platformType;
datalayer_extended.tesla.BMS_info_appCrc = BMS_info_appCrc;
datalayer_extended.tesla.BMS_info_bootGitHash = BMS_info_bootGitHash;
datalayer_extended.tesla.BMS_info_bootUdsProtoVersion = BMS_info_bootUdsProtoVersion;
datalayer_extended.tesla.BMS_info_bootCrc = BMS_info_bootCrc;
//0x312
datalayer_extended.tesla.BMS_powerDissipation = BMS_powerDissipation;
datalayer_extended.tesla.BMS_flowRequest = BMS_flowRequest;
datalayer_extended.tesla.BMS_inletActiveCoolTargetT = BMS_inletActiveCoolTargetT;
datalayer_extended.tesla.BMS_inletPassiveTargetT = BMS_inletPassiveTargetT;
datalayer_extended.tesla.BMS_inletActiveHeatTargetT = BMS_inletActiveHeatTargetT;
datalayer_extended.tesla.BMS_packTMin = BMS_packTMin;
datalayer_extended.tesla.BMS_packTMax = BMS_packTMax;
datalayer_extended.tesla.BMS_pcsNoFlowRequest = BMS_pcsNoFlowRequest;
datalayer_extended.tesla.BMS_noFlowRequest = BMS_noFlowRequest;
//0x3C4
datalayer_extended.tesla.PCS_info_buildConfigId = PCS_info_buildConfigId;
datalayer_extended.tesla.PCS_info_hardwareId = PCS_info_hardwareId;
datalayer_extended.tesla.PCS_info_componentId = PCS_info_componentId;
//0x2A4
datalayer_extended.tesla.PCS_dcdcTemp = PCS_dcdcTemp;
datalayer_extended.tesla.PCS_ambientTemp = PCS_ambientTemp;
datalayer_extended.tesla.PCS_chgPhATemp = PCS_chgPhATemp;
datalayer_extended.tesla.PCS_chgPhBTemp = PCS_chgPhBTemp;
datalayer_extended.tesla.PCS_chgPhCTemp = PCS_chgPhCTemp;
//0x2C4
datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent = PCS_dcdcMaxLvOutputCurrent;
datalayer_extended.tesla.PCS_dcdcCurrentLimit = PCS_dcdcCurrentLimit;
datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit = PCS_dcdcLvOutputCurrentTempLimit;
datalayer_extended.tesla.PCS_dcdcUnifiedCommand = PCS_dcdcUnifiedCommand;
datalayer_extended.tesla.PCS_dcdcCLAControllerOutput = PCS_dcdcCLAControllerOutput;
datalayer_extended.tesla.PCS_dcdcTankVoltage = PCS_dcdcTankVoltage;
datalayer_extended.tesla.PCS_dcdcTankVoltageTarget = PCS_dcdcTankVoltageTarget;
datalayer_extended.tesla.PCS_dcdcClaCurrentFreq = PCS_dcdcClaCurrentFreq;
datalayer_extended.tesla.PCS_dcdcTCommMeasured = PCS_dcdcTCommMeasured;
datalayer_extended.tesla.PCS_dcdcShortTimeUs = PCS_dcdcShortTimeUs;
datalayer_extended.tesla.PCS_dcdcHalfPeriodUs = PCS_dcdcHalfPeriodUs;
datalayer_extended.tesla.PCS_dcdcIntervalMaxFrequency = PCS_dcdcIntervalMaxFrequency;
datalayer_extended.tesla.PCS_dcdcIntervalMaxHvBusVolt = PCS_dcdcIntervalMaxHvBusVolt;
datalayer_extended.tesla.PCS_dcdcIntervalMaxLvBusVolt = PCS_dcdcIntervalMaxLvBusVolt;
datalayer_extended.tesla.PCS_dcdcIntervalMaxLvOutputCurr = PCS_dcdcIntervalMaxLvOutputCurr;
datalayer_extended.tesla.PCS_dcdcIntervalMinFrequency = PCS_dcdcIntervalMinFrequency;
datalayer_extended.tesla.PCS_dcdcIntervalMinHvBusVolt = PCS_dcdcIntervalMinHvBusVolt;
datalayer_extended.tesla.PCS_dcdcIntervalMinLvBusVolt = PCS_dcdcIntervalMinLvBusVolt;
datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr = PCS_dcdcIntervalMinLvOutputCurr;
datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh = PCS_dcdc12vSupportLifetimekWh;
//0x310
datalayer_extended.tesla.HVP_info_buildConfigId = HVP_info_buildConfigId;
datalayer_extended.tesla.HVP_info_hardwareId = HVP_info_hardwareId;
datalayer_extended.tesla.HVP_info_componentId = HVP_info_componentId;
//0x7AA
datalayer_extended.tesla.HVP_gpioPassivePyroDepl = HVP_gpioPassivePyroDepl;
datalayer_extended.tesla.HVP_gpioPyroIsoEn = HVP_gpioPyroIsoEn;
datalayer_extended.tesla.HVP_gpioCpFaultIn = HVP_gpioCpFaultIn;
datalayer_extended.tesla.HVP_gpioPackContPowerEn = HVP_gpioPackContPowerEn;
datalayer_extended.tesla.HVP_gpioHvCablesOk = HVP_gpioHvCablesOk;
datalayer_extended.tesla.HVP_gpioHvpSelfEnable = HVP_gpioHvpSelfEnable;
datalayer_extended.tesla.HVP_gpioLed = HVP_gpioLed;
datalayer_extended.tesla.HVP_gpioCrashSignal = HVP_gpioCrashSignal;
datalayer_extended.tesla.HVP_gpioShuntDataReady = HVP_gpioShuntDataReady;
datalayer_extended.tesla.HVP_gpioFcContPosAux = HVP_gpioFcContPosAux;
datalayer_extended.tesla.HVP_gpioFcContNegAux = HVP_gpioFcContNegAux;
datalayer_extended.tesla.HVP_gpioBmsEout = HVP_gpioBmsEout;
datalayer_extended.tesla.HVP_gpioCpFaultOut = HVP_gpioCpFaultOut;
datalayer_extended.tesla.HVP_gpioPyroPor = HVP_gpioPyroPor;
datalayer_extended.tesla.HVP_gpioShuntEn = HVP_gpioShuntEn;
datalayer_extended.tesla.HVP_gpioHvpVerEn = HVP_gpioHvpVerEn;
datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel = HVP_gpioPackCoontPosFlywheel;
datalayer_extended.tesla.HVP_gpioCpLatchEnable = HVP_gpioCpLatchEnable;
datalayer_extended.tesla.HVP_gpioPcsEnable = HVP_gpioPcsEnable;
datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable = HVP_gpioPcsDcdcPwmEnable;
datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable = HVP_gpioPcsChargePwmEnable;
datalayer_extended.tesla.HVP_gpioFcContPowerEnable = HVP_gpioFcContPowerEnable;
datalayer_extended.tesla.HVP_gpioHvilEnable = HVP_gpioHvilEnable;
datalayer_extended.tesla.HVP_gpioSecDrdy = HVP_gpioSecDrdy;
datalayer_extended.tesla.HVP_hvp1v5Ref = HVP_hvp1v5Ref;
datalayer_extended.tesla.HVP_shuntCurrentDebug = HVP_shuntCurrentDebug;
datalayer_extended.tesla.HVP_packCurrentMia = HVP_packCurrentMia;
datalayer_extended.tesla.HVP_auxCurrentMia = HVP_auxCurrentMia;
datalayer_extended.tesla.HVP_currentSenseMia = HVP_currentSenseMia;
datalayer_extended.tesla.HVP_shuntRefVoltageMismatch = HVP_shuntRefVoltageMismatch;
datalayer_extended.tesla.HVP_shuntThermistorMia = HVP_shuntThermistorMia;
datalayer_extended.tesla.HVP_shuntHwMia = HVP_shuntHwMia;
datalayer_extended.tesla.HVP_dcLinkVoltage = HVP_dcLinkVoltage;
datalayer_extended.tesla.HVP_packVoltage = HVP_packVoltage;
datalayer_extended.tesla.HVP_fcLinkVoltage = HVP_fcLinkVoltage;
datalayer_extended.tesla.HVP_packContVoltage = HVP_packContVoltage;
datalayer_extended.tesla.HVP_packNegativeV = HVP_packNegativeV;
datalayer_extended.tesla.HVP_packPositiveV = HVP_packPositiveV;
datalayer_extended.tesla.HVP_pyroAnalog = HVP_pyroAnalog;
datalayer_extended.tesla.HVP_dcLinkNegativeV = HVP_dcLinkNegativeV;
datalayer_extended.tesla.HVP_dcLinkPositiveV = HVP_dcLinkPositiveV;
datalayer_extended.tesla.HVP_fcLinkNegativeV = HVP_fcLinkNegativeV;
datalayer_extended.tesla.HVP_fcContCoilCurrent = HVP_fcContCoilCurrent;
datalayer_extended.tesla.HVP_fcContVoltage = HVP_fcContVoltage;
datalayer_extended.tesla.HVP_hvilInVoltage = HVP_hvilInVoltage;
datalayer_extended.tesla.HVP_hvilOutVoltage = HVP_hvilOutVoltage;
datalayer_extended.tesla.HVP_fcLinkPositiveV = HVP_fcLinkPositiveV;
datalayer_extended.tesla.HVP_packContCoilCurrent = HVP_packContCoilCurrent;
datalayer_extended.tesla.HVP_battery12V = HVP_battery12V;
datalayer_extended.tesla.HVP_shuntRefVoltageDbg = HVP_shuntRefVoltageDbg;
datalayer_extended.tesla.HVP_shuntAuxCurrentDbg = HVP_shuntAuxCurrentDbg;
datalayer_extended.tesla.HVP_shuntBarTempDbg = HVP_shuntBarTempDbg;
datalayer_extended.tesla.HVP_shuntAsicTempDbg = HVP_shuntAsicTempDbg;
datalayer_extended.tesla.HVP_shuntAuxCurrentStatus = HVP_shuntAuxCurrentStatus;
datalayer_extended.tesla.HVP_shuntBarTempStatus = HVP_shuntBarTempStatus;
datalayer_extended.tesla.HVP_shuntAsicTempStatus = HVP_shuntAsicTempStatus;
//Safety checks for CAN message sesnding
if ((datalayer.system.status.inverter_allows_contactor_closing == true) &&
(datalayer.battery.status.bms_status != FAULT) && (!datalayer.system.settings.equipment_stop_active)) {
// Carry on: 0x221 DRIVE state & reset power down timer
vehicleState = 1;
powerDownTimer = 180; //0x221 50ms cyclic, 20 calls/second
} else {
// Faulted state, or inverter blocks contactor closing
// Shut down: 0x221 ACCESSORY state for 3 seconds, followed by GOING_DOWN, then OFF
if (powerDownTimer <= 180 && powerDownTimer > 120) {
vehicleState = 2; //ACCESSORY
powerDownTimer--;
}
if (powerDownTimer <= 120 && powerDownTimer > 60) {
vehicleState = 3; //GOING_DOWN
powerDownTimer--;
}
if (powerDownTimer <= 60 && powerDownTimer > 0) {
vehicleState = 0; //OFF
powerDownTimer--;
}
}
printFaultCodesIfActive();
logging.printf("BMS Contactors State: ");
logging.printf(getBMSContactorState(battery_contactor)); // Display what state the BMS thinks the contactors are in
logging.printf(", HVIL: ");
logging.printf(getHvilStatusState(battery_hvil_status));
logging.printf(", NegativeState: ");
logging.printf(getContactorState(battery_packContNegativeState));
logging.printf(", PositiveState: ");
logging.println(getContactorState(battery_packContPositiveState));
logging.printf("HVP Contactors setState: ");
logging.printf(
getContactorText(battery_packContactorSetState)); // Display what state the HVP has set the contactors to be in
logging.printf(", Closing blocked: ");
logging.printf(getNoYes(battery_packCtrsClosingBlocked));
if (battery_packContactorSetState == 5) {
logging.printf(" (already CLOSED)");
}
logging.printf(", Pyrotest: ");
logging.println(getNoYes(battery_pyroTestInProgress));
logging.printf("Battery values: ");
logging.printf("Real SOC: ");
logging.print(battery_soc_ui / 10.0, 1);
logging.printf(", Battery voltage: ");
logging.print(battery_volts / 10.0, 1);
logging.printf("V");
logging.printf(", Battery HV current: ");
logging.print(battery_amps / 10.0, 1);
logging.printf("A");
logging.printf(", Fully charged?: ");
if (battery_full_charge_complete)
logging.printf("YES, ");
else
logging.printf("NO, ");
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
logging.printf("LFP chemistry detected!");
}
logging.println("");
logging.printf("Cellstats, Max: ");
logging.print(battery_cell_max_v);
logging.printf("mV (cell ");
logging.print(battery_BrickVoltageMaxNum);
logging.printf("), Min: ");
logging.print(battery_cell_min_v);
logging.printf("mV (cell ");
logging.print(battery_BrickVoltageMinNum);
logging.printf("), Imbalance: ");
logging.print(battery_cell_deviation_mV);
logging.println("mV.");
logging.printf("High Voltage Output Pins: %.2f V, Low Voltage: %.2f V, DC/DC 12V current: %.2f A.\n",
(battery_dcdcHvBusVolt * 0.146484), (battery_dcdcLvBusVolt * 0.0390625),
(battery_dcdcLvOutputCurrent * 0.1));
logging.printf("PCS_ambientTemp: %.2f°C, DCDC_Temp: %.2f°C, ChgPhA: %.2f°C, ChgPhB: %.2f°C, ChgPhC: %.2f°C.\n",
PCS_ambientTemp * 0.1 + 40, PCS_dcdcTemp * 0.1 + 40, PCS_chgPhATemp * 0.1 + 40,
PCS_chgPhBTemp * 0.1 + 40, PCS_chgPhCTemp * 0.1 + 40);
}
void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
static uint8_t mux = 0;
static uint16_t temp = 0;
static bool mux0_read = false;
static bool mux1_read = false;
switch (rx_frame.ID) {
case 0x352: // 850 BMS_energyStatus newer BMS
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = ((rx_frame.data.u8[0]) & 0x03); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X
if (mux == 0) {
battery_nominal_full_pack_energy_m0 =
(((rx_frame.data.u8[3]) << 8) |
rx_frame.data.u8[2]); //16|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended
battery_nominal_energy_remaining_m0 =
(((rx_frame.data.u8[5]) << 8) |
rx_frame.data.u8[4]); //32|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended
battery_ideal_energy_remaining_m0 =
(((rx_frame.data.u8[7]) << 8) |
rx_frame.data.u8[6]); //48|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended
mux0_read = true; //Set flag to true
}
if (mux == 1) {
battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //BMS_fullChargeComplete : 15|1@1+ (1,0) [0|1]//noYes
battery_energy_buffer_m1 =
((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //16|16@1+ (0.01,0) [0|0] "kWh"//to datalayer_extended
battery_expected_energy_remaining_m1 =
((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]); //32|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended
battery_energy_to_charge_complete_m1 =
((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); //48|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended
mux1_read = true; //Set flag to true
}
if (mux == 2) {
} // Additional information needed on this mux 2, example frame: 02 26 02 20 02 80 00 00 doesn't change
if (mux0_read && mux1_read) {
mux0_read = false;
mux1_read = false;
BMS352_mux = true; //Set flag to true
break;
}
if (mux0_read || mux1_read || BMS352_mux) {
//Skip older BMS frame parsing
break;
}
// Older BMS <2021 without mux
battery_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "kWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU));
(((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh)
battery_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "kWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU));
(((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh
battery_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "kWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U));
(((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) |
((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh)
battery_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "kWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU));
(((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh
battery_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "kWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU));
(((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh
battery_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "kWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U));
(((rx_frame.data.u8[7] & 0xFE) >> 1) | ((rx_frame.data.u8[6] & 0x80) >> 7)); //Example 1 * 0.1 = 0
battery_fully_charged = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U));
((rx_frame.data.u8[7] >> 7) & 0x01); //noYes
break;
case 0x20A: //522 HVP_contactorState:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
battery_packContNegativeState =
(rx_frame.data.u8[0] & 0x07); //(_d[0] & (0x07U)); 0|3@1+ (1,0) [0|7] //contactorState
battery_packContPositiveState =
(rx_frame.data.u8[0] & 0x38) >> 3; //((_d[0] >> 3) & (0x07U)); 3|3@1+ (1,0) [0|7] //contactorState
//battery_contactor = (rx_frame.data.u8[1] & 0x0F); // 8|4@1+ (1,0) [0|9] //contactorText
battery_packContactorSetState =
(rx_frame.data.u8[1] & 0x0F); //(_d[1] & (0x0FU)); 8|4@1+ (1,0) [0|9] //contactorState
battery_packCtrsClosingBlocked =
(rx_frame.data.u8[4] & 0x08) >> 3; //((_d[4] >> 3) & (0x01U)); 35|1@1+ (1,0) [0|1] //noYes
battery_pyroTestInProgress =
(rx_frame.data.u8[4] & 0x20) >> 5; //((_d[4] >> 5) & (0x01U));//37|1@1+ (1,0) [0|1] //noYes
battery_hvil_status =
(rx_frame.data.u8[5] & 0x0F); //(_d[5] & (0x0FU)); //40|4@1+ (1,0) [0|9] //hvilStatusState
battery_packCtrsOpenNowRequested = ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|1] //noYes
battery_packCtrsOpenRequested = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|1] //noYes
battery_packCtrsRequestStatus = ((rx_frame.data.u8[3] >> 6) & (0x03U)); //30|2@1+ (1,0) [0|2] //HVP_contactor
battery_packCtrsResetRequestRequired = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|1] //noYes
battery_dcLinkAllowedToEnergize = ((rx_frame.data.u8[4] >> 4) & (0x01U)); //36|1@1+ (1,0) [0|1] //noYes
battery_fcContNegativeAuxOpen = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|1] "" Receiver
battery_fcContNegativeState = ((rx_frame.data.u8[1] >> 4) & (0x07U)); //12|3@1+ (1,0) [0|7] "" Receiver
battery_fcContPositiveAuxOpen = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|1] "" Receiver
battery_fcContPositiveState = (rx_frame.data.u8[2] & (0x07U)); //16|3@1+ (1,0) [0|7] "" Receiver
battery_fcContactorSetState = ((rx_frame.data.u8[2] >> 3) & (0x0FU)); //19|4@1+ (1,0) [0|9] "" Receiver
battery_fcCtrsClosingAllowed = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|1] "" Receiver
battery_fcCtrsOpenNowRequested = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|1] "" Receiver
battery_fcCtrsOpenRequested = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|1] "" Receiver
battery_fcCtrsRequestStatus = (rx_frame.data.u8[3] & (0x03U)); //24|2@1+ (1,0) [0|2] "" Receiver
battery_fcCtrsResetRequestRequired = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|1] "" Receiver
battery_fcLinkAllowedToEnergize = ((rx_frame.data.u8[5] >> 4) & (0x03U)); //44|2@1+ (1,0) [0|2] "" Receiver
case 0x212: //530 BMS_status: 8
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
BMS_hvacPowerRequest = (rx_frame.data.u8[0] & (0x01U));
BMS_notEnoughPowerForDrive = ((rx_frame.data.u8[0] >> 1) & (0x01U));
BMS_notEnoughPowerForSupport = ((rx_frame.data.u8[0] >> 2) & (0x01U));
BMS_preconditionAllowed = ((rx_frame.data.u8[0] >> 3) & (0x01U));
BMS_updateAllowed = ((rx_frame.data.u8[0] >> 4) & (0x01U));
BMS_activeHeatingWorthwhile = ((rx_frame.data.u8[0] >> 5) & (0x01U));
BMS_cpMiaOnHvs = ((rx_frame.data.u8[0] >> 6) & (0x01U));
BMS_contactorState = (rx_frame.data.u8[1] &
(0x07U)); //0 "SNA" 1 "OPEN" 2 "OPENING" 3 "CLOSING" 4 "CLOSED" 5 "WELDED" 6 "BLOCKED" ;
battery_contactor = BMS_contactorState;
//BMS_state = // Original code from older DBCs
//((rx_frame.data.u8[1] >> 3) &
//(0x0FU)); //0 "STANDBY" 1 "DRIVE" 2 "SUPPORT" 3 "CHARGE" 4 "FEIM" 5 "CLEAR_FAULT" 6 "FAULT" 7 "WELD" 8 "TEST" 9 "SNA" ;
BMS_state = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 31, 4));
//0 "STANDBY" 1 "DRIVE" 2 "SUPPORT" 3 "CHARGE" 4 "FEIM" 5 "CLEAR_FAULT" 6 "FAULT" 7 "WELD" 8 "TEST" 9 "SNA" 10 "BMS_DIAG";
BMS_hvState = (rx_frame.data.u8[2] & (0x07U));
//0 "DOWN" 1 "COMING_UP" 2 "GOING_DOWN" 3 "UP_FOR_DRIVE" 4 "UP_FOR_CHARGE" 5 "UP_FOR_DC_CHARGE" 6 "UP" ;
BMS_isolationResistance =
((rx_frame.data.u8[3] & (0x1FU)) << 5) |
((rx_frame.data.u8[2] >> 3) & (0x1FU)); //19|10@1+ (10,0) [0|0] "kOhm"/to datalayer_extended
//BMS_chargeRequest = ((rx_frame.data.u8[3] >> 5) & (0x01U));
BMS_chargeRequest = static_cast<bool>(extract_signal_value(rx_frame.data.u8, 29, 1));
BMS_keepWarmRequest = ((rx_frame.data.u8[3] >> 6) & (0x01U));
BMS_uiChargeStatus = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 32, 3));
//BMS_uiChargeStatus =
//(rx_frame.data.u8[4] &
//(0x07U));
// 0 "DISCONNECTED" 1 "NO_POWER" 2 "ABOUT_TO_CHARGE" 3 "CHARGING" 4 "CHARGE_COMPLETE" 5 "CHARGE_STOPPED" ;
BMS_diLimpRequest = ((rx_frame.data.u8[4] >> 3) & (0x01U));
BMS_okToShipByAir = ((rx_frame.data.u8[4] >> 4) & (0x01U));
BMS_okToShipByLand = ((rx_frame.data.u8[4] >> 5) & (0x01U));
BMS_chgPowerAvailable = ((rx_frame.data.u8[6] & (0x01U)) << 10) | ((rx_frame.data.u8[5] & (0xFFU)) << 2) |
((rx_frame.data.u8[4] >> 6) & (0x03U)); //38|11@1+ (0.125,0) [0|0] "kW"
BMS_chargeRetryCount = ((rx_frame.data.u8[6] >> 1) & (0x0FU));
BMS_pcsPwmEnabled = ((rx_frame.data.u8[6] >> 5) & (0x01U));
BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U));
BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC
break;
case 0x224: //548 PCS_dcdcStatus:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ;
PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED"
PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED"
PCS_dcdcMainState =
((rx_frame.data.u8[1] & (0x03U)) << 2) |
((rx_frame.data.u8[0] >> 6) &
(0x03U)); //0 "STANDBY" 1 "12V_SUPPORT_ACTIVE" 2 "PRECHARGE_STARTUP" 3 "PRECHARGE_ACTIVE" 4 "DIS_HVBUS_ACTIVE" 5 "SHUTDOWN" 6 "FAULTED" ;
PCS_dcdcSubState =
((rx_frame.data.u8[1] >> 2) &
(0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ;
PCS_dcdcFaulted = ((rx_frame.data.u8[1] >> 7) & (0x01U));
PCS_dcdcOutputIsLimited = ((rx_frame.data.u8[3] >> 4) & (0x01U));
PCS_dcdcMaxOutputCurrentAllowed = ((rx_frame.data.u8[5] & (0x01U)) << 11) |
((rx_frame.data.u8[4] & (0xFFU)) << 3) |
((rx_frame.data.u8[3] >> 5) & (0x07U)); //29|12@1+ (0.1,0) [0|0] "A"
PCS_dcdcPrechargeRtyCnt = ((rx_frame.data.u8[5] >> 1) & (0x07U)); //Retry Count
PCS_dcdc12VSupportRtyCnt = ((rx_frame.data.u8[5] >> 4) & (0x0FU)); //Retry Count
PCS_dcdcDischargeRtyCnt = (rx_frame.data.u8[6] & (0x0FU)); //Retry Count
PCS_dcdcPwmEnableLine = ((rx_frame.data.u8[6] >> 4) & (0x01U));
PCS_dcdcSupportingFixedLvTarget = ((rx_frame.data.u8[6] >> 5) & (0x01U));
PCS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U));
PCS_dcdcPrechargeRestartCnt = (rx_frame.data.u8[7] & (0x07U));
PCS_dcdcInitialPrechargeSubState =
((rx_frame.data.u8[7] >> 3) &
(0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ;
break;
case 0x252: //Limit //594 BMS_powerAvailable:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
BMS_maxRegenPower = ((rx_frame.data.u8[1] << 8) |
rx_frame.data.u8[0]); //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW
BMS_maxDischargePower =
((rx_frame.data.u8[3] << 8) |
rx_frame.data.u8[2]); //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117???
BMS_maxStationaryHeatPower =
(((rx_frame.data.u8[5] & 0x03) << 8) |
rx_frame.data.u8[4]); //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW
BMS_hvacPowerBudget =
(((rx_frame.data.u8[7] << 6) |
((rx_frame.data.u8[6] & 0xFC) >> 2))); //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW?
BMS_notEnoughPowerForHeatPump =
((rx_frame.data.u8[5] >> 2) & (0x01U)); //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver
BMS_powerLimitState =
(rx_frame.data.u8[6] &
(0x01U)); //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] 0 "NOT_CALCULATED_FOR_DRIVE" 1 "CALCULATED_FOR_DRIVE"
BMS_inverterTQF = ((rx_frame.data.u8[7] >> 4) & (0x03U));
break;
case 0x132: //battery amps/volts //HVBattAmpVolt
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
battery_volts = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) *
0.1; //0|16@1+ (0.01,0) [0|655.35] "V" //Example 37030mv * 0.01 = 3703dV
battery_amps =
((rx_frame.data.u8[3] << 8) |
rx_frame.data.u8
[2]); //SmoothBattCurrent : 16|16@1- (-0.1,0) [-3276.7|3276.7] "A"//Example 65492 (-4.3A) OR 225 (22.5A)
battery_raw_amps =
((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * -0.05 +
822; //RawBattCurrent : 32|16@1- (-0.05,822) [-1138.35|2138.4] "A" //Example 10425 * -0.05 = ?
battery_charge_time_remaining =
(((rx_frame.data.u8[7] & 0x0F) << 8) |
rx_frame.data.u8[6]); //ChargeHoursRemaining : 48|12@1+ (1,0) [0|4095] "Min" //Example 228 * 0.1 = 22.8min
if (battery_charge_time_remaining == 4095) {
battery_charge_time_remaining = 0;
}
break;
case 0x3D2: //TotalChargeDischarge:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
battery_total_discharge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) |
(rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
//0|32@1+ (0.001,0) [0|4294970] "kWh"
battery_total_charge = ((rx_frame.data.u8[7] << 24) | (rx_frame.data.u8[6] << 16) | (rx_frame.data.u8[5] << 8) |
rx_frame.data.u8[4]);
//32|32@1+ (0.001,0) [0|4294970] "kWh"
break;
case 0x332: //min/max hist values //BattBrickMinMax:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = (rx_frame.data.u8[0] & 0x03); //BattBrickMultiplexer M : 0|2@1+ (1,0) [0|0] ""
if (mux == 1) //Cell voltages
{
temp = ((rx_frame.data.u8[1] << 6) | (rx_frame.data.u8[0] >> 2));
temp = (temp & 0xFFF);
battery_cell_max_v = temp * 2;
temp = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
temp = (temp & 0xFFF);
battery_cell_min_v = temp * 2;
cellvoltagesRead = true;
//BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[1] & (0x3FU)) << 6) | ((_d[0] >> 2) & (0x3FU));
battery_BrickVoltageMax =
((rx_frame.data.u8[1] & (0x3F)) << 6) | ((rx_frame.data.u8[0] >> 2) & (0x3F)); //to datalayer_extended
//BattBrickVoltageMin m1 : 16|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[3] & (0x0FU)) << 8) | (_d[2] & (0xFFU));
battery_BrickVoltageMin =
((rx_frame.data.u8[3] & (0x0F)) << 8) | (rx_frame.data.u8[2] & (0xFF)); //to datalayer_extended
//BattBrickVoltageMaxNum m1 : 32|7@1+ (1,1) [0|0] "" Receiver
battery_BrickVoltageMaxNum =
1 + (rx_frame.data.u8[4] & 0x7F); //(_d[4] & (0x7FU)); //This cell has highest voltage
//BattBrickVoltageMinNum m1 : 40|7@1+ (1,1) [0|0] "" Receiver
battery_BrickVoltageMinNum =
1 + (rx_frame.data.u8[5] & 0x7F); //(_d[5] & (0x7FU)); //This cell has lowest voltage
}
if (mux == 0) //Temperature sensors
{ //BattBrickTempMax m0 : 16|8@1+ (0.5,-40) [0|0] "C" (_d[2] & (0xFFU));
battery_max_temp = (rx_frame.data.u8[2] * 5) - 400; //Temperature values have 40.0*C offset, 0.5*C /bit
//BattBrickTempMin m0 : 24|8@1+ (0.5,-40) [0|0] "C" (_d[3] & (0xFFU));
battery_min_temp =
(rx_frame.data.u8[3] * 5) - 400; //Multiply by 5 and remove offset to get C+1 (0x61*5=485-400=8.5*C)
//BattBrickTempMaxNum m0 : 2|4@1+ (1,0) [0|0] "" ((_d[0] >> 2) & (0x0FU));
battery_BrickTempMaxNum = ((rx_frame.data.u8[0] >> 2) & (0x0F)); //to datalayer_extended
//BattBrickTempMinNum m0 : 8|4@1+ (1,0) [0|0] "" (_d[1] & (0x0FU));
battery_BrickTempMinNum = (rx_frame.data.u8[1] & (0x0F)); //to datalayer_extended
//BattBrickModelTMax m0 : 32|8@1+ (0.5,-40) [0|0] "C" (_d[4] & (0xFFU));
battery_BrickModelTMax = (rx_frame.data.u8[4] & (0xFFU)); //to datalayer_extended
//BattBrickModelTMin m0 : 40|8@1+ (0.5,-40) [0|0] "C" (_d[5] & (0xFFU));
battery_BrickModelTMin = (rx_frame.data.u8[5] & (0xFFU)); //to datalayer_extended
}
break;
case 0x312: // 786 BMS_thermalStatus
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
BMS_powerDissipation =
((rx_frame.data.u8[1] & (0x03U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|10@1+ (0.02,0) [0|0] "kW"
BMS_flowRequest = ((rx_frame.data.u8[2] & (0x01U)) << 6) |
((rx_frame.data.u8[1] >> 2) & (0x3FU)); //10|7@1+ (0.3,0) [0|0] "LPM"
BMS_inletActiveCoolTargetT = ((rx_frame.data.u8[3] & (0x03U)) << 7) |
((rx_frame.data.u8[2] >> 1) & (0x7FU)); //17|9@1+ (0.25,-25) [0|0] "DegC"
BMS_inletPassiveTargetT = ((rx_frame.data.u8[4] & (0x07U)) << 6) |
((rx_frame.data.u8[3] >> 2) & (0x3FU)); //26|9@1+ (0.25,-25) [0|0] "DegC" X
BMS_inletActiveHeatTargetT = ((rx_frame.data.u8[5] & (0x0FU)) << 5) |
((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|9@1+ (0.25,-25) [0|0] "DegC"
BMS_packTMin = ((rx_frame.data.u8[6] & (0x1FU)) << 4) |
((rx_frame.data.u8[5] >> 4) & (0x0FU)); //44|9@1+ (0.25,-25) [-25|100] "DegC"
BMS_packTMax = ((rx_frame.data.u8[7] & (0x3FU)) << 3) |
((rx_frame.data.u8[6] >> 5) & (0x07U)); //53|9@1+ (0.25,-25) [-25|100] "DegC"
BMS_pcsNoFlowRequest = ((rx_frame.data.u8[7] >> 6) & (0x01U)); // 62|1@1+ (1,0) [0|0] ""
BMS_noFlowRequest = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] ""
break;
case 0x2A4: //676 PCS_thermalStatus
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
PCS_chgPhATemp = (rx_frame.data.u8[0] & 0xFF) | ((rx_frame.data.u8[1] & 0x07) << 8); //0|11@1- (0.1,40) [0|0] "C"
PCS_chgPhBTemp =
((rx_frame.data.u8[1] & 0xF8) >> 3) | ((rx_frame.data.u8[2] & 0x3F) << 5); //11|11@1- (0.1,40) [0|0] "C"
PCS_chgPhCTemp = ((rx_frame.data.u8[2] & 0xC0) >> 6) | (rx_frame.data.u8[3] << 2) |
((rx_frame.data.u8[4] & 0x01) << 10); //22|11@1- (0.1,40) [0|0] "C"
PCS_dcdcTemp =
((rx_frame.data.u8[4] & 0xFE) >> 1) | ((rx_frame.data.u8[5] & 0x0F) << 7); //33|11@1- (0.1,40) [0|0] "C"
PCS_ambientTemp = ((rx_frame.data.u8[5] & 0xF0) >> 4) | (rx_frame.data.u8[6] << 4); //44|11@1- (0.1,40) [0|0] "C"
break;
case 0x2C4: // 708 PCS_logging: not all frames are listed, just ones relating to dcdc
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = (rx_frame.data.u8[0] & (0x1FU));
//PCS_logMessageSelect = (rx_frame.data.u8[0] & (0x1FU)); //0|5@1+ (1,0) [0|0] ""
if (mux == 6) {
PCS_dcdcMaxLvOutputCurrent = ((rx_frame.data.u8[4] & (0xFFU)) << 4) |
((rx_frame.data.u8[3] >> 4) & (0x0FU)); //m6 : 28|12@1+ (0.1,0) [0|0] "A" X
PCS_dcdcCurrentLimit = ((rx_frame.data.u8[6] & (0x0FU)) << 8) |
(rx_frame.data.u8[5] & (0xFFU)); //m6 : 40|12@1+ (0.1,0) [0|0] "A" X
PCS_dcdcLvOutputCurrentTempLimit = ((rx_frame.data.u8[7] & (0xFFU)) << 4) |
((rx_frame.data.u8[6] >> 4) & (0x0FU)); //m6 : 52|12@1+ (0.1,0) [0|0] "A" X
}
if (mux == 7) {
PCS_dcdcUnifiedCommand = ((rx_frame.data.u8[1] & (0x7FU)) << 3) |
((rx_frame.data.u8[0] >> 5) & (0x07U)); //m7 : 5|10@1+ (0.001,0) [0|0] "1" X
PCS_dcdcCLAControllerOutput = ((rx_frame.data.u8[3] & (0x03U)) << 8) |
(rx_frame.data.u8[2] & (0xFFU)); //m7 : 16|10@1+ (0.001,0) [0|0] "1" X
PCS_dcdcTankVoltage = ((rx_frame.data.u8[4] & (0x1FU)) << 6) |
((rx_frame.data.u8[3] >> 2) & (0x3FU)); //m7 : 26|11@1- (1,0) [0|0] "V" X
PCS_dcdcTankVoltageTarget = ((rx_frame.data.u8[5] & (0x7FU)) << 3) |
((rx_frame.data.u8[4] >> 5) & (0x07U)); // m7 : 37|10@1+ (1,0) [0|0] "V" X
PCS_dcdcClaCurrentFreq = ((rx_frame.data.u8[7] & (0x0FU)) << 8) |
(rx_frame.data.u8[6] & (0xFFU)); //P m7 : 48|12@1+ (0.0976563,0) [0|0] "kHz" X
}
if (mux == 8) {
PCS_dcdcTCommMeasured = ((rx_frame.data.u8[2] & (0xFFU)) << 8) |
(rx_frame.data.u8[1] & (0xFFU)); // m8 : 8|16@1- (0.00195313,0) [0|0] "us" X
PCS_dcdcShortTimeUs = ((rx_frame.data.u8[4] & (0xFFU)) << 8) |
(rx_frame.data.u8[3] & (0xFFU)); // m8 : 24|16@1+ (0.000488281,0) [0|0] "us" X
PCS_dcdcHalfPeriodUs = ((rx_frame.data.u8[6] & (0xFFU)) << 8) |
(rx_frame.data.u8[5] & (0xFFU)); // m8 : 40|16@1+ (0.000488281,0) [0|0] "us" X
}
if (mux == 18) {
PCS_dcdcIntervalMaxFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) |
(rx_frame.data.u8[1] & (0xFFU)); // m18 : 8|12@1+ (1,0) [0|0] "kHz" X
PCS_dcdcIntervalMaxHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) |
(rx_frame.data.u8[3] & (0xFFU)); //m18 : 24|13@1+ (0.1,0) [0|0] "V" X
PCS_dcdcIntervalMaxLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) |
((rx_frame.data.u8[4] >> 5) & (0x07U)); // m18 : 37|9@1+ (0.1,0) [0|0] "V" X
PCS_dcdcIntervalMaxLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) |
(rx_frame.data.u8[6] & (0xFFU)); //m18 : 48|12@1+ (1,0) [0|0] "A" X
}
if (mux == 19) {
PCS_dcdcIntervalMinFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) |
(rx_frame.data.u8[1] & (0xFFU)); //m19 : 8|12@1+ (1,0) [0|0] "kHz" X
PCS_dcdcIntervalMinHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) |
(rx_frame.data.u8[3] & (0xFFU)); //m19 : 24|13@1+ (0.1,0) [0|0] "V" X
PCS_dcdcIntervalMinLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) |
((rx_frame.data.u8[4] >> 5) & (0x07U)); //m19 : 37|9@1+ (0.1,0) [0|0] "V" X
PCS_dcdcIntervalMinLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) |
(rx_frame.data.u8[6] & (0xFFU)); // m19 : 48|12@1+ (1,0) [0|0] "A" X
}
if (mux == 22) {
PCS_dcdc12vSupportLifetimekWh = ((rx_frame.data.u8[3] & (0xFFU)) << 16) |
((rx_frame.data.u8[2] & (0xFFU)) << 8) |
(rx_frame.data.u8[1] & (0xFFU)); // m22 : 8|24@1+ (0.01,0) [0|0] "kWh" X
}
break;
case 0x401: // Cell stats //BrickVoltages
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = (rx_frame.data.u8[0]); //MultiplexSelector M : 0|8@1+ (1,0) [0|0] ""
//StatusFlags : 8|8@1+ (1,0) [0|0] ""
//Brick0 m0 : 16|16@1+ (0.0001,0) [0|0] "V"
//Brick1 m0 : 32|16@1+ (0.0001,0) [0|0] "V"
//Brick2 m0 : 48|16@1+ (0.0001,0) [0|0] "V"
static uint16_t volts;
static uint8_t mux_zero_counter = 0u;
static uint8_t mux_max = 0u;
if (rx_frame.data.u8[1] == 0x2A) // status byte must be 0x2A to read cellvoltages
{
// Example, frame3=0x89,frame2=0x1D = 35101 / 10 = 3510mV
volts = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) / 10;
datalayer.battery.status.cell_voltages_mV[mux * 3] = volts;
volts = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) / 10;
datalayer.battery.status.cell_voltages_mV[1 + mux * 3] = volts;
volts = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) / 10;
datalayer.battery.status.cell_voltages_mV[2 + mux * 3] = volts;
// Track the max value of mux. If we've seen two 0 values for mux, we've probably gathered all
// cell voltages. Then, 2 + mux_max * 3 + 1 is the number of cell voltages.
mux_max = (mux > mux_max) ? mux : mux_max;
if (mux_zero_counter < 2 && mux == 0u) {
mux_zero_counter++;
if (mux_zero_counter == 2u) {
// The max index will be 2 + mux_max * 3 (see above), so "+ 1" for the number of cells
datalayer.battery.info.number_of_cells = 2 + 3 * mux_max + 1;
// Increase the counter arbitrarily another time to make the initial if-statement evaluate to false
mux_zero_counter++;
}
}
}
break;
case 0x2d2: //BMSVAlimits:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
BMS_min_voltage = ((rx_frame.data.u8[1] << 8) |
rx_frame.data.u8[0]); //0|16@1+ (0.01,0) [0|430] "V" //Example 24148mv * 0.01 = 241.48 V
BMS_max_voltage = ((rx_frame.data.u8[3] << 8) |
rx_frame.data.u8[2]); //16|16@1+ (0.01,0) [0|430] "V" //Example 40282mv * 0.01 = 402.82 V
battery_max_charge_current = (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]) *
0.1; //32|14@1+ (0.1,0) [0|1638.2] "A" //Example 1301? * 0.1 = 130.1?
battery_max_discharge_current = (((rx_frame.data.u8[7] & 0x3F) << 8) | rx_frame.data.u8[6]) *
0.128; //48|14@1+ (0.128,0) [0|2096.9] "A" //Example 430? * 0.128 = 55.4?
break;
case 0x2b4: //PCS_dcdcRailStatus:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
battery_dcdcLvBusVolt =
(((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); //0|10@1+ (0.0390625,0) [0|39.9609] "V"
battery_dcdcHvBusVolt = (((rx_frame.data.u8[2] & 0x3F) << 6) |
((rx_frame.data.u8[1] & 0xFC) >> 2)); //10|12@1+ (0.146484,0) [0|599.854] "V"
battery_dcdcLvOutputCurrent =
(((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]); //24|12@1+ (0.1,0) [0|400] "A"
break;
case 0x292: //BMS_socStatus
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
battery_beginning_of_life =
(((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]) * 0.1; //40|10@1+ (0.1,0) [0|102.3] "kWh"
battery_soc_min = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); //0|10@1+ (0.1,0) [0|102.3] "%"
battery_soc_ui =
(((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); //10|10@1+ (0.1,0) [0|102.3] "%"
battery_soc_max =
(((rx_frame.data.u8[3] & 0x3F) << 4) | ((rx_frame.data.u8[2] & 0xF0) >> 4)); //20|10@1+ (0.1,0) [0|102.3] "%"
battery_soc_ave =
((rx_frame.data.u8[4] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6)); //30|10@1+ (0.1,0) [0|102.3] "%"
battery_battTempPct =
(((rx_frame.data.u8[7] & 0x03) << 6) | (rx_frame.data.u8[6] & 0x3F) >> 2); //50|8@1+ (0.4,0) [0|100] "%"
break;
case 0x392: //BMS_packConfig
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = (rx_frame.data.u8[0] & (0xFF));
if (mux == 1) {
battery_packConfigMultiplexer = (rx_frame.data.u8[0] & (0xff)); //0|8@1+ (1,0) [0|1] ""
battery_moduleType =
(rx_frame.data.u8[1] &
(0x07)); //8|3@1+ (1,0) [0|4] ""//0 "UNKNOWN" 1 "E3_NCT" 2 "E1_NCT" 3 "E3_CT" 4 "E1_CT" 5 "E1_CP" ;//to datalayer_extended
battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg"
battery_platformMaxBusVoltage =
(((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3])); //24|10@1+ (0.1,375) [0|0] "V"
}
if (mux == 0) {
battery_reservedConfig =
(rx_frame.data.u8[1] &
(0x1F)); //8|5@1+ (1,0) [0|31] ""//0 "BMS_CONFIG_0" 1 "BMS_CONFIG_1" 10 "BMS_CONFIG_10" 11 "BMS_CONFIG_11" 12 "BMS_CONFIG_12" 13 "BMS_CONFIG_13" 14 "BMS_CONFIG_14" 15 "BMS_CONFIG_15" 16 "BMS_CONFIG_16" 17 "BMS_CONFIG_17" 18 "BMS_CONFIG_18" 19 "BMS_CONFIG_19" 2 "BMS_CONFIG_2" 20 "BMS_CONFIG_20" 21 "BMS_CONFIG_21" 22 "BMS_CONFIG_22" 23 "BMS_CONFIG_23" 24 "BMS_CONFIG_24" 25 "BMS_CONFIG_25" 26 "BMS_CONFIG_26" 27 "BMS_CONFIG_27" 28 "BMS_CONFIG_28" 29 "BMS_CONFIG_29" 3 "BMS_CONFIG_3" 30 "BMS_CONFIG_30" 31 "BMS_CONFIG_31" 4 "BMS_CONFIG_4" 5 "BMS_CONFIG_5" 6 "BMS_CONFIG_6" 7 "BMS_CONFIG_7" 8 "BMS_CONFIG_8" 9 "BMS_CONFIG_9" ;
}
break;
case 0x7AA: //1962 HVP_debugMessage:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = (rx_frame.data.u8[0] & (0x0FU));
//HVP_debugMessageMultiplexer = (rx_frame.data.u8[0] & (0x0FU)); //0|4@1+ (1,0) [0|6] ""
if (mux == 0) {
HVP_gpioPassivePyroDepl = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //: 4|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioPyroIsoEn = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //: 5|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioCpFaultIn = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //: 6|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioPackContPowerEn = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //: 7|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioHvCablesOk = (rx_frame.data.u8[1] & (0x01U)); //: 8|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioHvpSelfEnable = ((rx_frame.data.u8[1] >> 1) & (0x01U)); //: 9|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioLed = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //: 10|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioCrashSignal = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //: 11|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioShuntDataReady = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //: 12|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioFcContPosAux = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //: 13|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioFcContNegAux = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //: 14|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioBmsEout = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //: 15|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioCpFaultOut = (rx_frame.data.u8[2] & (0x01U)); //: 16|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioPyroPor = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //: 17|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioShuntEn = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //: 18|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioHvpVerEn = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //: 19|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioPackCoontPosFlywheel = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //: 20|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioCpLatchEnable = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //: 21|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioPcsEnable = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //: 22|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioPcsDcdcPwmEnable = ((rx_frame.data.u8[2] >> 7) & (0x01U)); //: 23|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioPcsChargePwmEnable = (rx_frame.data.u8[3] & (0x01U)); //: 24|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioFcContPowerEnable = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //: 25|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioHvilEnable = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //: 26|1@1+ (1,0) [0|1] "" Receiver
HVP_gpioSecDrdy = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //: 27|1@1+ (1,0) [0|1] "" Receiver
HVP_hvp1v5Ref = ((rx_frame.data.u8[4] & (0xFFU)) << 4) |
((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|3] "V" Receiver
HVP_shuntCurrentDebug = ((rx_frame.data.u8[6] & (0xFFU)) << 8) |
(rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver
HVP_packCurrentMia = (rx_frame.data.u8[7] & (0x01U)); //: 56|1@1+ (1,0) [0|1] "" Receiver
HVP_auxCurrentMia = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //: 57|1@1+ (1,0) [0|1] "" Receiver
HVP_currentSenseMia = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|1@1+ (1,0) [0|1] "" Receiver
HVP_shuntRefVoltageMismatch = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //: 59|1@1+ (1,0) [0|1] "" Receiver
HVP_shuntThermistorMia = ((rx_frame.data.u8[7] >> 4) & (0x01U)); //: 60|1@1+ (1,0) [0|1] "" Receiver
HVP_shuntHwMia = ((rx_frame.data.u8[7] >> 5) & (0x01U)); //: 61|1@1+ (1,0) [0|1] "" Receiver
}
if (mux == 1) {
HVP_dcLinkVoltage = ((rx_frame.data.u8[2] & (0xFFU)) << 8) |
(rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver
HVP_packVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 8) |
(rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver
HVP_fcLinkVoltage = ((rx_frame.data.u8[6] & (0xFFU)) << 8) |
(rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver
}
if (mux == 2) {
HVP_packContVoltage = ((rx_frame.data.u8[1] & (0xFFU)) << 4) |
((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|30] "V" Receiver
HVP_packNegativeV = ((rx_frame.data.u8[3] & (0xFFU)) << 8) |
(rx_frame.data.u8[2] & (0xFFU)); //: 16|16@1- (0.1,0) [-550|550] "V" Receiver
HVP_packPositiveV = ((rx_frame.data.u8[5] & (0xFFU)) << 8) |
(rx_frame.data.u8[4] & (0xFFU)); //: 32|16@1- (0.1,0) [-550|550] "V" Receiver
HVP_pyroAnalog = ((rx_frame.data.u8[7] & (0x0FU)) << 8) |
(rx_frame.data.u8[6] & (0xFFU)); //: 48|12@1+ (0.1,0) [0|3] "V" Receiver
}
if (mux == 3) {
HVP_dcLinkNegativeV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) |
(rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver
HVP_dcLinkPositiveV = ((rx_frame.data.u8[4] & (0xFFU)) << 8) |
(rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-550|550] "V" Receiver
HVP_fcLinkNegativeV = ((rx_frame.data.u8[6] & (0xFFU)) << 8) |
(rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-550|550] "V" Receiver
}
if (mux == 4) {
HVP_fcContCoilCurrent = ((rx_frame.data.u8[1] & (0xFFU)) << 4) |
((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|7.5] "A" Receiver
HVP_fcContVoltage = ((rx_frame.data.u8[3] & (0x0FU)) << 8) |
(rx_frame.data.u8[2] & (0xFFU)); //: 16|12@1+ (0.1,0) [0|30] "V" Receiver
HVP_hvilInVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 4) |
((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|30] "V" Receiver
HVP_hvilOutVoltage = ((rx_frame.data.u8[6] & (0x0FU)) << 8) |
(rx_frame.data.u8[5] & (0xFFU)); //: 40|12@1+ (0.1,0) [0|30] "V" Receiver
}
if (mux == 5) {
HVP_fcLinkPositiveV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) |
(rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver
HVP_packContCoilCurrent = ((rx_frame.data.u8[4] & (0x0FU)) << 8) |
(rx_frame.data.u8[3] & (0xFFU)); //: 24|12@1+ (0.1,0) [0|7.5] "A" Receiver
HVP_battery12V = ((rx_frame.data.u8[5] & (0xFFU)) << 4) |
((rx_frame.data.u8[4] >> 4) & (0x0FU)); //: 36|12@1+ (0.1,0) [0|30] "V" Receiver
HVP_shuntRefVoltageDbg = ((rx_frame.data.u8[7] & (0xFFU)) << 8) |
(rx_frame.data.u8[6] & (0xFFU)); //: 48|16@1- (0.001,0) [-32.768|32.767] "V" Receiver
}
if (mux == 6) {
HVP_shuntAuxCurrentDbg = ((rx_frame.data.u8[2] & (0xFFU)) << 8) |
(rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver
HVP_shuntBarTempDbg = ((rx_frame.data.u8[4] & (0xFFU)) << 8) |
(rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.01,0) [-327.67|327.67] "C" Receiver
HVP_shuntAsicTempDbg = ((rx_frame.data.u8[6] & (0xFFU)) << 8) |
(rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.01,0) [-327.67|327.67] "C" Receiver
HVP_shuntAuxCurrentStatus = (rx_frame.data.u8[7] & (0x03U)); //: 56|2@1+ (1,0) [0|3] "" Receiver
HVP_shuntBarTempStatus = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|2@1+ (1,0) [0|3] "" Receiver
HVP_shuntAsicTempStatus = ((rx_frame.data.u8[7] >> 4) & (0x03U)); //: 60|2@1+ (1,0) [0|3] "" Receiver
}
break;
/* We ignore 0x3AA for now, as on later software/firmware this is a muxed frame so values aren't correct
case 0x3aa: //HVP_alertMatrix1
battery_WatchdogReset = (rx_frame.data.u8[0] & 0x01);
battery_PowerLossReset = ((rx_frame.data.u8[0] & 0x02) >> 1);
battery_SwAssertion = ((rx_frame.data.u8[0] & 0x04) >> 2);
battery_CrashEvent = ((rx_frame.data.u8[0] & 0x08) >> 3);
battery_OverDchgCurrentFault = ((rx_frame.data.u8[0] & 0x10) >> 4);
battery_OverChargeCurrentFault = ((rx_frame.data.u8[0] & 0x20) >> 5);
battery_OverCurrentFault = ((rx_frame.data.u8[0] & 0x40) >> 6);
battery_OverTemperatureFault = ((rx_frame.data.u8[0] & 0x80) >> 7);
battery_OverVoltageFault = (rx_frame.data.u8[1] & 0x01);
battery_UnderVoltageFault = ((rx_frame.data.u8[1] & 0x02) >> 1);
battery_PrimaryBmbMiaFault = ((rx_frame.data.u8[1] & 0x04) >> 2);
battery_SecondaryBmbMiaFault = ((rx_frame.data.u8[1] & 0x08) >> 3);
battery_BmbMismatchFault = ((rx_frame.data.u8[1] & 0x10) >> 4);
battery_BmsHviMiaFault = ((rx_frame.data.u8[1] & 0x20) >> 5);
battery_CpMiaFault = ((rx_frame.data.u8[1] & 0x40) >> 6);
battery_PcsMiaFault = ((rx_frame.data.u8[1] & 0x80) >> 7);
battery_BmsFault = (rx_frame.data.u8[2] & 0x01);
battery_PcsFault = ((rx_frame.data.u8[2] & 0x02) >> 1);
battery_CpFault = ((rx_frame.data.u8[2] & 0x04) >> 2);
battery_ShuntHwMiaFault = ((rx_frame.data.u8[2] & 0x08) >> 3);
battery_PyroMiaFault = ((rx_frame.data.u8[2] & 0x10) >> 4);
battery_hvsMiaFault = ((rx_frame.data.u8[2] & 0x20) >> 5);
battery_hviMiaFault = ((rx_frame.data.u8[2] & 0x40) >> 6);
battery_Supply12vFault = ((rx_frame.data.u8[2] & 0x80) >> 7);
battery_VerSupplyFault = (rx_frame.data.u8[3] & 0x01);
battery_HvilFault = ((rx_frame.data.u8[3] & 0x02) >> 1);
battery_BmsHvsMiaFault = ((rx_frame.data.u8[3] & 0x04) >> 2);
battery_PackVoltMismatchFault = ((rx_frame.data.u8[3] & 0x08) >> 3);
battery_EnsMiaFault = ((rx_frame.data.u8[3] & 0x10) >> 4);
battery_PackPosCtrArcFault = ((rx_frame.data.u8[3] & 0x20) >> 5);
battery_packNegCtrArcFault = ((rx_frame.data.u8[3] & 0x40) >> 6);
battery_ShuntHwAndBmsMiaFault = ((rx_frame.data.u8[3] & 0x80) >> 7);
battery_fcContHwFault = (rx_frame.data.u8[4] & 0x01);
battery_robinOverVoltageFault = ((rx_frame.data.u8[4] & 0x02) >> 1);
battery_packContHwFault = ((rx_frame.data.u8[4] & 0x04) >> 2);
battery_pyroFuseBlown = ((rx_frame.data.u8[4] & 0x08) >> 3);
battery_pyroFuseFailedToBlow = ((rx_frame.data.u8[4] & 0x10) >> 4);
battery_CpilFault = ((rx_frame.data.u8[4] & 0x20) >> 5);
battery_PackContactorFellOpen = ((rx_frame.data.u8[4] & 0x40) >> 6);
battery_FcContactorFellOpen = ((rx_frame.data.u8[4] & 0x80) >> 7);
battery_packCtrCloseBlocked = (rx_frame.data.u8[5] & 0x01);
battery_fcCtrCloseBlocked = ((rx_frame.data.u8[5] & 0x02) >> 1);
battery_packContactorForceOpen = ((rx_frame.data.u8[5] & 0x04) >> 2);
battery_fcContactorForceOpen = ((rx_frame.data.u8[5] & 0x08) >> 3);
battery_dcLinkOverVoltage = ((rx_frame.data.u8[5] & 0x10) >> 4);
battery_shuntOverTemperature = ((rx_frame.data.u8[5] & 0x20) >> 5);
battery_passivePyroDeploy = ((rx_frame.data.u8[5] & 0x40) >> 6);
battery_logUploadRequest = ((rx_frame.data.u8[5] & 0x80) >> 7);
battery_packCtrCloseFailed = (rx_frame.data.u8[6] & 0x01);
battery_fcCtrCloseFailed = ((rx_frame.data.u8[6] & 0x02) >> 1);
battery_shuntThermistorMia = ((rx_frame.data.u8[6] & 0x04) >> 2);
break;*/
case 0x320: //800 BMS_alertMatrix //BMS_alertMatrix 800 BMS_alertMatrix: 8 VEH
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
mux = (rx_frame.data.u8[0] & (0x0F));
if (mux == 0) { //mux0
BMS_matrixIndex = (rx_frame.data.u8[0] & (0x0F)); // 0|4@1+ (1,0) [0|0] "" X
BMS_a017_SW_Brick_OV = ((rx_frame.data.u8[2] >> 4) & (0x01)); //20|1@1+ (1,0) [0|0] "" X
BMS_a018_SW_Brick_UV = ((rx_frame.data.u8[2] >> 5) & (0x01)); //21|1@1+ (1,0) [0|0] "" X
BMS_a019_SW_Module_OT = ((rx_frame.data.u8[2] >> 6) & (0x01)); //22|1@1+ (1,0) [0|0] "" X
BMS_a021_SW_Dr_Limits_Regulation = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X
BMS_a022_SW_Over_Current = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X
BMS_a023_SW_Stack_OV = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X
BMS_a024_SW_Islanded_Brick = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X
BMS_a025_SW_PwrBalance_Anomaly = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X
BMS_a026_SW_HFCurrent_Anomaly = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X
BMS_a034_SW_Passive_Isolation = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X ?
BMS_a035_SW_Isolation = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //38|1@1+ (1,0) [0|0] "" X
BMS_a036_SW_HvpHvilFault = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X
BMS_a037_SW_Flood_Port_Open = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X
BMS_a039_SW_DC_Link_Over_Voltage = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X
BMS_a041_SW_Power_On_Reset = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X
BMS_a042_SW_MPU_Error = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X
BMS_a043_SW_Watch_Dog_Reset = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X
BMS_a044_SW_Assertion = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X
BMS_a045_SW_Exception = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X
BMS_a046_SW_Task_Stack_Usage = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X
BMS_a047_SW_Task_Stack_Overflow = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X
BMS_a048_SW_Log_Upload_Request = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X
BMS_a050_SW_Brick_Voltage_MIA = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X
BMS_a051_SW_HVC_Vref_Bad = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X
BMS_a052_SW_PCS_MIA = ((rx_frame.data.u8[6] >> 7) & (0x01U)); //55|1@1+ (1,0) [0|0] "" X
BMS_a053_SW_ThermalModel_Sanity = (rx_frame.data.u8[7] & (0x01U)); //56|1@1+ (1,0) [0|0] "" X
BMS_a054_SW_Ver_Supply_Fault = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X
BMS_a059_SW_Pack_Voltage_Sensing = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X
BMS_a060_SW_Leakage_Test_Failure = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X
}
if (mux == 1) { //mux1
BMS_a061_robinBrickOverVoltage = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //4|1@1+ (1,0) [0|0] "" X
BMS_a062_SW_BrickV_Imbalance = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X
BMS_a063_SW_ChargePort_Fault = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X
BMS_a064_SW_SOC_Imbalance = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|0] "" X
BMS_a069_SW_Low_Power = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X
BMS_a071_SW_SM_TransCon_Not_Met = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X
BMS_a075_SW_Chg_Disable_Failure = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //18|1@1+ (1,0) [0|0] "" X
BMS_a076_SW_Dch_While_Charging = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X
BMS_a077_SW_Charger_Regulation = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X
BMS_a081_SW_Ctr_Close_Blocked = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X
BMS_a082_SW_Ctr_Force_Open = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X
BMS_a083_SW_Ctr_Close_Failure = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X
BMS_a084_SW_Sleep_Wake_Aborted = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X
BMS_a087_SW_Feim_Test_Blocked = ((rx_frame.data.u8[3] >> 6) & (0x01U)); //30|1@1+ (1,0) [0|0] "" X
BMS_a088_SW_VcFront_MIA_InDrive = ((rx_frame.data.u8[3] >> 7) & (0x01U)); //31|1@1+ (1,0) [0|0] "" X
BMS_a089_SW_VcFront_MIA = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X
BMS_a090_SW_Gateway_MIA = ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|0] "" X
BMS_a091_SW_ChargePort_MIA = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X
BMS_a092_SW_ChargePort_Mia_On_Hv = ((rx_frame.data.u8[4] >> 3) & (0x01U)); //35|1@1+ (1,0) [0|0] "" X
BMS_a094_SW_Drive_Inverter_MIA = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X
BMS_a099_SW_BMB_Communication = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X
BMS_a105_SW_One_Module_Tsense = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X
BMS_a106_SW_All_Module_Tsense = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X
BMS_a107_SW_Stack_Voltage_MIA = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X
}
if (mux == 2) { //mux2
BMS_a121_SW_NVRAM_Config_Error = ((rx_frame.data.u8[0] >> 4) & (0x01U)); // 4|1@1+ (1,0) [0|0] "" X
BMS_a122_SW_BMS_Therm_Irrational = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X
BMS_a123_SW_Internal_Isolation = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X
BMS_a127_SW_shunt_SNA = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //10|1@1+ (1,0) [0|0] "" X
BMS_a128_SW_shunt_MIA = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //11|1@1+ (1,0) [0|0] "" X
BMS_a129_SW_VSH_Failure = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X
BMS_a130_IO_CAN_Error = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //13|1@1+ (1,0) [0|0] "" X
BMS_a131_Bleed_FET_Failure = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X
BMS_a132_HW_BMB_OTP_Uncorrctbl = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //15|1@1+ (1,0) [0|0] "" X
BMS_a134_SW_Delayed_Ctr_Off = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //17|1@1+ (1,0) [0|0] "" X
BMS_a136_SW_Module_OT_Warning = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X
BMS_a137_SW_Brick_UV_Warning = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X
BMS_a138_SW_Brick_OV_Warning = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //21|1@1+ (1,0) [0|0] "" X
BMS_a139_SW_DC_Link_V_Irrational = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //22|1@1+ (1,0) [0|0] "" X
BMS_a141_SW_BMB_Status_Warning = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X
BMS_a144_Hvp_Config_Mismatch = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X
BMS_a145_SW_SOC_Change = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X
BMS_a146_SW_Brick_Overdischarged = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X
BMS_a149_SW_Missing_Config_Block = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X
BMS_a151_SW_external_isolation = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X
BMS_a156_SW_BMB_Vref_bad = ((rx_frame.data.u8[4] >> 7) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X
BMS_a157_SW_HVP_HVS_Comms = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X
BMS_a158_SW_HVP_HVI_Comms = ((rx_frame.data.u8[5] >> 1) & (0x01U)); //41|1@1+ (1,0) [0|0] "" X
BMS_a159_SW_HVP_ECU_Error = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X
BMS_a161_SW_DI_Open_Request = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X
BMS_a162_SW_No_Power_For_Support = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X
BMS_a163_SW_Contactor_Mismatch = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X
BMS_a164_SW_Uncontrolled_Regen = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X
BMS_a165_SW_Pack_Partial_Weld = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X
BMS_a166_SW_Pack_Full_Weld = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X
BMS_a167_SW_FC_Partial_Weld = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X
BMS_a168_SW_FC_Full_Weld = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X
BMS_a169_SW_FC_Pack_Weld = ((rx_frame.data.u8[6] >> 4) & (0x01U)); //52|1@1+ (1,0) [0|0] "" X
BMS_a170_SW_Limp_Mode = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X
BMS_a171_SW_Stack_Voltage_Sense = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X
BMS_a174_SW_Charge_Failure = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X
BMS_a176_SW_GracefulPowerOff = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //59|1@1+ (1,0) [0|0] "" X
BMS_a179_SW_Hvp_12V_Fault = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X
BMS_a180_SW_ECU_reset_blocked = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X
}
break;
case 0x72A: //BMS_serialNumber
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//Pack serial number in ASCII: 00 54 47 33 32 31 32 30 (mux 0) .TG32120 + 01 32 30 30 33 41 48 58 (mux 1) .2003AHX = TG321202003AHX
if (rx_frame.data.u8[0] == 0x00 && !parsed_battery_serialNumber) { // Serial number 1-7
battery_serialNumber[0] = rx_frame.data.u8[1];
battery_serialNumber[1] = rx_frame.data.u8[2];
battery_serialNumber[2] = rx_frame.data.u8[3];
battery_serialNumber[3] = rx_frame.data.u8[4];
battery_serialNumber[4] = rx_frame.data.u8[5];
battery_serialNumber[5] = rx_frame.data.u8[6];
battery_serialNumber[6] = rx_frame.data.u8[7];
}
if (rx_frame.data.u8[0] == 0x01 && !parsed_battery_serialNumber) { // Serial number 8-14
battery_serialNumber[7] = rx_frame.data.u8[1];
battery_serialNumber[8] = rx_frame.data.u8[2];
battery_serialNumber[9] = rx_frame.data.u8[3];
battery_serialNumber[10] = rx_frame.data.u8[4];
battery_serialNumber[11] = rx_frame.data.u8[5];
battery_serialNumber[12] = rx_frame.data.u8[6];
battery_serialNumber[13] = rx_frame.data.u8[7];
}
if (battery_serialNumber[6] != 0 && battery_serialNumber[12] != 0 &&
!parsed_battery_serialNumber) { // Serial number complete
//Manufacture year
char yearStr[5]; // Full year string (including the "20" prefix)
snprintf(yearStr, sizeof(yearStr), "20%c%c", battery_serialNumber[3], battery_serialNumber[4]);
int year = atoi(yearStr);
//Manufacture day (Julian calendar)
char dayStr[4];
snprintf(dayStr, sizeof(dayStr), "%c%c%c", battery_serialNumber[5], battery_serialNumber[6],
battery_serialNumber[7]);
int day = atoi(dayStr);
battery_manufactureDate = dayOfYearToDate(year, day);
parsed_battery_serialNumber = true;
}
break;
case 0x300: //BMS_info
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//Display internal BMS info and other build/version data
if (rx_frame.data.u8[0] == 0x0A) { // Mux 10: BUILD_HWID_COMPONENTID
if (BMS_info_buildConfigId == 0) {
BMS_info_buildConfigId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 16, 16));
}
if (BMS_info_hardwareId == 0) {
BMS_info_hardwareId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 32, 16));
}
if (BMS_info_componentId == 0) {
BMS_info_componentId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 48, 16));
}
}
/*
if (rx_frame.data.u8[0] == 0x0B) { // Mux 11: PCBAID_ASSYID_USAGEID
if (BMS_info_pcbaId == 0) {BMS_info_pcbaId = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 16, 8));}
if (BMS_info_assemblyId == 0) {BMS_info_assemblyId = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 24, 8));}
if (BMS_info_usageId == 0) {BMS_info_usageId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 32, 16));}
if (BMS_info_subUsageId == 0) {BMS_info_subUsageId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 48, 16));}
}
if (rx_frame.data.u8[0] == 0x0D) { // Mux 13: APP_CRC
if (BMS_info_platformType == 0) {BMS_info_platformType = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 8, 8));}
if (BMS_info_appCrc == 0) {BMS_info_appCrc = static_cast<uint32_t>(extract_signal_value(rx_frame.data.u8, 32, 32));}
}
if (rx_frame.data.u8[0] == 0x12) { // Mux 18: BOOTLOADER_GITHASH
if (BMS_info_bootGitHash == 0) {BMS_info_bootGitHash = static_cast<uint64_t>(extract_signal_value(rx_frame.data.u8, 10, 54));}
}
if (rx_frame.data.u8[0] == 0x14) { // Mux 20: UDS_PROTOCOL_BOOTCRC
if (BMS_info_bootUdsProtoVersion == 0) {BMS_info_bootUdsProtoVersion = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 8, 8));}
if (BMS_info_bootCrc == 0) {BMS_info_bootCrc = static_cast<uint32_t>(extract_signal_value(rx_frame.data.u8, 32, 32));}
}
*/
break;
case 0x3C4: //PCS_info
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//Display internal PCS info and other build/version data
if (rx_frame.data.u8[0] == 0x0A) { // Mux 10: BUILD_HWID_COMPONENTID
if (PCS_info_buildConfigId == 0) {
PCS_info_buildConfigId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 16, 16));
}
if (PCS_info_hardwareId == 0) {
PCS_info_hardwareId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 32, 16));
}
if (PCS_info_componentId == 0) {
PCS_info_componentId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 48, 16));
}
}
/*
if (rx_frame.data.u8[0] == 0x0B) { // Mux 11: PCBAID_ASSYID_USAGEID
if (PCS_info_pcbaId == 0) {PCS_info_pcbaId = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 16, 8));}
if (PCS_info_assemblyId == 0) {PCS_info_assemblyId = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 24, 8));}
if (PCS_info_usageId == 0) {PCS_info_usageId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 32, 16));}
if (PCS_info_subUsageId == 0) {PCS_info_subUsageId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 48, 16));}
}
if (rx_frame.data.u8[0] == 0x0D) { // Mux 13: APP_CRC
PCS_info_platformType = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 8, 8));
PCS_info_appCrc = static_cast<uint32_t>(extract_signal_value(rx_frame.data.u8, 32, 32));
}
if (rx_frame.data.u8[0] == 0x10) { // Mux 16: SUBCOMPONENT
PCS_info_cpu2AppCrc = static_cast<uint32_t>(extract_signal_value(rx_frame.data.u8, 32, 32));
}
if (rx_frame.data.u8[0] == 0x12) { // Mux 18: BOOTLOADER_GITHASH
PCS_info_bootGitHash = static_cast<uint64_t>(extract_signal_value(rx_frame.data.u8, 10, 54));
}
if (rx_frame.data.u8[0] == 0x14) { // Mux 20: UDS_PROTOCOL_BOOTCRC
PCS_info_bootUdsProtoVersion = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 8, 8));
PCS_info_bootCrc = static_cast<uint32_t>(extract_signal_value(rx_frame.data.u8, 32, 32));
}
*/
//PCS Part Number in ASCII
if (rx_frame.data.u8[0] == 0x19 && !parsed_PCS_partNumber) { // Part number 1-7
PCS_partNumber[0] = rx_frame.data.u8[1];
PCS_partNumber[1] = rx_frame.data.u8[2];
PCS_partNumber[2] = rx_frame.data.u8[3];
PCS_partNumber[3] = rx_frame.data.u8[4];
PCS_partNumber[4] = rx_frame.data.u8[5];
PCS_partNumber[5] = rx_frame.data.u8[6];
PCS_partNumber[6] = rx_frame.data.u8[7];
}
if (rx_frame.data.u8[0] == 0x1A && !parsed_PCS_partNumber) { // Part number 8-14
PCS_partNumber[7] = rx_frame.data.u8[1];
PCS_partNumber[8] = rx_frame.data.u8[2];
PCS_partNumber[9] = rx_frame.data.u8[3];
PCS_partNumber[10] = rx_frame.data.u8[4];
PCS_partNumber[11] = rx_frame.data.u8[5];
PCS_partNumber[12] = rx_frame.data.u8[6];
}
if (PCS_partNumber[6] != 0 && PCS_partNumber[11] != 0) {
parsed_PCS_partNumber = true;
}
break;
case 0x310: //HVP_info
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//Display internal HVP info and other build/version data
if (rx_frame.data.u8[0] == 0x0A) { // Mux 10: BUILD_HWID_COMPONENTID
if (HVP_info_buildConfigId == 0) {
HVP_info_buildConfigId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 16, 16));
}
if (HVP_info_hardwareId == 0) {
HVP_info_hardwareId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 32, 16));
}
if (HVP_info_componentId == 0) {
HVP_info_componentId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 48, 16));
}
}
/*
if (rx_frame.data.u8[0] == 0x0B) { // Mux 11: PCBAID_ASSYID_USAGEID
if (HVP_info_pcbaId == 0) {HVP_info_pcbaId = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 16, 8));}
if (HVP_info_assemblyId == 0) {HVP_info_assemblyId = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 24, 8));}
if (HVP_info_usageId == 0) {HVP_info_usageId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 32, 16));}
if (HVP_info_subUsageId == 0) {HVP_info_subUsageId = static_cast<uint16_t>(extract_signal_value(rx_frame.data.u8, 48, 16));}
}
if (rx_frame.data.u8[0] == 0x0D) { // Mux 13: APP_CRC
HVP_info_platformType = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 8, 8));
HVP_info_appCrc = static_cast<uint32_t>(extract_signal_value(rx_frame.data.u8, 32, 32));
}
if (rx_frame.data.u8[0] == 0x12) { // Mux 18: BOOTLOADER_GITHASH
HVP_info_bootGitHash = static_cast<uint64_t>(extract_signal_value(rx_frame.data.u8, 10, 54));
}
if (rx_frame.data.u8[0] == 0x14) { // Mux 20: UDS_PROTOCOL_BOOTCRC
HVP_info_bootUdsProtoVersion = static_cast<uint8_t>(extract_signal_value(rx_frame.data.u8, 8, 8));
HVP_info_bootCrc = static_cast<uint32_t>(extract_signal_value(rx_frame.data.u8, 32, 32));
}
*/
break;
case 0x612: // CAN UDSs for BMS
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//BMS Query
if (stateMachineBMSQuery != 0xFF && stateMachineBMSReset == 0xFF) {
if (memcmp(rx_frame.data.u8, "\x02\x50\x03\xAA\xAA\xAA\xAA\xAA", 8) == 0) {
//Received initial response, proceed to actual query
logging.println("CAN UDS: Received BMS query initial handshake reply");
stateMachineBMSQuery = 1;
break;
}
if (memcmp(&rx_frame.data.u8[0], "\x10", 1) == 0) {
//Received first data frame
battery_partNumber[0] = rx_frame.data.u8[5];
battery_partNumber[1] = rx_frame.data.u8[6];
battery_partNumber[2] = rx_frame.data.u8[7];
logging.println("CAN UDS: Received BMS query data frame");
stateMachineBMSQuery = 2;
break;
}
if (memcmp(&rx_frame.data.u8[0], "\x21", 1) == 0) {
//Second part of part number after flow control
battery_partNumber[3] = rx_frame.data.u8[1];
battery_partNumber[4] = rx_frame.data.u8[2];
battery_partNumber[5] = rx_frame.data.u8[3];
battery_partNumber[6] = rx_frame.data.u8[4];
battery_partNumber[7] = rx_frame.data.u8[5];
battery_partNumber[8] = rx_frame.data.u8[6];
battery_partNumber[9] = rx_frame.data.u8[7];
logging.println("CAN UDS: Received BMS query second data frame");
break;
}
if (memcmp(&rx_frame.data.u8[0], "\x22", 1) == 0) {
//Final part of part number
battery_partNumber[10] = rx_frame.data.u8[1];
battery_partNumber[11] = rx_frame.data.u8[2];
logging.println("CAN UDS: Received BMS query final data frame");
break;
}
if (memcmp(rx_frame.data.u8, "\x23\x00\x00\x00\xAA\xAA\xAA\xAA", 8) == 0) {
//Received final frame
logging.println("CAN UDS: Received BMS query termination frame");
parsed_battery_partNumber = true;
stateMachineBMSQuery = 0xFF;
break;
}
}
//BMS Reset
if (stateMachineBMSQuery == 0xFF) { // Make sure this is reset request not query
if (memcmp(rx_frame.data.u8, "\x02\x67\x06\xAA\xAA\xAA\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: ECU unlocked");
} else if (memcmp(rx_frame.data.u8, "\x03\x7F\x11\x78\xAA\xAA\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: ECU reset request successful but ECU busy, response pending");
} else if (memcmp(rx_frame.data.u8, "\x02\x51\x01\xAA\xAA\xAA\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: ECU reset positive response, 1 second downtime");
}
}
break;
default:
break;
}
}
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, 0x80, 0x89}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0xA0, 0xA9}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0xC0, 0xC9}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0xE0, 0xE9}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0x00, 0x09}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0x20, 0x29}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x1CF, .data = {0x01, 0x00, 0x00, 0x1A, 0x1C, 0x02, 0x40, 0x49}}};
CAN_frame can_msg_118[] = {
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x61, 0x80, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x62, 0x81, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x63, 0x82, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x64, 0x83, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x65, 0x84, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x66, 0x85, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x67, 0x86, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x68, 0x87, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x69, 0x88, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x6A, 0x89, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x6B, 0x8A, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x6C, 0x8B, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x6D, 0x8C, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x6E, 0x8D, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x6F, 0x8E, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x70, 0x8F, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}}};
unsigned long lastSend1CF = 0;
unsigned long lastSend118 = 0;
int index_1CF = 0;
int index_118 = 0;
void TeslaBattery::transmit_can(unsigned long currentMillis) {
if (user_selected_tesla_digital_HVIL) { //Special S/X? mode for 2024+ batteries
if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) {
if (currentMillis - lastSend1CF >= 10) {
transmit_can_frame(&can_msg_1CF[index_1CF]);
index_1CF = (index_1CF + 1) % 8;
lastSend1CF = currentMillis;
}
if (currentMillis - lastSend118 >= 10) {
transmit_can_frame(&can_msg_118[index_118]);
index_118 = (index_118 + 1) % 16;
lastSend118 = currentMillis;
}
} else {
index_1CF = 0;
index_118 = 0;
}
}
//Send 10ms messages
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
previousMillis10 = currentMillis;
//0x118 DI_systemStatus
transmit_can_frame(&TESLA_118);
//0x2E1 VCFRONT_status
switch (muxNumber_TESLA_2E1) {
case 0:
transmit_can_frame(&TESLA_2E1_VEHICLE_AND_RAILS);
muxNumber_TESLA_2E1++;
break;
case 1:
transmit_can_frame(&TESLA_2E1_HOMELINK);
muxNumber_TESLA_2E1++;
break;
case 2:
transmit_can_frame(&TESLA_2E1_REFRIGERANT_SYSTEM);
muxNumber_TESLA_2E1++;
break;
case 3:
transmit_can_frame(&TESLA_2E1_LV_BATTERY_DEBUG);
muxNumber_TESLA_2E1++;
break;
case 4:
transmit_can_frame(&TESLA_2E1_MUX_5);
muxNumber_TESLA_2E1++;
break;
case 5:
transmit_can_frame(&TESLA_2E1_BODY_CONTROLS);
muxNumber_TESLA_2E1 = 0;
break;
default:
break;
}
//Generate next frames
generateFrameCounterChecksum(TESLA_118, 8, 4, 0, 8);
}
//Send 50ms messages
if (currentMillis - previousMillis50 >= INTERVAL_50_MS) {
previousMillis50 = currentMillis;
//0x221 VCFRONT_LVPowerState
if (vehicleState == 1) { // Drive
switch (muxNumber_TESLA_221) {
case 0:
generateMuxFrameCounterChecksum(TESLA_221_DRIVE_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8);
transmit_can_frame(&TESLA_221_DRIVE_Mux0);
muxNumber_TESLA_221++;
break;
case 1:
generateMuxFrameCounterChecksum(TESLA_221_DRIVE_Mux1, frameCounter_TESLA_221, 52, 4, 56, 8);
transmit_can_frame(&TESLA_221_DRIVE_Mux1);
muxNumber_TESLA_221 = 0;
break;
default:
break;
}
//Generate next new frame
frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16;
}
if (vehicleState == 2) { // Accessory
switch (muxNumber_TESLA_221) {
case 0:
generateMuxFrameCounterChecksum(TESLA_221_ACCESSORY_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8);
transmit_can_frame(&TESLA_221_ACCESSORY_Mux0);
muxNumber_TESLA_221++;
break;
case 1:
generateMuxFrameCounterChecksum(TESLA_221_ACCESSORY_Mux1, frameCounter_TESLA_221, 52, 4, 56, 8);
transmit_can_frame(&TESLA_221_ACCESSORY_Mux1);
muxNumber_TESLA_221 = 0;
break;
default:
break;
}
//Generate next new frame
frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16;
}
if (vehicleState == 3) { // Going down
switch (muxNumber_TESLA_221) {
case 0:
generateMuxFrameCounterChecksum(TESLA_221_GOING_DOWN_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8);
transmit_can_frame(&TESLA_221_GOING_DOWN_Mux0);
muxNumber_TESLA_221++;
break;
case 1:
generateMuxFrameCounterChecksum(TESLA_221_GOING_DOWN_Mux1, frameCounter_TESLA_221, 52, 4, 56, 8);
transmit_can_frame(&TESLA_221_GOING_DOWN_Mux1);
muxNumber_TESLA_221 = 0;
break;
default:
break;
}
//Generate next new frame
frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16;
}
if (vehicleState == 0) { // Off
switch (muxNumber_TESLA_221) {
case 0:
generateMuxFrameCounterChecksum(TESLA_221_OFF_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8);
transmit_can_frame(&TESLA_221_OFF_Mux0);
muxNumber_TESLA_221++;
break;
case 1:
generateMuxFrameCounterChecksum(TESLA_221_OFF_Mux1, frameCounter_TESLA_221, 52, 4, 56, 8);
transmit_can_frame(&TESLA_221_OFF_Mux1);
muxNumber_TESLA_221 = 0;
break;
default:
break;
}
//Generate next new frame
frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16;
}
//0x3C2 VCLEFT_switchStatus
switch (muxNumber_TESLA_3C2) {
case 0:
transmit_can_frame(&TESLA_3C2_Mux0);
muxNumber_TESLA_3C2++;
break;
case 1:
transmit_can_frame(&TESLA_3C2_Mux1);
muxNumber_TESLA_3C2 = 0;
break;
default:
break;
}
//0x39D IBST_status
transmit_can_frame(&TESLA_39D);
if (battery_contactor == 4) { // Contactors closed
// Frames to be sent only when contactors closed
//0x3A1 VCFRONT_vehicleStatus, critical otherwise VCFRONT_MIA triggered
transmit_can_frame(&TESLA_3A1[frameCounter_TESLA_3A1]);
frameCounter_TESLA_3A1 = (frameCounter_TESLA_3A1 + 1) % 16;
}
//Generate next frame
generateFrameCounterChecksum(TESLA_39D, 8, 4, 0, 8);
}
//Send 100ms messages
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis;
//0x102 VCLEFT_doorStatus, static
transmit_can_frame(&TESLA_102);
//0x103 VCRIGHT_doorStatus, static
transmit_can_frame(&TESLA_103);
//0x229 SCCM_rightStalk
transmit_can_frame(&TESLA_229);
//0x241 VCFRONT_coolant, static
transmit_can_frame(&TESLA_241);
//0x2D1 VCFRONT_okToUseHighPower, static
transmit_can_frame(&TESLA_2D1);
//0x2A8 CMPD_state
transmit_can_frame(&TESLA_2A8);
//0x2E8 EPBR_status
transmit_can_frame(&TESLA_2E8);
//0x7FF GTW_carConfig
switch (muxNumber_TESLA_7FF) {
case 0:
transmit_can_frame(&TESLA_7FF_Mux1);
muxNumber_TESLA_7FF++;
break;
case 1:
transmit_can_frame(&TESLA_7FF_Mux2);
muxNumber_TESLA_7FF++;
break;
case 2:
transmit_can_frame(&TESLA_7FF_Mux3);
muxNumber_TESLA_7FF++;
break;
case 3:
transmit_can_frame(&TESLA_7FF_Mux4);
muxNumber_TESLA_7FF++;
break;
case 4:
transmit_can_frame(&TESLA_7FF_Mux5);
muxNumber_TESLA_7FF = 0;
break;
default:
break;
}
//Generate next frames
generateTESLA_229(TESLA_229);
generateFrameCounterChecksum(TESLA_2A8, 52, 4, 56, 8);
generateFrameCounterChecksum(TESLA_2E8, 52, 4, 56, 8);
if (stateMachineClearIsolationFault != 0xFF) {
//This implementation should be rewritten to actually reply to the UDS responses sent by the BMS
//While this may work, it is not the correct way to implement this clearing logic
switch (stateMachineClearIsolationFault) {
case 0:
TESLA_602.data = {0x02, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineClearIsolationFault = 1;
break;
case 1:
TESLA_602.data = {0x30, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
// BMS should reply 02 50 C0 FF FF FF FF FF
stateMachineClearIsolationFault = 2;
break;
case 2:
TESLA_602.data = {0x10, 0x12, 0x27, 0x06, 0x35, 0x34, 0x37, 0x36};
transmit_can_frame(&TESLA_602);
// BMS should reply 7E FF FF FF FF FF FF
stateMachineClearIsolationFault = 3;
break;
case 3:
TESLA_602.data = {0x21, 0x31, 0x30, 0x33, 0x32, 0x3D, 0x3C, 0x3F};
transmit_can_frame(&TESLA_602);
stateMachineClearIsolationFault = 4;
break;
case 4:
TESLA_602.data = {0x22, 0x3E, 0x39, 0x38, 0x3B, 0x3A, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
//Should generate a CAN UDS log message indicating ECU unlocked
stateMachineClearIsolationFault = 5;
break;
case 5:
TESLA_602.data = {0x04, 0x31, 0x01, 0x04, 0x0A, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineClearIsolationFault = 0xFF;
break;
default:
//Something went wrong. Reset all and cancel
stateMachineClearIsolationFault = 0xFF;
break;
}
}
if (stateMachineBMSReset != 0xFF) {
//This implementation should be rewritten to actually reply to the UDS responses sent by the BMS
//While this may work, it is not the correct way to implement this reset logic
switch (stateMachineBMSReset) {
case 0:
TESLA_602.data = {0x02, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineBMSReset = 1;
break;
case 1:
TESLA_602.data = {0x30, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineBMSReset = 2;
break;
case 2:
TESLA_602.data = {0x10, 0x12, 0x27, 0x06, 0x35, 0x34, 0x37, 0x36};
transmit_can_frame(&TESLA_602);
stateMachineBMSReset = 3;
break;
case 3:
TESLA_602.data = {0x21, 0x31, 0x30, 0x33, 0x32, 0x3D, 0x3C, 0x3F};
transmit_can_frame(&TESLA_602);
stateMachineBMSReset = 4;
break;
case 4:
TESLA_602.data = {0x22, 0x3E, 0x39, 0x38, 0x3B, 0x3A, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
//Should generate a CAN UDS log message indicating ECU unlocked
stateMachineBMSReset = 5;
break;
case 5:
TESLA_602.data = {0x02, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineBMSReset = 6;
break;
case 6:
TESLA_602.data = {0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineBMSReset = 7;
break;
case 7:
TESLA_602.data = {0x02, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
//Should generate a CAN UDS log message(s) indicating ECU has reset
stateMachineBMSReset = 0xFF;
break;
default:
//Something went wrong. Reset all and cancel
stateMachineBMSReset = 0xFF;
break;
}
}
if (stateMachineSOCReset != 0xFF) {
//This implementation should be rewritten to actually reply to the UDS responses sent by the BMS
//While this may work, it is not the correct way to implement this
switch (stateMachineSOCReset) {
case 0:
TESLA_602.data = {0x02, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineSOCReset = 1;
break;
case 1:
TESLA_602.data = {0x30, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineSOCReset = 2;
break;
case 2:
TESLA_602.data = {0x10, 0x12, 0x27, 0x06, 0x35, 0x34, 0x37, 0x36};
transmit_can_frame(&TESLA_602);
stateMachineSOCReset = 3;
break;
case 3:
TESLA_602.data = {0x21, 0x31, 0x30, 0x33, 0x32, 0x3D, 0x3C, 0x3F};
transmit_can_frame(&TESLA_602);
stateMachineSOCReset = 4;
break;
case 4:
TESLA_602.data = {0x22, 0x3E, 0x39, 0x38, 0x3B, 0x3A, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
//Should generate a CAN UDS log message indicating ECU unlocked
stateMachineSOCReset = 5;
break;
case 5:
TESLA_602.data = {0x04, 0x31, 0x01, 0x04, 0x07, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
stateMachineSOCReset = 0xFF;
break;
default:
//Something went wrong. Reset all and cancel
stateMachineSOCReset = 0xFF;
break;
}
}
if (stateMachineBMSQuery != 0xFF) {
//This implementation should be rewritten to actually reply to the UDS responses sent by the BMS
//While this may work, it is not the correct way to implement this query logic
switch (stateMachineBMSQuery) {
case 0:
//Initial request
logging.println("CAN UDS: Sending BMS query initial handshake");
TESLA_602.data = {0x02, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
break;
case 1:
//Send query
logging.println("CAN UDS: Sending BMS query for pack part number");
TESLA_602.data = {0x03, 0x22, 0xF0, 0x14, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
break;
case 2:
//Flow control
logging.println("CAN UDS: Sending BMS query flow control");
TESLA_602.data = {0x30, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&TESLA_602);
break;
case 3:
break;
case 4:
break;
default:
//Something went wrong. Reset all and cancel
stateMachineBMSQuery = 0xFF;
break;
}
}
}
//Send 500ms messages
if (currentMillis - previousMillis500 >= INTERVAL_500_MS) {
previousMillis500 = currentMillis;
transmit_can_frame(&TESLA_213);
transmit_can_frame(&TESLA_284);
transmit_can_frame(&TESLA_293);
transmit_can_frame(&TESLA_313);
transmit_can_frame(&TESLA_333);
if (TESLA_334_INITIAL_SENT == false) {
transmit_can_frame(&TESLA_334_INITIAL);
TESLA_334_INITIAL_SENT = true;
} else {
transmit_can_frame(&TESLA_334);
}
transmit_can_frame(&TESLA_3B3);
transmit_can_frame(&TESLA_55A);
//Generate next frames
generateTESLA_213(TESLA_213);
generateFrameCounterChecksum(TESLA_293, 52, 4, 56, 8);
generateFrameCounterChecksum(TESLA_313, 52, 4, 56, 8);
generateFrameCounterChecksum(TESLA_334, 52, 4, 56, 8);
}
//Send 1000ms messages
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis;
transmit_can_frame(&TESLA_082);
transmit_can_frame(&TESLA_321);
//Generate next frames
generateFrameCounterChecksum(TESLA_321, 52, 4, 56, 8);
}
}
void printDebugIfActive(uint8_t symbol, const char* message) {
if (symbol == 1) {
logging.println(message);
}
}
void TeslaBattery::printFaultCodesIfActive() {
if (battery_packCtrsClosingBlocked &&
battery_packContactorSetState != 5) { // Contactors blocked closing and not already closed
logging.println("ERROR: Check high voltage connectors and interlock circuit, closing contactors not allowed!");
}
if (battery_pyroTestInProgress) {
logging.println("ERROR: Please wait for pyro test to finish, HV cables successfully seated!");
}
if (datalayer.system.status.inverter_allows_contactor_closing == false) {
logging.println(
"ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter "
"or "
"disable the inverter protocol to proceed in Tesla battery testing mode.");
}
// Check each symbol and print debug information if its value is 1
// 0X3AA: 938 HVP_alertMatrix1
//printDebugIfActive(battery_WatchdogReset, "ERROR: The processor has experienced a reset due to watchdog reset"); //Uncommented due to not affecting usage
printDebugIfActive(battery_PowerLossReset, "ERROR: The processor has experienced a reset due to power loss");
printDebugIfActive(battery_SwAssertion, "ERROR: An internal software assertion has failed");
printDebugIfActive(battery_CrashEvent, "ERROR: crash signal is detected by HVP");
printDebugIfActive(battery_OverDchgCurrentFault,
"ERROR: Pack discharge current is above the safe max discharge current limit!");
printDebugIfActive(battery_OverChargeCurrentFault,
"ERROR: Pack charge current is above the safe max charge current limit!");
printDebugIfActive(battery_OverCurrentFault, "ERROR: Pack current (discharge or charge) is above max current limit!");
printDebugIfActive(battery_OverTemperatureFault,
"ERROR: A pack module temperature is above the max temperature limit!");
printDebugIfActive(battery_OverVoltageFault, "ERROR: A brick voltage is above maximum voltage limit");
printDebugIfActive(battery_UnderVoltageFault, "ERROR: A brick voltage is below minimum voltage limit");
printDebugIfActive(battery_PrimaryBmbMiaFault,
"ERROR: Voltage and temperature readings from primary BMB chain are mia");
printDebugIfActive(battery_SecondaryBmbMiaFault,
"ERROR: Voltage and temperature readings from secondary BMB chain are mia");
printDebugIfActive(battery_BmbMismatchFault,
"ERROR: Primary and secondary BMB chain readings don't match with each other");
printDebugIfActive(battery_BmsHviMiaFault, "ERROR: BMS node is mia on HVS or HVI CAN");
//printDebugIfActive(battery_CpMiaFault, "ERROR: CP node is mia on HVS CAN"); //Uncommented due to not affecting usage
printDebugIfActive(battery_PcsMiaFault, "ERROR: PCS node is mia on HVS CAN");
//printDebugIfActive(battery_BmsFault, "ERROR: BmsFault is active"); //Uncommented due to not affecting usage
printDebugIfActive(battery_PcsFault, "ERROR: PcsFault is active");
//printDebugIfActive(battery_CpFault, "ERROR: CpFault is active"); //Uncommented due to not affecting usage
printDebugIfActive(battery_ShuntHwMiaFault, "ERROR: Shunt current reading is not available");
printDebugIfActive(battery_PyroMiaFault, "ERROR: Pyro squib is not connected");
printDebugIfActive(battery_hvsMiaFault, "ERROR: Pack contactor hw fault");
printDebugIfActive(battery_hviMiaFault, "ERROR: FC contactor hw fault");
printDebugIfActive(battery_Supply12vFault, "ERROR: Low voltage (12V) battery is below minimum voltage threshold");
printDebugIfActive(battery_VerSupplyFault, "ERROR: Energy reserve voltage supply is below minimum voltage threshold");
printDebugIfActive(battery_HvilFault, "ERROR: High Voltage Inter Lock fault is detected");
printDebugIfActive(battery_BmsHvsMiaFault, "ERROR: BMS node is mia on HVS or HVI CAN");
printDebugIfActive(battery_PackVoltMismatchFault,
"ERROR: Pack voltage doesn't match approximately with sum of brick voltages");
//printDebugIfActive(battery_EnsMiaFault, "ERROR: ENS line is not connected to HVC"); //Uncommented due to not affecting usage
printDebugIfActive(battery_PackPosCtrArcFault, "ERROR: HVP detectes series arc at pack contactor");
printDebugIfActive(battery_packNegCtrArcFault, "ERROR: HVP detectes series arc at FC contactor");
printDebugIfActive(battery_ShuntHwAndBmsMiaFault, "ERROR: ShuntHwAndBmsMiaFault is active");
printDebugIfActive(battery_fcContHwFault, "ERROR: fcContHwFault is active");
printDebugIfActive(battery_robinOverVoltageFault, "ERROR: robinOverVoltageFault is active");
printDebugIfActive(battery_packContHwFault, "ERROR: packContHwFault is active");
printDebugIfActive(battery_pyroFuseBlown, "ERROR: pyroFuseBlown is active");
printDebugIfActive(battery_pyroFuseFailedToBlow, "ERROR: pyroFuseFailedToBlow is active");
//printDebugIfActive(battery_CpilFault, "ERROR: CpilFault is active"); //Uncommented due to not affecting usage
printDebugIfActive(battery_PackContactorFellOpen, "ERROR: PackContactorFellOpen is active");
printDebugIfActive(battery_FcContactorFellOpen, "ERROR: FcContactorFellOpen is active");
printDebugIfActive(battery_packCtrCloseBlocked, "ERROR: packCtrCloseBlocked is active");
printDebugIfActive(battery_fcCtrCloseBlocked, "ERROR: fcCtrCloseBlocked is active");
printDebugIfActive(battery_packContactorForceOpen, "ERROR: packContactorForceOpen is active");
printDebugIfActive(battery_fcContactorForceOpen, "ERROR: fcContactorForceOpen is active");
printDebugIfActive(battery_dcLinkOverVoltage, "ERROR: dcLinkOverVoltage is active");
printDebugIfActive(battery_shuntOverTemperature, "ERROR: shuntOverTemperature is active");
printDebugIfActive(battery_passivePyroDeploy, "ERROR: passivePyroDeploy is active");
printDebugIfActive(battery_logUploadRequest, "ERROR: logUploadRequest is active");
printDebugIfActive(battery_packCtrCloseFailed, "ERROR: packCtrCloseFailed is active");
printDebugIfActive(battery_fcCtrCloseFailed, "ERROR: fcCtrCloseFailed is active");
printDebugIfActive(battery_shuntThermistorMia, "ERROR: shuntThermistorMia is active");
// 0x320 800 BMS_alertMatrix
printDebugIfActive(BMS_a017_SW_Brick_OV, "ERROR: BMS_a017_SW_Brick_OV");
printDebugIfActive(BMS_a018_SW_Brick_UV, "ERROR: BMS_a018_SW_Brick_UV");
printDebugIfActive(BMS_a019_SW_Module_OT, "ERROR: BMS_a019_SW_Module_OT");
printDebugIfActive(BMS_a021_SW_Dr_Limits_Regulation, "ERROR: BMS_a021_SW_Dr_Limits_Regulation");
//printDebugIfActive(BMS_a022_SW_Over_Current, "ERROR: BMS_a022_SW_Over_Current");
printDebugIfActive(BMS_a023_SW_Stack_OV, "ERROR: BMS_a023_SW_Stack_OV");
printDebugIfActive(BMS_a024_SW_Islanded_Brick, "ERROR: BMS_a024_SW_Islanded_Brick");
printDebugIfActive(BMS_a025_SW_PwrBalance_Anomaly, "ERROR: BMS_a025_SW_PwrBalance_Anomaly");
printDebugIfActive(BMS_a026_SW_HFCurrent_Anomaly, "ERROR: BMS_a026_SW_HFCurrent_Anomaly");
printDebugIfActive(BMS_a034_SW_Passive_Isolation, "ERROR: BMS_a034_SW_Passive_Isolation");
printDebugIfActive(BMS_a035_SW_Isolation, "ERROR: BMS_a035_SW_Isolation");
printDebugIfActive(BMS_a036_SW_HvpHvilFault, "ERROR: BMS_a036_SW_HvpHvilFault");
printDebugIfActive(BMS_a037_SW_Flood_Port_Open, "ERROR: BMS_a037_SW_Flood_Port_Open");
printDebugIfActive(BMS_a039_SW_DC_Link_Over_Voltage, "ERROR: BMS_a039_SW_DC_Link_Over_Voltage");
printDebugIfActive(BMS_a041_SW_Power_On_Reset, "ERROR: BMS_a041_SW_Power_On_Reset");
printDebugIfActive(BMS_a042_SW_MPU_Error, "ERROR: BMS_a042_SW_MPU_Error");
printDebugIfActive(BMS_a043_SW_Watch_Dog_Reset, "ERROR: BMS_a043_SW_Watch_Dog_Reset");
printDebugIfActive(BMS_a044_SW_Assertion, "ERROR: BMS_a044_SW_Assertion");
printDebugIfActive(BMS_a045_SW_Exception, "ERROR: BMS_a045_SW_Exception");
printDebugIfActive(BMS_a046_SW_Task_Stack_Usage, "ERROR: BMS_a046_SW_Task_Stack_Usage");
printDebugIfActive(BMS_a047_SW_Task_Stack_Overflow, "ERROR: BMS_a047_SW_Task_Stack_Overflow");
printDebugIfActive(BMS_a048_SW_Log_Upload_Request, "ERROR: BMS_a048_SW_Log_Upload_Request");
//printDebugIfActive(BMS_a050_SW_Brick_Voltage_MIA, "ERROR: BMS_a050_SW_Brick_Voltage_MIA");
printDebugIfActive(BMS_a051_SW_HVC_Vref_Bad, "ERROR: BMS_a051_SW_HVC_Vref_Bad");
printDebugIfActive(BMS_a052_SW_PCS_MIA, "ERROR: BMS_a052_SW_PCS_MIA");
printDebugIfActive(BMS_a053_SW_ThermalModel_Sanity, "ERROR: BMS_a053_SW_ThermalModel_Sanity");
printDebugIfActive(BMS_a054_SW_Ver_Supply_Fault, "ERROR: BMS_a054_SW_Ver_Supply_Fault");
printDebugIfActive(BMS_a059_SW_Pack_Voltage_Sensing, "ERROR: BMS_a059_SW_Pack_Voltage_Sensing");
printDebugIfActive(BMS_a060_SW_Leakage_Test_Failure, "ERROR: BMS_a060_SW_Leakage_Test_Failure");
printDebugIfActive(BMS_a061_robinBrickOverVoltage, "ERROR: BMS_a061_robinBrickOverVoltage");
printDebugIfActive(BMS_a062_SW_BrickV_Imbalance, "ERROR: BMS_a062_SW_BrickV_Imbalance");
//printDebugIfActive(BMS_a063_SW_ChargePort_Fault, "ERROR: BMS_a063_SW_ChargePort_Fault");
printDebugIfActive(BMS_a064_SW_SOC_Imbalance, "ERROR: BMS_a064_SW_SOC_Imbalance");
printDebugIfActive(BMS_a069_SW_Low_Power, "ERROR: BMS_a069_SW_Low_Power");
printDebugIfActive(BMS_a071_SW_SM_TransCon_Not_Met, "ERROR: BMS_a071_SW_SM_TransCon_Not_Met");
printDebugIfActive(BMS_a075_SW_Chg_Disable_Failure, "ERROR: BMS_a075_SW_Chg_Disable_Failure");
printDebugIfActive(BMS_a076_SW_Dch_While_Charging, "ERROR: BMS_a076_SW_Dch_While_Charging");
printDebugIfActive(BMS_a077_SW_Charger_Regulation, "ERROR: BMS_a077_SW_Charger_Regulation");
printDebugIfActive(BMS_a081_SW_Ctr_Close_Blocked, "ERROR: BMS_a081_SW_Ctr_Close_Blocked");
printDebugIfActive(BMS_a082_SW_Ctr_Force_Open, "ERROR: BMS_a082_SW_Ctr_Force_Open");
printDebugIfActive(BMS_a083_SW_Ctr_Close_Failure, "ERROR: BMS_a083_SW_Ctr_Close_Failure");
printDebugIfActive(BMS_a084_SW_Sleep_Wake_Aborted, "ERROR: BMS_a084_SW_Sleep_Wake_Aborted");
printDebugIfActive(BMS_a087_SW_Feim_Test_Blocked, "ERROR: BMS_a087_SW_Feim_Test_Blocked");
printDebugIfActive(BMS_a088_SW_VcFront_MIA_InDrive, "ERROR: BMS_a088_SW_VcFront_MIA_InDrive");
printDebugIfActive(BMS_a089_SW_VcFront_MIA, "ERROR: BMS_a089_SW_VcFront_MIA");
printDebugIfActive(BMS_a090_SW_Gateway_MIA, "ERROR: BMS_a090_SW_Gateway_MIA");
//printDebugIfActive(BMS_a091_SW_ChargePort_MIA, "ERROR: BMS_a091_SW_ChargePort_MIA");
//printDebugIfActive(BMS_a092_SW_ChargePort_Mia_On_Hv, "ERROR: BMS_a092_SW_ChargePort_Mia_On_Hv");
//printDebugIfActive(BMS_a094_SW_Drive_Inverter_MIA, "ERROR: BMS_a094_SW_Drive_Inverter_MIA");
printDebugIfActive(BMS_a099_SW_BMB_Communication, "ERROR: BMS_a099_SW_BMB_Communication");
printDebugIfActive(BMS_a105_SW_One_Module_Tsense, "ERROR: BMS_a105_SW_One_Module_Tsense");
printDebugIfActive(BMS_a106_SW_All_Module_Tsense, "ERROR: BMS_a106_SW_All_Module_Tsense");
printDebugIfActive(BMS_a107_SW_Stack_Voltage_MIA, "ERROR: BMS_a107_SW_Stack_Voltage_MIA");
printDebugIfActive(BMS_a121_SW_NVRAM_Config_Error, "ERROR: BMS_a121_SW_NVRAM_Config_Error");
printDebugIfActive(BMS_a122_SW_BMS_Therm_Irrational, "ERROR: BMS_a122_SW_BMS_Therm_Irrational");
printDebugIfActive(BMS_a123_SW_Internal_Isolation, "ERROR: BMS_a123_SW_Internal_Isolation");
printDebugIfActive(BMS_a127_SW_shunt_SNA, "ERROR: BMS_a127_SW_shunt_SNA");
printDebugIfActive(BMS_a128_SW_shunt_MIA, "ERROR: BMS_a128_SW_shunt_MIA");
printDebugIfActive(BMS_a129_SW_VSH_Failure, "ERROR: BMS_a129_SW_VSH_Failure");
printDebugIfActive(BMS_a130_IO_CAN_Error, "ERROR: BMS_a130_IO_CAN_Error");
printDebugIfActive(BMS_a131_Bleed_FET_Failure, "ERROR: BMS_a131_Bleed_FET_Failure");
printDebugIfActive(BMS_a132_HW_BMB_OTP_Uncorrctbl, "ERROR: BMS_a132_HW_BMB_OTP_Uncorrctbl");
printDebugIfActive(BMS_a134_SW_Delayed_Ctr_Off, "ERROR: BMS_a134_SW_Delayed_Ctr_Off");
printDebugIfActive(BMS_a136_SW_Module_OT_Warning, "ERROR: BMS_a136_SW_Module_OT_Warning");
printDebugIfActive(BMS_a137_SW_Brick_UV_Warning, "ERROR: BMS_a137_SW_Brick_UV_Warning");
printDebugIfActive(BMS_a139_SW_DC_Link_V_Irrational, "ERROR: BMS_a139_SW_DC_Link_V_Irrational");
printDebugIfActive(BMS_a141_SW_BMB_Status_Warning, "ERROR: BMS_a141_SW_BMB_Status_Warning");
printDebugIfActive(BMS_a144_Hvp_Config_Mismatch, "ERROR: BMS_a144_Hvp_Config_Mismatch");
printDebugIfActive(BMS_a145_SW_SOC_Change, "ERROR: BMS_a145_SW_SOC_Change");
printDebugIfActive(BMS_a146_SW_Brick_Overdischarged, "ERROR: BMS_a146_SW_Brick_Overdischarged");
printDebugIfActive(BMS_a149_SW_Missing_Config_Block, "ERROR: BMS_a149_SW_Missing_Config_Block");
printDebugIfActive(BMS_a151_SW_external_isolation, "ERROR: BMS_a151_SW_external_isolation");
printDebugIfActive(BMS_a156_SW_BMB_Vref_bad, "ERROR: BMS_a156_SW_BMB_Vref_bad");
printDebugIfActive(BMS_a157_SW_HVP_HVS_Comms, "ERROR: BMS_a157_SW_HVP_HVS_Comms");
printDebugIfActive(BMS_a158_SW_HVP_HVI_Comms, "ERROR: BMS_a158_SW_HVP_HVI_Comms");
printDebugIfActive(BMS_a159_SW_HVP_ECU_Error, "ERROR: BMS_a159_SW_HVP_ECU_Error");
printDebugIfActive(BMS_a161_SW_DI_Open_Request, "ERROR: BMS_a161_SW_DI_Open_Request");
printDebugIfActive(BMS_a162_SW_No_Power_For_Support, "ERROR: BMS_a162_SW_No_Power_For_Support");
printDebugIfActive(BMS_a163_SW_Contactor_Mismatch, "ERROR: BMS_a163_SW_Contactor_Mismatch");
printDebugIfActive(BMS_a164_SW_Uncontrolled_Regen, "ERROR: BMS_a164_SW_Uncontrolled_Regen");
printDebugIfActive(BMS_a165_SW_Pack_Partial_Weld, "ERROR: BMS_a165_SW_Pack_Partial_Weld");
printDebugIfActive(BMS_a166_SW_Pack_Full_Weld, "ERROR: BMS_a166_SW_Pack_Full_Weld");
printDebugIfActive(BMS_a167_SW_FC_Partial_Weld, "ERROR: BMS_a167_SW_FC_Partial_Weld");
printDebugIfActive(BMS_a168_SW_FC_Full_Weld, "ERROR: BMS_a168_SW_FC_Full_Weld");
printDebugIfActive(BMS_a169_SW_FC_Pack_Weld, "ERROR: BMS_a169_SW_FC_Pack_Weld");
//printDebugIfActive(BMS_a170_SW_Limp_Mode, "ERROR: BMS_a170_SW_Limp_Mode");
printDebugIfActive(BMS_a171_SW_Stack_Voltage_Sense, "ERROR: BMS_a171_SW_Stack_Voltage_Sense");
printDebugIfActive(BMS_a174_SW_Charge_Failure, "ERROR: BMS_a174_SW_Charge_Failure");
printDebugIfActive(BMS_a176_SW_GracefulPowerOff, "ERROR: BMS_a176_SW_GracefulPowerOff");
printDebugIfActive(BMS_a179_SW_Hvp_12V_Fault, "ERROR: BMS_a179_SW_Hvp_12V_Fault");
printDebugIfActive(BMS_a180_SW_ECU_reset_blocked, "ERROR: BMS_a180_SW_ECU_reset_blocked");
}
void TeslaModel3YBattery::setup(void) { // Performs one time setup at startup
if (allows_contactor_closing) {
*allows_contactor_closing = true;
}
//0x7FF GTW CAN frame values
//Mux1
write_signal_value(&TESLA_7FF_Mux1, 16, 16, user_selected_tesla_GTW_country, false);
write_signal_value(&TESLA_7FF_Mux1, 11, 1, user_selected_tesla_GTW_country, false);
//Mux3
write_signal_value(&TESLA_7FF_Mux3, 8, 4, user_selected_tesla_GTW_mapRegion, false);
write_signal_value(&TESLA_7FF_Mux3, 18, 3, user_selected_tesla_GTW_chassisType, false);
write_signal_value(&TESLA_7FF_Mux3, 32, 5, user_selected_tesla_GTW_packEnergy, false);
strncpy(datalayer.system.info.battery_protocol, Name, 63);
datalayer.system.info.battery_protocol[63] = '\0';
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_LFP;
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_LFP;
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_LFP;
} else {
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_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;
}
}
void TeslaModelSXBattery::setup(void) {
if (allows_contactor_closing) {
*allows_contactor_closing = true;
}
strncpy(datalayer.system.info.battery_protocol, Name, 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;
}