Merge branch 'main' into bugfix/atto3-end-of-charge-ramping

This commit is contained in:
Daniel Öster 2025-05-05 17:10:56 +03:00
commit aa520e171b
70 changed files with 290 additions and 345 deletions

View file

@ -52,6 +52,7 @@ volatile unsigned long long bmsResetTimeOffset = 0;
const char* version_number = "8.12.dev"; const char* version_number = "8.12.dev";
// Interval timers // Interval timers
volatile unsigned long currentMillis = 0;
unsigned long previousMillis10ms = 0; unsigned long previousMillis10ms = 0;
unsigned long previousMillisUpdateVal = 0; unsigned long previousMillisUpdateVal = 0;
unsigned long lastMillisOverflowCheck = 0; unsigned long lastMillisOverflowCheck = 0;
@ -100,12 +101,13 @@ void setup() {
init_precharge_control(); init_precharge_control();
#endif // PRECHARGE_CONTROL #endif // PRECHARGE_CONTROL
init_rs485();
#if defined(CAN_INVERTER_SELECTED) || defined(MODBUS_INVERTER_SELECTED) || defined(RS485_INVERTER_SELECTED) #if defined(CAN_INVERTER_SELECTED) || defined(MODBUS_INVERTER_SELECTED) || defined(RS485_INVERTER_SELECTED)
setup_inverter(); setup_inverter();
#endif #endif
setup_battery(); setup_battery();
init_rs485();
#ifdef EQUIPMENT_STOP_BUTTON #ifdef EQUIPMENT_STOP_BUTTON
init_equipment_stop_button(); init_equipment_stop_button();
#endif #endif
@ -208,6 +210,7 @@ void core_loop(void*) {
led_init(); led_init();
while (true) { while (true) {
START_TIME_MEASUREMENT(all); START_TIME_MEASUREMENT(all);
START_TIME_MEASUREMENT(comm); START_TIME_MEASUREMENT(comm);
#ifdef EQUIPMENT_STOP_BUTTON #ifdef EQUIPMENT_STOP_BUTTON
@ -227,8 +230,12 @@ void core_loop(void*) {
#endif // WEBSERVER #endif // WEBSERVER
// Process // Process
if (millis() - previousMillis10ms >= INTERVAL_10_MS) { currentMillis = millis();
previousMillis10ms = millis(); if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) {
if ((currentMillis - previousMillis10ms >= INTERVAL_10_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_TASK_OVERRUN, (currentMillis - previousMillis10ms));
}
previousMillis10ms = currentMillis;
#ifdef FUNCTION_TIME_MEASUREMENT #ifdef FUNCTION_TIME_MEASUREMENT
START_TIME_MEASUREMENT(time_10ms); START_TIME_MEASUREMENT(time_10ms);
#endif #endif
@ -242,8 +249,8 @@ void core_loop(void*) {
#endif #endif
} }
if (millis() - previousMillisUpdateVal >= INTERVAL_1_S) { if (currentMillis - previousMillisUpdateVal >= INTERVAL_1_S) {
previousMillisUpdateVal = millis(); // Order matters on the update_loop! previousMillisUpdateVal = currentMillis; // Order matters on the update_loop!
#ifdef FUNCTION_TIME_MEASUREMENT #ifdef FUNCTION_TIME_MEASUREMENT
START_TIME_MEASUREMENT(time_values); START_TIME_MEASUREMENT(time_values);
#endif #endif
@ -264,7 +271,7 @@ void core_loop(void*) {
START_TIME_MEASUREMENT(cantx); START_TIME_MEASUREMENT(cantx);
#endif #endif
// Output // Output
transmit_can(); // Send CAN messages to all components transmit_can(currentMillis); // Send CAN messages to all components
#ifdef RS485_BATTERY_SELECTED #ifdef RS485_BATTERY_SELECTED
transmit_rs485(); transmit_rs485();

View file

@ -3,14 +3,17 @@
// These functions adapt the old C-style global functions battery-API to the // These functions adapt the old C-style global functions battery-API to the
// object-oriented battery API. // object-oriented battery API.
#ifdef OO_BATTERY_SELECTED // The instantiated class is defined by the pre-compiler define
// to support battery class selection at compile-time
#ifdef SELECTED_BATTERY_CLASS
static CanBattery* battery; static CanBattery* battery = nullptr;
void setup_battery() { void setup_battery() {
// Currently only one battery is implemented as a class. // Instantiate the battery only once just in case this function gets called multiple times.
// TODO: Extend based on build-time or run-time selected battery. if (battery == nullptr) {
battery = new RenaultZoeGen1Battery(); battery = new SELECTED_BATTERY_CLASS();
}
battery->setup(); battery->setup();
} }
@ -18,8 +21,8 @@ void update_values_battery() {
battery->update_values(); battery->update_values();
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
battery->transmit_can(); battery->transmit_can(currentMillis);
} }
void handle_incoming_can_frame_battery(CAN_frame rx_frame) { void handle_incoming_can_frame_battery(CAN_frame rx_frame) {

View file

@ -2,23 +2,10 @@
#define BATTERIES_H #define BATTERIES_H
#include "../../USER_SETTINGS.h" #include "../../USER_SETTINGS.h"
#include "src/devboard/utils/types.h"
// Abstract base class for next-generation battery implementations.
// Defines the interface to call battery specific functionality.
// No support for double battery yet.
class CanBattery {
public:
virtual void setup(void) = 0;
virtual void handle_incoming_can_frame(CAN_frame rx_frame) = 0;
virtual void update_values() = 0;
virtual void transmit_can() = 0;
};
#ifdef BMW_SBOX #ifdef BMW_SBOX
#include "BMW-SBOX.h" #include "BMW-SBOX.h"
void handle_incoming_can_frame_shunt(CAN_frame rx_frame); void handle_incoming_can_frame_shunt(CAN_frame rx_frame);
void transmit_can_shunt(); void transmit_can_shunt(unsigned long currentMillis);
void setup_can_shunt(); void setup_can_shunt();
#endif #endif
@ -168,7 +155,7 @@ void transmit_rs485();
void receive_RS485(); void receive_RS485();
#else #else
void handle_incoming_can_frame_battery(CAN_frame rx_frame); void handle_incoming_can_frame_battery(CAN_frame rx_frame);
void transmit_can_battery(); void transmit_can_battery(unsigned long currentMillis);
#endif #endif
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY

View file

@ -880,18 +880,11 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
break; break;
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
if (battery_awake) { if (battery_awake) {
//Send 20ms message //Send 20ms message
if (currentMillis - previousMillis20 >= INTERVAL_20_MS) { if (currentMillis - previousMillis20 >= INTERVAL_20_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis20 >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis20 = currentMillis; previousMillis20 = currentMillis;
if (startup_counter_contactor < 160) { if (startup_counter_contactor < 160) {

View file

@ -11,8 +11,6 @@ static unsigned long previousMillis100 = 0; // will store last time a 100ms C
static unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was send static unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was send
static unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was send static unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was send
static unsigned long previousMillis640 = 0; // will store last time a 600ms CAN Message was send static unsigned long previousMillis640 = 0; // will store last time a 600ms CAN Message was send
static unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was send
static unsigned long previousMillis5000 = 0; // will store last time a 5000ms CAN Message was send
static unsigned long previousMillis10000 = 0; // will store last time a 10000ms CAN Message was send static unsigned long previousMillis10000 = 0; // will store last time a 10000ms CAN Message was send
#define ALIVE_MAX_VALUE 14 // BMW CAN messages contain alive counter, goes from 0...14 #define ALIVE_MAX_VALUE 14 // BMW CAN messages contain alive counter, goes from 0...14
@ -839,8 +837,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
//if (battery_awake) { //We can always send CAN as the iX BMS will wake up on vehicle comms //if (battery_awake) { //We can always send CAN as the iX BMS will wake up on vehicle comms
// Send 100ms CAN Message // Send 100ms CAN Message
@ -862,14 +859,6 @@ void transmit_can_battery() {
BMWiX_C0.data.u8[0] = increment_C0_counter(BMWiX_C0.data.u8[0]); //Keep Alive 1 BMWiX_C0.data.u8[0] = increment_C0_counter(BMWiX_C0.data.u8[0]); //Keep Alive 1
transmit_can_frame(&BMWiX_C0, can_config.battery); transmit_can_frame(&BMWiX_C0, can_config.battery);
} }
// Send 1000ms CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis;
}
// Send 5000ms CAN Message
if (currentMillis - previousMillis5000 >= INTERVAL_5_S) {
previousMillis5000 = currentMillis;
}
// Send 10000ms CAN Message // Send 10000ms CAN Message
if (currentMillis - previousMillis10000 >= INTERVAL_10_S) { if (currentMillis - previousMillis10000 >= INTERVAL_10_S) {
previousMillis10000 = currentMillis; previousMillis10000 = currentMillis;
@ -877,18 +866,6 @@ void transmit_can_battery() {
transmit_can_frame(&BMWiX_6F4_REQUEST_BALANCING_START, can_config.battery); transmit_can_frame(&BMWiX_6F4_REQUEST_BALANCING_START, can_config.battery);
} }
} }
//We can always send CAN as the iX BMS will wake up on vehicle comms
// else {
// previousMillis20 = currentMillis;
// previousMillis100 = currentMillis;
// previousMillis200 = currentMillis;
// previousMillis500 = currentMillis;
// previousMillis640 = currentMillis;
// previousMillis1000 = currentMillis;
// previousMillis5000 = currentMillis;
// previousMillis10000 = currentMillis;
// }
//} //We can always send CAN as the iX BMS will wake up on vehicle comms
void setup_battery(void) { // Performs one time setup at startup void setup_battery(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, "BMW iX and i4-7 platform", 63); strncpy(datalayer.system.info.battery_protocol, "BMW iX and i4-7 platform", 63);

View file

@ -1005,8 +1005,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
//if (battery_awake) { //We can always send CAN as the PHEV BMS will wake up on vehicle comms //if (battery_awake) { //We can always send CAN as the PHEV BMS will wake up on vehicle comms

View file

@ -100,18 +100,17 @@ void handle_incoming_can_frame_shunt(CAN_frame rx_frame) {
} }
} }
void transmit_can_shunt() { void transmit_can_shunt(unsigned long currentMillis) {
unsigned long currentTime = millis();
/** Shunt can frames seen? **/ /** Shunt can frames seen? **/
if (ShuntLastSeen + 1000 < currentTime) { if (ShuntLastSeen + 1000 < currentMillis) {
datalayer.shunt.available = false; datalayer.shunt.available = false;
} else { } else {
datalayer.shunt.available = true; datalayer.shunt.available = true;
} }
// Send 20ms CAN Message // Send 20ms CAN Message
if (currentTime - LastMsgTime >= INTERVAL_20_MS) { if (currentMillis - LastMsgTime >= INTERVAL_20_MS) {
LastMsgTime = currentTime; LastMsgTime = currentMillis;
// First check if we have any active errors, incase we do, turn off the battery // First check if we have any active errors, incase we do, turn off the battery
if (datalayer.battery.status.bms_status == FAULT) { if (datalayer.battery.status.bms_status == FAULT) {
timeSpentInFaultedMode++; timeSpentInFaultedMode++;
@ -154,16 +153,16 @@ void transmit_can_shunt() {
switch (contactorStatus) { switch (contactorStatus) {
case PRECHARGE: case PRECHARGE:
SBOX_100.data.u8[0] = 0x86; // Precharge relay only SBOX_100.data.u8[0] = 0x86; // Precharge relay only
prechargeStartTime = currentTime; prechargeStartTime = currentMillis;
contactorStatus = NEGATIVE; contactorStatus = NEGATIVE;
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
Serial.println("S-BOX Precharge relay engaged"); Serial.println("S-BOX Precharge relay engaged");
#endif #endif
break; break;
case NEGATIVE: case NEGATIVE:
if (currentTime - prechargeStartTime >= CONTACTOR_CONTROL_T1) { if (currentMillis - prechargeStartTime >= CONTACTOR_CONTROL_T1) {
SBOX_100.data.u8[0] = 0xA6; // Precharge + Negative SBOX_100.data.u8[0] = 0xA6; // Precharge + Negative
negativeStartTime = currentTime; negativeStartTime = currentMillis;
contactorStatus = POSITIVE; contactorStatus = POSITIVE;
datalayer.shunt.precharging = true; datalayer.shunt.precharging = true;
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
@ -172,11 +171,11 @@ void transmit_can_shunt() {
} }
break; break;
case POSITIVE: case POSITIVE:
if (currentTime - negativeStartTime >= CONTACTOR_CONTROL_T2 && if (currentMillis - negativeStartTime >= CONTACTOR_CONTROL_T2 &&
(datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < (datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT <
datalayer.shunt.measured_outvoltage_mV)) { datalayer.shunt.measured_outvoltage_mV)) {
SBOX_100.data.u8[0] = 0xAA; // Precharge + Negative + Positive SBOX_100.data.u8[0] = 0xAA; // Precharge + Negative + Positive
positiveStartTime = currentTime; positiveStartTime = currentMillis;
contactorStatus = PRECHARGE_OFF; contactorStatus = PRECHARGE_OFF;
datalayer.shunt.precharging = false; datalayer.shunt.precharging = false;
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
@ -185,7 +184,7 @@ void transmit_can_shunt() {
} }
break; break;
case PRECHARGE_OFF: case PRECHARGE_OFF:
if (currentTime - positiveStartTime >= CONTACTOR_CONTROL_T3) { if (currentMillis - positiveStartTime >= CONTACTOR_CONTROL_T3) {
SBOX_100.data.u8[0] = 0x6A; // Negative + Positive SBOX_100.data.u8[0] = 0x6A; // Negative + Positive
contactorStatus = COMPLETED; contactorStatus = COMPLETED;
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB

View file

@ -769,17 +769,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
//Send 20ms message //Send 20ms message
if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) { if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis20ms >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20ms));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis20ms = currentMillis; previousMillis20ms = currentMillis;
transmit_can_frame(&BOLT_778, can_config.battery); transmit_can_frame(&BOLT_778, can_config.battery);
} }

View file

@ -6,16 +6,21 @@
#include "BYD-ATTO-3-BATTERY.h" #include "BYD-ATTO-3-BATTERY.h"
/* Notes /* Notes
- SOC% by default is now ESTIMATED. SOC% by default is now ESTIMATED.
- If you have a non-crashed pack, enable using real SOC. See Wiki for info. If you have a crash-locked pack, See the Wiki for more info on how to attempt an unlock
- TODO: In the future, we might be able to unlock crashed batteries and get SOC going always After battery has been unlocked, you can remove the "USE_ESTIMATED_SOC" from the BYD-ATTO-3-BATTERY.h file
*/ */
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
#define NOT_DETERMINED_YET 0 #define NOT_DETERMINED_YET 0
#define STANDARD_RANGE 1 #define STANDARD_RANGE 1
#define EXTENDED_RANGE 2 #define EXTENDED_RANGE 2
#define NOT_RUNNING 0xFF
#define STARTED 0
#define RUNNING_STEP_1 1
#define RUNNING_STEP_2 2
static uint8_t battery_type = NOT_DETERMINED_YET; static uint8_t battery_type = NOT_DETERMINED_YET;
static uint8_t stateMachineClearCrash = NOT_RUNNING;
static unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was send static unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was send
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
static unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was send static unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was send
@ -178,6 +183,16 @@ CAN_frame ATTO_3_7E7_POLL = {.FD = false,
.DLC = 8, .DLC = 8,
.ID = 0x7E7, //Poll PID 03 22 00 05 (POLL_FOR_BATTERY_SOC) .ID = 0x7E7, //Poll PID 03 22 00 05 (POLL_FOR_BATTERY_SOC)
.data = {0x03, 0x22, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00}}; .data = {0x03, 0x22, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00}};
CAN_frame ATTO_3_7E7_ACK = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E7, //ACK frame for long PIDs
.data = {0x30, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame ATTO_3_7E7_CLEAR_CRASH = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E7,
.data = {0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}};
// Define the data points for %SOC depending on pack voltage // Define the data points for %SOC depending on pack voltage
const uint8_t numPoints = 28; const uint8_t numPoints = 28;
@ -366,6 +381,12 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer_extended.bydAtto3.unknown11 = BMS_unknown11; datalayer_extended.bydAtto3.unknown11 = BMS_unknown11;
datalayer_extended.bydAtto3.unknown12 = BMS_unknown12; datalayer_extended.bydAtto3.unknown12 = BMS_unknown12;
datalayer_extended.bydAtto3.unknown13 = BMS_unknown13; datalayer_extended.bydAtto3.unknown13 = BMS_unknown13;
// Update requests from webserver datalayer
if (datalayer_extended.bydAtto3.UserRequestCrashReset && stateMachineClearCrash == NOT_RUNNING) {
stateMachineClearCrash = STARTED;
datalayer_extended.bydAtto3.UserRequestCrashReset = false;
}
} }
void handle_incoming_can_frame_battery(CAN_frame rx_frame) { void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
@ -470,6 +491,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break; break;
case 0x7EF: //OBD2 PID reply from battery case 0x7EF: //OBD2 PID reply from battery
if (rx_frame.data.u8[0] == 0x10) {
transmit_can_frame(&ATTO_3_7E7_ACK, can_config.battery); //Send next line request
}
pid_reply = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); pid_reply = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
switch (pid_reply) { switch (pid_reply) {
case POLL_FOR_BATTERY_SOC: case POLL_FOR_BATTERY_SOC:
@ -548,16 +572,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break; break;
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
//Send 50ms message //Send 50ms message
if (currentMillis - previousMillis50 >= INTERVAL_50_MS) { if (currentMillis - previousMillis50 >= INTERVAL_50_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis50 >= INTERVAL_50_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis50));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis50 = currentMillis; previousMillis50 = currentMillis;
// Set close contactors to allowed (Useful for crashed packs, started via contactor control thru GPIO) // Set close contactors to allowed (Useful for crashed packs, started via contactor control thru GPIO)
@ -603,7 +620,6 @@ void transmit_can_battery() {
} }
if (counter_100ms > 3) { if (counter_100ms > 3) {
ATTO_3_441.data.u8[4] = 0x9D; ATTO_3_441.data.u8[4] = 0x9D;
ATTO_3_441.data.u8[5] = 0x01; ATTO_3_441.data.u8[5] = 0x01;
ATTO_3_441.data.u8[6] = 0xFF; ATTO_3_441.data.u8[6] = 0xFF;
@ -614,6 +630,27 @@ void transmit_can_battery() {
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
transmit_can_frame(&ATTO_3_441, can_config.battery_double); transmit_can_frame(&ATTO_3_441, can_config.battery_double);
#endif //DOUBLE_BATTERY #endif //DOUBLE_BATTERY
switch (stateMachineClearCrash) {
case STARTED:
ATTO_3_7E7_CLEAR_CRASH.data = {0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_config.battery);
stateMachineClearCrash = RUNNING_STEP_1;
break;
case RUNNING_STEP_1:
ATTO_3_7E7_CLEAR_CRASH.data = {0x04, 0x14, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00};
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_config.battery);
stateMachineClearCrash = RUNNING_STEP_2;
break;
case RUNNING_STEP_2:
ATTO_3_7E7_CLEAR_CRASH.data = {0x03, 0x19, 0x02, 0x09, 0x00, 0x00, 0x00, 0x00};
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_config.battery);
stateMachineClearCrash = NOT_RUNNING;
break;
case NOT_RUNNING:
break;
default:
break;
}
} }
// Send 200ms CAN Message // Send 200ms CAN Message
if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { if (currentMillis - previousMillis200 >= INTERVAL_200_MS) {
@ -735,10 +772,12 @@ void transmit_can_battery() {
break; break;
} }
transmit_can_frame(&ATTO_3_7E7_POLL, can_config.battery); if (stateMachineClearCrash == NOT_RUNNING) { //Don't poll battery for data if clear crash running
transmit_can_frame(&ATTO_3_7E7_POLL, can_config.battery);
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
transmit_can_frame(&ATTO_3_7E7_POLL, can_config.battery_double); transmit_can_frame(&ATTO_3_7E7_POLL, can_config.battery_double);
#endif //DOUBLE_BATTERY #endif //DOUBLE_BATTERY
}
} }
} }

View file

@ -316,11 +316,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 1s CAN Message // Send 1s CAN Message
if (currentMillis - previousMillis1s >= INTERVAL_1_S) { if (currentMillis - previousMillis1s >= INTERVAL_1_S) {
previousMillis1s = currentMillis; previousMillis1s = currentMillis;
/* /*

View file

@ -655,9 +655,7 @@ void update_evse_discharge_capabilities(CAN_frame& f) {
CHADEMO_208.data.u8[7] = highByte(x208_evse_dischg_cap.lower_threshold_voltage); CHADEMO_208.data.u8[7] = highByte(x208_evse_dischg_cap.lower_threshold_voltage);
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
handlerBeforeMillis = currentMillis; handlerBeforeMillis = currentMillis;
handle_chademo_sequence(); handle_chademo_sequence();
@ -665,12 +663,6 @@ void transmit_can_battery() {
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis100 >= INTERVAL_100_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis100));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
/* no EVSE messages should be sent until the vehicle has /* no EVSE messages should be sent until the vehicle has

View file

@ -513,14 +513,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 10ms CAN Message // Send 10ms CAN Message
if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) { if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis10ms >= INTERVAL_10_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis10ms));
}
previousMillis10ms = currentMillis; previousMillis10ms = currentMillis;
transmit_can_frame(&CMFA_1EA, can_config.battery); transmit_can_frame(&CMFA_1EA, can_config.battery);
transmit_can_frame(&CMFA_135, can_config.battery); transmit_can_frame(&CMFA_135, can_config.battery);

View file

@ -0,0 +1,17 @@
#ifndef CAN_BATTERY_H
#define CAN_BATTERY_H
#include "src/devboard/utils/types.h"
// Abstract base class for next-generation battery implementations.
// Defines the interface to call battery specific functionality.
// No support for double battery yet.
class CanBattery {
public:
virtual void setup(void) = 0;
virtual void handle_incoming_can_frame(CAN_frame rx_frame) = 0;
virtual void update_values() = 0;
virtual void transmit_can(unsigned long currentMillis) = 0;
};
#endif

View file

@ -288,8 +288,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 1s CAN Message // Send 1s CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis; previousMillis1000 = currentMillis;

View file

@ -474,9 +474,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break; break;
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 500ms CAN Message // Send 500ms CAN Message
if (currentMillis - previousMillis500 >= INTERVAL_500_MS) { if (currentMillis - previousMillis500 >= INTERVAL_500_MS) {
previousMillis500 = currentMillis; previousMillis500 = currentMillis;

View file

@ -207,16 +207,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis100 >= INTERVAL_100_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis100));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
// Send CAN goes here... // Send CAN goes here...

View file

@ -1,5 +1,6 @@
#include "../include.h" #include "../include.h"
#ifdef JAGUAR_IPACE_BATTERY #ifdef JAGUAR_IPACE_BATTERY
#include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "JAGUAR-IPACE-BATTERY.h" #include "JAGUAR-IPACE-BATTERY.h"
@ -62,7 +63,7 @@ void print_units(char* header, int value, char* units) {
logging.print(units); logging.print(units);
} }
void update_values_battery() { void JaguarIpaceBattery::update_values() {
datalayer.battery.status.real_soc = HVBattAvgSOC * 100; //Add two decimals datalayer.battery.status.real_soc = HVBattAvgSOC * 100; //Add two decimals
@ -119,14 +120,7 @@ void update_values_battery() {
#endif #endif
} }
void handle_incoming_can_frame_battery(CAN_frame rx_frame) { void JaguarIpaceBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
// Do not log noisy startup messages - there are many !
if (rx_frame.ID == 0 && rx_frame.DLC == 8 && rx_frame.data.u8[0] == 0 && rx_frame.data.u8[1] == 0 &&
rx_frame.data.u8[2] == 0 && rx_frame.data.u8[3] == 0 && rx_frame.data.u8[4] == 0 && rx_frame.data.u8[5] == 0 &&
rx_frame.data.u8[6] == 0x80 && rx_frame.data.u8[7] == 0) {
return;
}
switch (rx_frame.ID) { // These messages are periodically transmitted by the battery switch (rx_frame.ID) { // These messages are periodically transmitted by the battery
case 0x080: case 0x080:
@ -222,38 +216,17 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
default: default:
break; break;
} }
// Discard non-interesting can messages so they do not get logged via serial
if (rx_frame.ID < 0x500) {
return;
}
// All CAN messages recieved will be logged via serial
logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D
logging.print(" ");
logging.print(rx_frame.ID, HEX);
logging.print(" ");
logging.print(rx_frame.DLC);
logging.print(" ");
for (int i = 0; i < rx_frame.DLC; ++i) {
logging.print(rx_frame.data.u8[i], HEX);
logging.print(" ");
}
logging.println("");
} }
void transmit_can_battery() { void JaguarIpaceBattery::transmit_can(unsigned long currentMillis) {
unsigned long currentMillis = millis();
/* Send keep-alive every 200ms */ /* Send keep-alive every 200ms */
if (currentMillis - previousMillisKeepAlive >= INTERVAL_200_MS) { if (currentMillis - previousMillisKeepAlive >= INTERVAL_200_MS) {
previousMillisKeepAlive = currentMillis; previousMillisKeepAlive = currentMillis;
transmit_can_frame(&ipace_keep_alive, can_config.battery); transmit_can_frame(&ipace_keep_alive, can_config.battery);
return;
} }
} }
void setup_battery(void) { // Performs one time setup at startup void JaguarIpaceBattery::setup(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, "Jaguar I-PACE", 63); strncpy(datalayer.system.info.battery_protocol, "Jaguar I-PACE", 63);
datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.info.battery_protocol[63] = '\0';
datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.number_of_cells = 108;

View file

@ -1,15 +1,23 @@
#ifndef JAGUAR_IPACE_BATTERY_H #ifndef JAGUAR_IPACE_BATTERY_H
#define JAGUAR_IPACE_BATTERY_H #define JAGUAR_IPACE_BATTERY_H
#include "../include.h"
#include "CanBattery.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define SELECTED_BATTERY_CLASS JaguarIpaceBattery
#define MAX_PACK_VOLTAGE_DV 4546 //5000 = 500.0V #define MAX_PACK_VOLTAGE_DV 4546 //5000 = 500.0V
#define MIN_PACK_VOLTAGE_DV 3370 #define MIN_PACK_VOLTAGE_DV 3370
#define MAX_CELL_DEVIATION_MV 250 #define MAX_CELL_DEVIATION_MV 250
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value #define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
void setup_battery(void); class JaguarIpaceBattery : public CanBattery {
void transmit_can_frame(CAN_frame* tx_frame, int interface); public:
virtual void setup(void);
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
virtual void update_values();
virtual void transmit_can(unsigned long currentMillis);
};
#endif #endif

View file

@ -1082,8 +1082,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
if (startedUp) { if (startedUp) {
//Send Contactor closing message loop //Send Contactor closing message loop
// Check if we still have messages to send // Check if we still have messages to send
@ -1108,13 +1107,6 @@ void transmit_can_battery() {
//Send 200ms CANFD message //Send 200ms CANFD message
if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) { if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) {
previousMillis200ms = currentMillis; previousMillis200ms = currentMillis;
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis200ms >= INTERVAL_200_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis200ms));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis200ms = currentMillis;
EGMP_7E4.data.u8[3] = KIA_7E4_COUNTER; EGMP_7E4.data.u8[3] = KIA_7E4_COUNTER;

View file

@ -924,8 +924,7 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
} }
#endif //DOUBLE_BATTERY #endif //DOUBLE_BATTERY
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
if (!startedUp) { if (!startedUp) {
return; // Don't send any CAN messages towards battery until it has started up return; // Don't send any CAN messages towards battery until it has started up
@ -948,12 +947,6 @@ void transmit_can_battery() {
} }
// Send 10ms CAN Message // Send 10ms CAN Message
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis10 >= INTERVAL_10_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis10));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis10 = currentMillis; previousMillis10 = currentMillis;
switch (counter_200) { switch (counter_200) {

View file

@ -230,8 +230,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break; break;
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 1000ms CAN Message // Send 1000ms CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {

View file

@ -1627,9 +1627,8 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 10ms CAN Message
if (currentMillis > last_can_msg_timestamp + 500) { if (currentMillis > last_can_msg_timestamp + 500) {
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
if (first_can_msg) if (first_can_msg)
@ -1642,15 +1641,8 @@ void transmit_can_battery() {
datalayer.system.status.battery_allows_contactor_closing = false; datalayer.system.status.battery_allows_contactor_closing = false;
} }
} }
// Send 10ms CAN Message
if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) { if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis10ms >= INTERVAL_10_MS_DELAYED) && (currentMillis > BOOTUP_TIME) &&
previousMillis10ms > 0) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis10ms));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis10ms = currentMillis; previousMillis10ms = currentMillis;
MEB_0FC.data.u8[1] = ((MEB_0FC.data.u8[1] & 0xF0) | counter_10ms); MEB_0FC.data.u8[1] = ((MEB_0FC.data.u8[1] & 0xF0) | counter_10ms);

View file

@ -108,16 +108,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break; break;
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
//Send 10ms message //Send 10ms message
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis10 >= INTERVAL_10_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis10));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis10 = currentMillis; previousMillis10 = currentMillis;
transmit_can_frame(&MG_5_100, can_config.battery); transmit_can_frame(&MG_5_100, can_config.battery);

View file

@ -1071,13 +1071,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break; break;
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
if (datalayer.system.status.BMS_reset_in_progress || datalayer.system.status.BMS_startup_in_progress) { if (datalayer.system.status.BMS_reset_in_progress || datalayer.system.status.BMS_startup_in_progress) {
// Transmitting towards battery is halted while BMS is being reset // Transmitting towards battery is halted while BMS is being reset
// Reset sending counters to avoid overrun messages when reset is over
previousMillis10 = currentMillis; previousMillis10 = currentMillis;
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
previousMillis10s = currentMillis; previousMillis10s = currentMillis;
@ -1088,12 +1085,6 @@ void transmit_can_battery() {
//Send 10ms message //Send 10ms message
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis10 >= INTERVAL_10_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis10));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis10 = currentMillis; previousMillis10 = currentMillis;
switch (mprun10) { switch (mprun10) {

View file

@ -132,8 +132,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// No transmission needed for this integration // No transmission needed for this integration
} }

View file

@ -158,11 +158,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 1s CAN Message // Send 1s CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis; previousMillis1000 = currentMillis;
transmit_can_frame(&PYLON_3010, can_config.battery); // Heartbeat transmit_can_frame(&PYLON_3010, can_config.battery); // Heartbeat

View file

@ -301,11 +301,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 50ms CAN Message // Send 50ms CAN Message
if (currentMillis - previousMillis50ms >= INTERVAL_50_MS) { if (currentMillis - previousMillis50ms >= INTERVAL_50_MS) {
previousMillis50ms = currentMillis; previousMillis50ms = currentMillis;
transmit_can_frame(&RANGE_ROVER_18B, can_config.battery); transmit_can_frame(&RANGE_ROVER_18B, can_config.battery);

View file

@ -210,8 +210,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message (for 2.4s, then pause 10s) // Send 100ms CAN Message (for 2.4s, then pause 10s)
if ((currentMillis - previousMillis100) >= (INTERVAL_100_MS + GVL_pause)) { if ((currentMillis - previousMillis100) >= (INTERVAL_100_MS + GVL_pause)) {
previousMillis100 = currentMillis; previousMillis100 = currentMillis;

View file

@ -127,7 +127,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
// we do not need to send anything to the battery for now // we do not need to send anything to the battery for now
} }

View file

@ -493,14 +493,10 @@ void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
} }
} }
void RenaultZoeGen1Battery::transmit_can() { void RenaultZoeGen1Battery::transmit_can(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis100 >= INTERVAL_100_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis100));
}
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
transmit_can_frame(&ZOE_423, can_config.battery); transmit_can_frame(&ZOE_423, can_config.battery);

View file

@ -1,11 +1,10 @@
#ifndef RENAULT_ZOE_GEN1_BATTERY_H #ifndef RENAULT_ZOE_GEN1_BATTERY_H
#define RENAULT_ZOE_GEN1_BATTERY_H #define RENAULT_ZOE_GEN1_BATTERY_H
#include "../include.h"
#include "CanBattery.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define SELECTED_BATTERY_CLASS RenaultZoeGen1Battery
// Indicates that the object-oriented battery interface is to be activated.
#define OO_BATTERY_SELECTED
#define MAX_PACK_VOLTAGE_DV 4200 //5000 = 500.0V #define MAX_PACK_VOLTAGE_DV 4200 //5000 = 500.0V
#define MIN_PACK_VOLTAGE_DV 3000 #define MIN_PACK_VOLTAGE_DV 3000
@ -18,7 +17,7 @@ class RenaultZoeGen1Battery : public CanBattery {
virtual void setup(void); virtual void setup(void);
virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void handle_incoming_can_frame(CAN_frame rx_frame);
virtual void update_values(); virtual void update_values();
virtual void transmit_can(); virtual void transmit_can(unsigned long currentMillis);
}; };
#endif #endif

View file

@ -371,8 +371,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
@ -391,10 +390,6 @@ void transmit_can_battery() {
// Send 200ms CAN Message // Send 200ms CAN Message
if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { if (currentMillis - previousMillis200 >= INTERVAL_200_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis200 >= INTERVAL_200_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis200));
}
previousMillis200 = currentMillis; previousMillis200 = currentMillis;
// Update current poll from the array // Update current poll from the array

View file

@ -571,11 +571,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 10s CAN Message // Send 10s CAN Message
if (currentMillis - previousMillis10s >= INTERVAL_10_S) { if (currentMillis - previousMillis10s >= INTERVAL_10_S) {
previousMillis10s = currentMillis; previousMillis10s = currentMillis;
if (datalayer.battery.status.bms_status == FAULT) { if (datalayer.battery.status.bms_status == FAULT) {

View file

@ -333,17 +333,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break; break;
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
//Send 10ms message //Send 10ms message
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis10 >= INTERVAL_10_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis10));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis10 = currentMillis; previousMillis10 = currentMillis;
SANTAFE_200.data.u8[6] = (counter_200 << 1); SANTAFE_200.data.u8[6] = (counter_200 << 1);

View file

@ -115,7 +115,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
} }
} }
void transmit_can_battery() {} void transmit_can_battery(unsigned long currentMillis) {
// No periodic transmitting for this battery type
}
void setup_battery(void) { // Performs one time setup at startup void setup_battery(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, "SIMPBMS battery", 63); strncpy(datalayer.system.info.battery_protocol, "SIMPBMS battery", 63);

View file

@ -137,9 +137,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break; break;
} }
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis; previousMillis100 = currentMillis;

View file

@ -1864,14 +1864,12 @@ int index_1CF = 0;
int index_118 = 0; int index_118 = 0;
#endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL)
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
/*From bielec: My fist 221 message, to close the contactors is 0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96 and then, /*From bielec: My fist 221 message, to close the contactors is 0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96 and then,
to cause "hv_up_for_drive" I send an additional 221 message 0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA so to cause "hv_up_for_drive" I send an additional 221 message 0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA so
two 221 messages are being continuously transmitted. When I want to shut down, I stop the second message and only send two 221 messages are being continuously transmitted. When I want to shut down, I stop the second message and only send
the first, for a few cycles, then stop all messages which causes the contactor to open. */ the first, for a few cycles, then stop all messages which causes the contactor to open. */
unsigned long currentMillis = millis();
if (!cellvoltagesRead) { if (!cellvoltagesRead) {
return; //All cellvoltages not read yet, do not proceed with contactor closing return; //All cellvoltages not read yet, do not proceed with contactor closing
} }
@ -1906,12 +1904,6 @@ the first, for a few cycles, then stop all messages which causes the contactor
//Send 50ms message //Send 50ms message
if (currentMillis - previousMillis50 >= INTERVAL_50_MS) { if (currentMillis - previousMillis50 >= INTERVAL_50_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis50 >= INTERVAL_50_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis50));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis50 = currentMillis; previousMillis50 = currentMillis;
if ((datalayer.system.status.inverter_allows_contactor_closing == true) && if ((datalayer.system.status.inverter_allows_contactor_closing == true) &&

View file

@ -130,8 +130,7 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
void handle_incoming_can_frame_battery(CAN_frame rx_frame) { void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis; previousMillis100 = currentMillis;

View file

@ -435,16 +435,9 @@ void readCellVoltages() {
transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis100 >= INTERVAL_100_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis100));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
transmit_can_frame(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive transmit_can_frame(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive

View file

@ -610,16 +610,9 @@ void readCellVoltages() {
transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module
} }
void transmit_can_battery() { void transmit_can_battery(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
// Check if sending of CAN messages has been delayed too much.
if ((currentMillis - previousMillis100 >= INTERVAL_100_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) {
set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis100));
} else {
clear_event(EVENT_CAN_OVERRUN);
}
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
transmit_can_frame(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive transmit_can_frame(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive

View file

@ -11,6 +11,6 @@
#endif #endif
void map_can_frame_to_variable_charger(CAN_frame rx_frame); void map_can_frame_to_variable_charger(CAN_frame rx_frame);
void transmit_can_charger(); void transmit_can_charger(unsigned long currentMillis);
#endif #endif

View file

@ -98,8 +98,7 @@ void map_can_frame_to_variable_charger(CAN_frame rx_frame) {
} }
} }
void transmit_can_charger() { void transmit_can_charger(unsigned long currentMillis) {
unsigned long currentMillis = millis();
uint16_t Vol_temp = 0; uint16_t Vol_temp = 0;
uint16_t setpoint_HV_VDC = floor(datalayer.charger.charger_setpoint_HV_VDC); uint16_t setpoint_HV_VDC = floor(datalayer.charger.charger_setpoint_HV_VDC);

View file

@ -156,8 +156,7 @@ void map_can_frame_to_variable_charger(CAN_frame rx_frame) {
} }
} }
void transmit_can_charger() { void transmit_can_charger(unsigned long currentMillis) {
unsigned long currentMillis = millis();
/* Send keepalive with mode every 10ms */ /* Send keepalive with mode every 10ms */
if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) { if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) {

View file

@ -3,12 +3,12 @@
#include "src/devboard/sdcard/sdcard.h" #include "src/devboard/sdcard/sdcard.h"
// Parameters // Parameters
CAN_device_t CAN_cfg; // CAN Config
CAN_device_t CAN_cfg; // CAN Config const uint8_t rx_queue_size = 10; // Receive Queue size
const int rx_queue_size = 10; // Receive Queue size
volatile bool send_ok_native = 0; volatile bool send_ok_native = 0;
volatile bool send_ok_2515 = 0; volatile bool send_ok_2515 = 0;
volatile bool send_ok_2518 = 0; volatile bool send_ok_2518 = 0;
static unsigned long previousMillis10 = 0;
#ifdef CAN_ADDON #ifdef CAN_ADDON
static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h
@ -105,25 +105,26 @@ void init_CAN() {
} }
// Transmit functions // Transmit functions
void transmit_can() { void transmit_can(unsigned long currentMillis) {
if (!allowed_to_send_CAN) { if (!allowed_to_send_CAN) {
return; //Global block of CAN messages return; //Global block of CAN messages
} }
#ifndef RS485_BATTERY_SELECTED #ifndef RS485_BATTERY_SELECTED
transmit_can_battery(); transmit_can_battery(currentMillis);
#endif #endif
#ifdef CAN_INVERTER_SELECTED #ifdef CAN_INVERTER_SELECTED
transmit_can_inverter(); transmit_can_inverter(currentMillis);
#endif // CAN_INVERTER_SELECTED #endif // CAN_INVERTER_SELECTED
#ifdef CHARGER_SELECTED #ifdef CHARGER_SELECTED
transmit_can_charger(); transmit_can_charger(currentMillis);
#endif // CHARGER_SELECTED #endif // CHARGER_SELECTED
#ifdef CAN_SHUNT_SELECTED #ifdef CAN_SHUNT_SELECTED
transmit_can_shunt(); transmit_can_shunt(currentMillis);
#endif // CAN_SHUNT_SELECTED #endif // CAN_SHUNT_SELECTED
} }

View file

@ -16,6 +16,7 @@
#endif //CANFD_ADDON #endif //CANFD_ADDON
void dump_can_frame(CAN_frame& frame, frameDirection msgDir); void dump_can_frame(CAN_frame& frame, frameDirection msgDir);
void transmit_can_frame(CAN_frame* tx_frame, int interface);
/** /**
* @brief Initialization function for CAN. * @brief Initialization function for CAN.
@ -40,10 +41,11 @@ void transmit_can_frame();
* @brief Send CAN messages to all components * @brief Send CAN messages to all components
* *
* @param[in] void * @param[in] void
* @param[in] unsigned long currentMillis
* *
* @return void * @return void
*/ */
void transmit_can(); void transmit_can(unsigned long currentMillis);
/** /**
* @brief Receive CAN messages from all interfaces * @brief Receive CAN messages from all interfaces

View file

@ -94,7 +94,7 @@ void init_contactors() {
#ifdef BMS_2_POWER //Hardware supports 2x BMS #ifdef BMS_2_POWER //Hardware supports 2x BMS
pinMode(BMS_2_POWER, OUTPUT); pinMode(BMS_2_POWER, OUTPUT);
digitalWrite(BMS_2_POWER, HIGH); digitalWrite(BMS_2_POWER, HIGH);
#endif BMS_2_POWER #endif //BMS_2_POWER
#endif // HW with dedicated BMS pins #endif // HW with dedicated BMS pins
#if defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET) // User has enabled BMS reset, turn on output on start #if defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET) // User has enabled BMS reset, turn on output on start
pinMode(BMS_POWER, OUTPUT); pinMode(BMS_POWER, OUTPUT);

View file

@ -163,6 +163,9 @@ typedef struct {
} DATALAYER_INFO_BMWI3; } DATALAYER_INFO_BMWI3;
typedef struct { typedef struct {
/** bool */
/** User requesting crash reset via WebUI*/
bool UserRequestCrashReset = false;
/** bool */ /** bool */
/** Which SOC method currently used. 0 = Estimated, 1 = Measured */ /** Which SOC method currently used. 0 = Estimated, 1 = Measured */
bool SOC_method = 0; bool SOC_method = 0;

View file

@ -19,11 +19,19 @@ battery_pause_status emulator_pause_status = NORMAL;
//battery pause status end //battery pause status end
void update_machineryprotection() { void update_machineryprotection() {
// Check if the CPU is too hot /* Check if the ESP32 CPU running the Battery-Emulator is too hot.
We start with a warning, you can start to see Wifi issues if it becomes too hot
If the chip starts to approach the design limit, we perform a graceful shutdown */
if (datalayer.system.info.CPU_temperature > 80.0f) { if (datalayer.system.info.CPU_temperature > 80.0f) {
set_event(EVENT_CPU_OVERHEAT, 0); set_event(EVENT_CPU_OVERHEATING, 0);
} else { } else {
clear_event(EVENT_CPU_OVERHEAT); clear_event(EVENT_CPU_OVERHEATING);
}
if (datalayer.system.info.CPU_temperature > 110.0f) {
set_event(EVENT_CPU_OVERHEATED, 0);
}
if (datalayer.system.info.CPU_temperature < 105.0f) {
clear_event(EVENT_CPU_OVERHEATED); //Hysteresis on the clearing
} }
// Check health status of CAN interfaces // Check health status of CAN interfaces

View file

@ -39,7 +39,7 @@ void init_events(void) {
events.entries[EVENT_CANMCP2515_INIT_FAILURE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANMCP2515_INIT_FAILURE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CANFD_BUFFER_FULL].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANFD_BUFFER_FULL].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CAN_BUFFER_FULL].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CAN_BUFFER_FULL].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CAN_OVERRUN].level = EVENT_LEVEL_INFO; events.entries[EVENT_TASK_OVERRUN].level = EVENT_LEVEL_INFO;
events.entries[EVENT_CAN_CORRUPTED_WARNING].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CAN_CORRUPTED_WARNING].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CAN_NATIVE_TX_FAILURE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CAN_NATIVE_TX_FAILURE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CAN_BATTERY_MISSING].level = EVENT_LEVEL_ERROR; events.entries[EVENT_CAN_BATTERY_MISSING].level = EVENT_LEVEL_ERROR;
@ -47,7 +47,8 @@ void init_events(void) {
events.entries[EVENT_CAN_CHARGER_MISSING].level = EVENT_LEVEL_INFO; events.entries[EVENT_CAN_CHARGER_MISSING].level = EVENT_LEVEL_INFO;
events.entries[EVENT_CAN_INVERTER_MISSING].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CAN_INVERTER_MISSING].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CONTACTOR_WELDED].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CONTACTOR_WELDED].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CPU_OVERHEAT].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CPU_OVERHEATING].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CPU_OVERHEATED].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_WATER_INGRESS].level = EVENT_LEVEL_ERROR; events.entries[EVENT_WATER_INGRESS].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_CHARGE_LIMIT_EXCEEDED].level = EVENT_LEVEL_INFO; events.entries[EVENT_CHARGE_LIMIT_EXCEEDED].level = EVENT_LEVEL_INFO;
events.entries[EVENT_DISCHARGE_LIMIT_EXCEEDED].level = EVENT_LEVEL_INFO; events.entries[EVENT_DISCHARGE_LIMIT_EXCEEDED].level = EVENT_LEVEL_INFO;
@ -81,6 +82,7 @@ void init_events(void) {
events.entries[EVENT_INVERTER_OPEN_CONTACTOR].level = EVENT_LEVEL_INFO; events.entries[EVENT_INVERTER_OPEN_CONTACTOR].level = EVENT_LEVEL_INFO;
events.entries[EVENT_INTERFACE_MISSING].level = EVENT_LEVEL_INFO; events.entries[EVENT_INTERFACE_MISSING].level = EVENT_LEVEL_INFO;
events.entries[EVENT_MODBUS_INVERTER_MISSING].level = EVENT_LEVEL_INFO; events.entries[EVENT_MODBUS_INVERTER_MISSING].level = EVENT_LEVEL_INFO;
events.entries[EVENT_NO_ENABLE_DETECTED].level = EVENT_LEVEL_INFO;
events.entries[EVENT_ERROR_OPEN_CONTACTOR].level = EVENT_LEVEL_INFO; events.entries[EVENT_ERROR_OPEN_CONTACTOR].level = EVENT_LEVEL_INFO;
events.entries[EVENT_CELL_CRITICAL_UNDER_VOLTAGE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_CELL_CRITICAL_UNDER_VOLTAGE].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_CELL_CRITICAL_OVER_VOLTAGE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_CELL_CRITICAL_OVER_VOLTAGE].level = EVENT_LEVEL_ERROR;
@ -176,8 +178,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
return "MCP2518FD message failed to send. Buffer full or no one on the bus to ACK the message!"; return "MCP2518FD message failed to send. Buffer full or no one on the bus to ACK the message!";
case EVENT_CAN_BUFFER_FULL: case EVENT_CAN_BUFFER_FULL:
return "MCP2515 message failed to send. Buffer full or no one on the bus to ACK the message!"; return "MCP2515 message failed to send. Buffer full or no one on the bus to ACK the message!";
case EVENT_CAN_OVERRUN: case EVENT_TASK_OVERRUN:
return "CAN message failed to send within defined time. Contact developers, CPU load might be too high."; return "Task took too long to complete. CPU load might be too high. Info message, no action required.";
case EVENT_CAN_CORRUPTED_WARNING: case EVENT_CAN_CORRUPTED_WARNING:
return "High amount of corrupted CAN messages detected. Check CAN wire shielding!"; return "High amount of corrupted CAN messages detected. Check CAN wire shielding!";
case EVENT_CAN_NATIVE_TX_FAILURE: case EVENT_CAN_NATIVE_TX_FAILURE:
@ -192,8 +194,10 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
return "Inverter not sending messages via CAN for the last 60 seconds. Check wiring!"; return "Inverter not sending messages via CAN for the last 60 seconds. Check wiring!";
case EVENT_CONTACTOR_WELDED: case EVENT_CONTACTOR_WELDED:
return "Contactors sticking/welded. Inspect battery with caution!"; return "Contactors sticking/welded. Inspect battery with caution!";
case EVENT_CPU_OVERHEAT: case EVENT_CPU_OVERHEATING:
return "Battery-Emulator CPU overheating! Increase airflow/cooling to increase hardware lifespan!"; return "Battery-Emulator CPU overheating! Increase airflow/cooling to increase hardware lifespan!";
case EVENT_CPU_OVERHEATED:
return "Battery-Emulator CPU melting! Performing controlled shutdown until temperature drops!";
case EVENT_CHARGE_LIMIT_EXCEEDED: case EVENT_CHARGE_LIMIT_EXCEEDED:
return "Inverter is charging faster than battery is allowing."; return "Inverter is charging faster than battery is allowing.";
case EVENT_DISCHARGE_LIMIT_EXCEEDED: case EVENT_DISCHARGE_LIMIT_EXCEEDED:
@ -269,6 +273,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
"Check other error code for reason!"; "Check other error code for reason!";
case EVENT_MODBUS_INVERTER_MISSING: case EVENT_MODBUS_INVERTER_MISSING:
return "Modbus inverter has not sent any data. Inspect communication wiring!"; return "Modbus inverter has not sent any data. Inspect communication wiring!";
case EVENT_NO_ENABLE_DETECTED:
return "Inverter Enable line has not been active for a long time. Check Wiring!";
case EVENT_CELL_CRITICAL_UNDER_VOLTAGE: case EVENT_CELL_CRITICAL_UNDER_VOLTAGE:
return "CELL VOLTAGE CRITICALLY LOW! Not possible to continue. Inspect battery!"; return "CELL VOLTAGE CRITICALLY LOW! Not possible to continue. Inspect battery!";
case EVENT_CELL_UNDER_VOLTAGE: case EVENT_CELL_UNDER_VOLTAGE:

View file

@ -12,7 +12,6 @@
XX(EVENT_CANMCP2515_INIT_FAILURE) \ XX(EVENT_CANMCP2515_INIT_FAILURE) \
XX(EVENT_CANFD_BUFFER_FULL) \ XX(EVENT_CANFD_BUFFER_FULL) \
XX(EVENT_CAN_BUFFER_FULL) \ XX(EVENT_CAN_BUFFER_FULL) \
XX(EVENT_CAN_OVERRUN) \
XX(EVENT_CAN_CORRUPTED_WARNING) \ XX(EVENT_CAN_CORRUPTED_WARNING) \
XX(EVENT_CAN_BATTERY_MISSING) \ XX(EVENT_CAN_BATTERY_MISSING) \
XX(EVENT_CAN_BATTERY2_MISSING) \ XX(EVENT_CAN_BATTERY2_MISSING) \
@ -21,7 +20,8 @@
XX(EVENT_CAN_NATIVE_TX_FAILURE) \ XX(EVENT_CAN_NATIVE_TX_FAILURE) \
XX(EVENT_CHARGE_LIMIT_EXCEEDED) \ XX(EVENT_CHARGE_LIMIT_EXCEEDED) \
XX(EVENT_CONTACTOR_WELDED) \ XX(EVENT_CONTACTOR_WELDED) \
XX(EVENT_CPU_OVERHEAT) \ XX(EVENT_CPU_OVERHEATING) \
XX(EVENT_CPU_OVERHEATED) \
XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \ XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \
XX(EVENT_WATER_INGRESS) \ XX(EVENT_WATER_INGRESS) \
XX(EVENT_12V_LOW) \ XX(EVENT_12V_LOW) \
@ -55,6 +55,7 @@
XX(EVENT_INVERTER_OPEN_CONTACTOR) \ XX(EVENT_INVERTER_OPEN_CONTACTOR) \
XX(EVENT_INTERFACE_MISSING) \ XX(EVENT_INTERFACE_MISSING) \
XX(EVENT_MODBUS_INVERTER_MISSING) \ XX(EVENT_MODBUS_INVERTER_MISSING) \
XX(EVENT_NO_ENABLE_DETECTED) \
XX(EVENT_ERROR_OPEN_CONTACTOR) \ XX(EVENT_ERROR_OPEN_CONTACTOR) \
XX(EVENT_CELL_CRITICAL_UNDER_VOLTAGE) \ XX(EVENT_CELL_CRITICAL_UNDER_VOLTAGE) \
XX(EVENT_CELL_CRITICAL_OVER_VOLTAGE) \ XX(EVENT_CELL_CRITICAL_OVER_VOLTAGE) \
@ -73,6 +74,7 @@
XX(EVENT_SERIAL_RX_FAILURE) \ XX(EVENT_SERIAL_RX_FAILURE) \
XX(EVENT_SERIAL_TX_FAILURE) \ XX(EVENT_SERIAL_TX_FAILURE) \
XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \ XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \
XX(EVENT_TASK_OVERRUN) \
XX(EVENT_RESET_UNKNOWN) \ XX(EVENT_RESET_UNKNOWN) \
XX(EVENT_RESET_POWERON) \ XX(EVENT_RESET_POWERON) \
XX(EVENT_RESET_EXT) \ XX(EVENT_RESET_EXT) \

View file

@ -37,12 +37,6 @@ enum PrechargeState {
#define INTERVAL_60_S 60000 #define INTERVAL_60_S 60000
#define INTERVAL_10_MS_DELAYED 15 #define INTERVAL_10_MS_DELAYED 15
#define INTERVAL_20_MS_DELAYED 30
#define INTERVAL_30_MS_DELAYED 40
#define INTERVAL_50_MS_DELAYED 65
#define INTERVAL_100_MS_DELAYED 120
#define INTERVAL_200_MS_DELAYED 240
#define INTERVAL_500_MS_DELAYED 550
#define CAN_STILL_ALIVE 60 #define CAN_STILL_ALIVE 60
// Set by battery each time we get a CAN message. Decrements every second. When reaching 0, sets event // Set by battery each time we get a CAN message. Decrements every second. When reaching 0, sets event

View file

@ -487,6 +487,7 @@ String advanced_battery_processor(const String& var) {
#ifdef BYD_ATTO_3_BATTERY #ifdef BYD_ATTO_3_BATTERY
static const char* SOCmethod[2] = {"Estimated from voltage", "Measured by BMS"}; static const char* SOCmethod[2] = {"Estimated from voltage", "Measured by BMS"};
content += "<button onclick='askResetCrash()'>Unlock crashed BMS</button>";
content += "<h4>SOC method used: " + String(SOCmethod[datalayer_extended.bydAtto3.SOC_method]) + "</h4>"; content += "<h4>SOC method used: " + String(SOCmethod[datalayer_extended.bydAtto3.SOC_method]) + "</h4>";
content += "<h4>SOC estimated: " + String(datalayer_extended.bydAtto3.SOC_estimated) + "</h4>"; content += "<h4>SOC estimated: " + String(datalayer_extended.bydAtto3.SOC_estimated) + "</h4>";
content += "<h4>SOC highprec: " + String(datalayer_extended.bydAtto3.SOC_highprec) + "</h4>"; content += "<h4>SOC highprec: " + String(datalayer_extended.bydAtto3.SOC_highprec) + "</h4>";
@ -1516,6 +1517,18 @@ String advanced_battery_processor(const String& var) {
content += "function goToMainPage() { window.location.href = '/'; }"; content += "function goToMainPage() { window.location.href = '/'; }";
content += "</script>"; content += "</script>";
content += "<script>"; content += "<script>";
content +=
"function askResetCrash() { if (window.confirm('Are you sure you want to reset crash data? "
"Note this will unlock your BMS and enable contactor closing and SOC calculation.')) { "
"resetCrash(); } }";
content += "function resetCrash() {";
content += " var xhr = new XMLHttpRequest();";
content += " xhr.open('GET', '/resetCrash', true);";
content += " xhr.send();";
content += "}";
content += "function goToMainPage() { window.location.href = '/'; }";
content += "</script>";
content += "<script>";
content += content +=
"function askTriggerNVROL() { if (window.confirm('Are you sure you want to trigger " "function askTriggerNVROL() { if (window.confirm('Are you sure you want to trigger "
"an NVROL reset? Battery will be unavailable for 30 seconds while this is active!')) { " "an NVROL reset? Battery will be unavailable for 30 seconds while this is active!')) { "

View file

@ -608,6 +608,15 @@ void init_webserver() {
request->send(200, "text/plain", "Updated successfully"); request->send(200, "text/plain", "Updated successfully");
}); });
// Route for resetting Crash data on BYD Atto3 batteries
server.on("/resetCrash", HTTP_GET, [](AsyncWebServerRequest* request) {
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) {
return request->requestAuthentication();
}
datalayer_extended.bydAtto3.UserRequestCrashReset = true;
request->send(200, "text/plain", "Updated successfully");
});
// Route for erasing DTC on Volvo/Polestar batteries // Route for erasing DTC on Volvo/Polestar batteries
server.on("/volvoEraseDTC", HTTP_GET, [](AsyncWebServerRequest* request) { server.on("/volvoEraseDTC", HTTP_GET, [](AsyncWebServerRequest* request) {
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) {

View file

@ -217,7 +217,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
if (time_to_send_info) { // Set every 1s if we get message from inverter if (time_to_send_info) { // Set every 1s if we get message from inverter
transmit_can_frame(&AFORE_350, can_config.inverter); transmit_can_frame(&AFORE_350, can_config.inverter);
transmit_can_frame(&AFORE_351, can_config.inverter); transmit_can_frame(&AFORE_351, can_config.inverter);

View file

@ -204,8 +204,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
if (!inverterStartedUp) { if (!inverterStartedUp) {
//Avoid sending messages towards inverter, unless it has woken up and sent something to us first //Avoid sending messages towards inverter, unless it has woken up and sent something to us first

View file

@ -453,7 +453,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
// No periodic sending, we only react on received can messages // No periodic sending, we only react on received can messages
} }

View file

@ -595,10 +595,9 @@ void update_values_can_inverter() { //This function maps all the CAN values fet
// So do we really need to map the same two values over and over to 32 places? // So do we really need to map the same two values over and over to 32 places?
} }
void transmit_can_inverter() { // This function loops as fast as possible void transmit_can_inverter(unsigned long currentMillis) {
if (send_bms_info) { if (send_bms_info) {
currentMillis = millis(); // Get the current time
// Check if enough time has passed since the last batch // Check if enough time has passed since the last batch
if (currentMillis - previousMillisBMSinfo >= delay_between_batches_ms) { if (currentMillis - previousMillisBMSinfo >= delay_between_batches_ms) {
@ -634,7 +633,6 @@ void transmit_can_inverter() { // This function loops as fast as possible
} }
if (send_individual_pack_status) { if (send_individual_pack_status) {
currentMillis = millis(); // Get the current time
// Check if enough time has passed since the last batch // Check if enough time has passed since the last batch
if (currentMillis - previousMillisIndividualPacks >= delay_between_batches_ms) { if (currentMillis - previousMillisIndividualPacks >= delay_between_batches_ms) {
@ -670,7 +668,6 @@ void transmit_can_inverter() { // This function loops as fast as possible
} }
if (send_serial_numbers) { if (send_serial_numbers) {
currentMillis = millis(); // Get the current time
// Check if enough time has passed since the last batch // Check if enough time has passed since the last batch
if (currentMillis - previousMillisSerialNumber >= delay_between_batches_ms) { if (currentMillis - previousMillisSerialNumber >= delay_between_batches_ms) {
@ -781,7 +778,6 @@ void transmit_can_inverter() { // This function loops as fast as possible
} }
if (send_cellvoltages) { if (send_cellvoltages) {
currentMillis = millis(); // Get the current time
// Check if enough time has passed since the last batch // Check if enough time has passed since the last batch
if (currentMillis - previousMillisCellvoltage >= delay_between_batches_ms) { if (currentMillis - previousMillisCellvoltage >= delay_between_batches_ms) {

View file

@ -523,14 +523,12 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
if (!inverter_alive) { if (!inverter_alive) {
return; //Dont send messages towards inverter until it has started return; //Dont send messages towards inverter until it has started
} }
unsigned long currentMillis = millis();
//Check if 1 second has passed, then we start sending! //Check if 1 second has passed, then we start sending!
if (currentMillis - previousMillis1s >= INTERVAL_1_S) { if (currentMillis - previousMillis1s >= INTERVAL_1_S) {
previousMillis1s = currentMillis; previousMillis1s = currentMillis;

View file

@ -267,7 +267,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
// No periodic sending for this battery type. Data is sent when inverter requests it // No periodic sending for this battery type. Data is sent when inverter requests it
} }

View file

@ -95,7 +95,7 @@ class ModbusInverterProtocol : public InverterProtocol {
#ifdef CAN_INVERTER_SELECTED #ifdef CAN_INVERTER_SELECTED
void update_values_can_inverter(); void update_values_can_inverter();
void map_can_frame_to_variable_inverter(CAN_frame rx_frame); void map_can_frame_to_variable_inverter(CAN_frame rx_frame);
void transmit_can_inverter(); void transmit_can_inverter(unsigned long currentMillis);
#endif #endif
#ifdef MODBUS_INVERTER_SELECTED #ifdef MODBUS_INVERTER_SELECTED

View file

@ -438,7 +438,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
// No periodic sending, we only react on received can messages // No periodic sending, we only react on received can messages
} }

View file

@ -158,8 +158,7 @@ void dump_frame(CAN_frame* frame) {
} }
#endif #endif
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis1000ms >= 1000) { if (currentMillis - previousMillis1000ms >= 1000) {
previousMillis1000ms = currentMillis; previousMillis1000ms = currentMillis;

View file

@ -265,8 +265,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 500ms CAN Message // Send 500ms CAN Message
if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) { if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) {

View file

@ -1,6 +1,7 @@
#include "../include.h" #include "../include.h"
#ifdef SMA_BYD_H_CAN #ifdef SMA_BYD_H_CAN
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"
#include "SMA-BYD-H-CAN.h" #include "SMA-BYD-H-CAN.h"
/* TODO: Map error bits in 0x158 */ /* TODO: Map error bits in 0x158 */
@ -11,6 +12,8 @@ static unsigned long previousMillis100ms = 0;
static uint32_t inverter_time = 0; static uint32_t inverter_time = 0;
static uint16_t inverter_voltage = 0; static uint16_t inverter_voltage = 0;
static int16_t inverter_current = 0; static int16_t inverter_current = 0;
static uint16_t timeWithoutInverterAllowsContactorClosing = 0;
#define THIRTY_MINUTES 1200
//Actual content messages //Actual content messages
CAN_frame SMA_158 = {.FD = false, CAN_frame SMA_158 = {.FD = false,
@ -145,6 +148,17 @@ void update_values_can_inverter() { //This function maps all the values fetched
#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN #endif // INVERTER_CONTACTOR_ENABLE_LED_PIN
} }
// Check if Enable line is working. If we go too long without any input, raise an event
if (!datalayer.system.status.inverter_allows_contactor_closing) {
timeWithoutInverterAllowsContactorClosing++;
if (timeWithoutInverterAllowsContactorClosing > THIRTY_MINUTES) {
set_event(EVENT_NO_ENABLE_DETECTED, 0);
}
} else {
timeWithoutInverterAllowsContactorClosing = 0;
}
/* /*
//SMA_158.data.u8[0] = //bit12 Fault high temperature, bit34Battery cellundervoltage, bit56 Battery cell overvoltage, bit78 batterysystemdefect //SMA_158.data.u8[0] = //bit12 Fault high temperature, bit34Battery cellundervoltage, bit56 Battery cell overvoltage, bit78 batterysystemdefect
//TODO: add all error bits. Sending message with all 0xAA until that. //TODO: add all error bits. Sending message with all 0xAA until that.
@ -236,8 +250,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send CAN Message every 100ms if inverter allows contactor closing // Send CAN Message every 100ms if inverter allows contactor closing
if (datalayer.system.status.inverter_allows_contactor_closing) { if (datalayer.system.status.inverter_allows_contactor_closing) {

View file

@ -1,6 +1,7 @@
#include "../include.h" #include "../include.h"
#ifdef SMA_BYD_HVS_CAN #ifdef SMA_BYD_HVS_CAN
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"
#include "SMA-BYD-HVS-CAN.h" #include "SMA-BYD-HVS-CAN.h"
/* TODO: Map error bits in 0x158 */ /* TODO: Map error bits in 0x158 */
@ -11,6 +12,8 @@ static unsigned long previousMillis100ms = 0;
static uint32_t inverter_time = 0; static uint32_t inverter_time = 0;
static uint16_t inverter_voltage = 0; static uint16_t inverter_voltage = 0;
static int16_t inverter_current = 0; static int16_t inverter_current = 0;
static uint16_t timeWithoutInverterAllowsContactorClosing = 0;
#define THIRTY_MINUTES 1200
//Actual content messages //Actual content messages
CAN_frame SMA_158 = {.FD = false, CAN_frame SMA_158 = {.FD = false,
@ -149,6 +152,17 @@ void update_values_can_inverter() { //This function maps all the values fetched
#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN #endif // INVERTER_CONTACTOR_ENABLE_LED_PIN
} }
// Check if Enable line is working. If we go too long without any input, raise an event
if (!datalayer.system.status.inverter_allows_contactor_closing) {
timeWithoutInverterAllowsContactorClosing++;
if (timeWithoutInverterAllowsContactorClosing > THIRTY_MINUTES) {
set_event(EVENT_NO_ENABLE_DETECTED, 0);
}
} else {
timeWithoutInverterAllowsContactorClosing = 0;
}
/* /*
//SMA_158.data.u8[0] = //bit12 Fault high temperature, bit34Battery cellundervoltage, bit56 Battery cell overvoltage, bit78 batterysystemdefect //SMA_158.data.u8[0] = //bit12 Fault high temperature, bit34Battery cellundervoltage, bit56 Battery cell overvoltage, bit78 batterysystemdefect
//TODO: add all error bits. Sending message with all 0xAA until that. //TODO: add all error bits. Sending message with all 0xAA until that.
@ -240,8 +254,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send CAN Message every 100ms if inverter allows contactor closing // Send CAN Message every 100ms if inverter allows contactor closing
if (datalayer.system.status.inverter_allows_contactor_closing) { if (datalayer.system.status.inverter_allows_contactor_closing) {

View file

@ -136,8 +136,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) { if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) {
previousMillis100ms = currentMillis; previousMillis100ms = currentMillis;

View file

@ -1,6 +1,7 @@
#include "../include.h" #include "../include.h"
#ifdef SMA_TRIPOWER_CAN #ifdef SMA_TRIPOWER_CAN
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"
#include "SMA-TRIPOWER-CAN.h" #include "SMA-TRIPOWER-CAN.h"
/* TODO: /* TODO:
@ -32,6 +33,8 @@ static int16_t inverter_current = 0;
static bool pairing_completed = false; static bool pairing_completed = false;
static int16_t temperature_average = 0; static int16_t temperature_average = 0;
static uint16_t ampere_hours_remaining = 0; static uint16_t ampere_hours_remaining = 0;
static uint16_t timeWithoutInverterAllowsContactorClosing = 0;
#define THIRTY_MINUTES 1200
//Actual content messages //Actual content messages
CAN_frame SMA_358 = {.FD = false, CAN_frame SMA_358 = {.FD = false,
@ -146,6 +149,17 @@ void update_values_can_inverter() { //This function maps all the values fetched
} else { } else {
SMA_4D8.data.u8[6] = READY_STATE; SMA_4D8.data.u8[6] = READY_STATE;
} }
// Check if Enable line is working. If we go too long without any input, raise an event
if (!datalayer.system.status.inverter_allows_contactor_closing) {
timeWithoutInverterAllowsContactorClosing++;
if (timeWithoutInverterAllowsContactorClosing > THIRTY_MINUTES) {
set_event(EVENT_NO_ENABLE_DETECTED, 0);
}
} else {
timeWithoutInverterAllowsContactorClosing = 0;
}
} }
void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
@ -190,8 +204,7 @@ void pushFrame(CAN_frame* frame, void (*callback)() = NULL) {
listLength++; listLength++;
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send CAN Message only if we're enabled by inverter // Send CAN Message only if we're enabled by inverter
if (!datalayer.system.status.inverter_allows_contactor_closing) { if (!datalayer.system.status.inverter_allows_contactor_closing) {

View file

@ -247,8 +247,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis; previousMillis100 = currentMillis;

View file

@ -206,7 +206,7 @@ void update_values_can_inverter() { //This function maps all the values fetched
SOLAX_187E.data.u8[5] = (uint8_t)(datalayer.battery.status.reported_soc / 100); SOLAX_187E.data.u8[5] = (uint8_t)(datalayer.battery.status.reported_soc / 100);
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
// No periodic sending used on this protocol, we react only on incoming CAN messages! // No periodic sending used on this protocol, we react only on incoming CAN messages!
} }

View file

@ -557,9 +557,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
} }
} }
void transmit_can_inverter() { void transmit_can_inverter(unsigned long currentMillis) {
unsigned long currentMillis = millis();
// Send 1s CAN Message // Send 1s CAN Message
if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) { if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) {
previousMillis500ms = currentMillis; previousMillis500ms = currentMillis;