mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Merge branch 'main' into improvement/can-overrun-refactoring
This commit is contained in:
commit
cd5facf774
13 changed files with 110 additions and 35 deletions
|
@ -3,14 +3,17 @@
|
|||
// These functions adapt the old C-style global functions battery-API to the
|
||||
// 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() {
|
||||
// Currently only one battery is implemented as a class.
|
||||
// TODO: Extend based on build-time or run-time selected battery.
|
||||
battery = new RenaultZoeGen1Battery();
|
||||
// Instantiate the battery only once just in case this function gets called multiple times.
|
||||
if (battery == nullptr) {
|
||||
battery = new SELECTED_BATTERY_CLASS();
|
||||
}
|
||||
battery->setup();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,6 @@
|
|||
#define BATTERIES_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(unsigned long currentMillis) = 0;
|
||||
};
|
||||
|
||||
#ifdef BMW_SBOX
|
||||
#include "BMW-SBOX.h"
|
||||
void handle_incoming_can_frame_shunt(CAN_frame rx_frame);
|
||||
|
|
17
Software/src/battery/CanBattery.h
Normal file
17
Software/src/battery/CanBattery.h
Normal 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() = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef JAGUAR_IPACE_BATTERY
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "JAGUAR-IPACE-BATTERY.h"
|
||||
|
@ -62,7 +63,7 @@ void print_units(char* header, int value, char* units) {
|
|||
logging.print(units);
|
||||
}
|
||||
|
||||
void update_values_battery() {
|
||||
void JaguarIpaceBattery::update_values() {
|
||||
|
||||
datalayer.battery.status.real_soc = HVBattAvgSOC * 100; //Add two decimals
|
||||
|
||||
|
@ -119,7 +120,8 @@ void update_values_battery() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||
void JaguarIpaceBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||
|
||||
switch (rx_frame.ID) { // These messages are periodically transmitted by the battery
|
||||
case 0x080:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
|
@ -216,7 +218,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
|||
}
|
||||
}
|
||||
|
||||
void transmit_can_battery(unsigned long currentMillis) {
|
||||
void JaguarIpaceBattery::transmit_can(unsigned long currentMillis) {
|
||||
/* Send keep-alive every 200ms */
|
||||
if (currentMillis - previousMillisKeepAlive >= INTERVAL_200_MS) {
|
||||
previousMillisKeepAlive = currentMillis;
|
||||
|
@ -224,7 +226,7 @@ void transmit_can_battery(unsigned long currentMillis) {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
datalayer.system.info.battery_protocol[63] = '\0';
|
||||
datalayer.battery.info.number_of_cells = 108;
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
#ifndef JAGUAR_IPACE_BATTERY_H
|
||||
#define JAGUAR_IPACE_BATTERY_H
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define SELECTED_BATTERY_CLASS JaguarIpaceBattery
|
||||
|
||||
#define MAX_PACK_VOLTAGE_DV 4546 //5000 = 500.0V
|
||||
#define MIN_PACK_VOLTAGE_DV 3370
|
||||
#define MAX_CELL_DEVIATION_MV 250
|
||||
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
||||
#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
|
||||
|
||||
void setup_battery(void);
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
class JaguarIpaceBattery : public CanBattery {
|
||||
public:
|
||||
virtual void setup(void);
|
||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||
virtual void update_values();
|
||||
virtual void transmit_can();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#ifndef RENAULT_ZOE_GEN1_BATTERY_H
|
||||
#define RENAULT_ZOE_GEN1_BATTERY_H
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
// Indicates that the object-oriented battery interface is to be activated.
|
||||
#define OO_BATTERY_SELECTED
|
||||
#define SELECTED_BATTERY_CLASS RenaultZoeGen1Battery
|
||||
|
||||
#define MAX_PACK_VOLTAGE_DV 4200 //5000 = 500.0V
|
||||
#define MIN_PACK_VOLTAGE_DV 3000
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#endif //CANFD_ADDON
|
||||
|
||||
void dump_can_frame(CAN_frame& frame, frameDirection msgDir);
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
|
||||
/**
|
||||
* @brief Initialization function for CAN.
|
||||
|
|
|
@ -19,11 +19,19 @@ battery_pause_status emulator_pause_status = NORMAL;
|
|||
//battery pause status end
|
||||
|
||||
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) {
|
||||
set_event(EVENT_CPU_OVERHEAT, 0);
|
||||
set_event(EVENT_CPU_OVERHEATING, 0);
|
||||
} 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
|
||||
|
|
|
@ -47,7 +47,8 @@ void init_events(void) {
|
|||
events.entries[EVENT_CAN_CHARGER_MISSING].level = EVENT_LEVEL_INFO;
|
||||
events.entries[EVENT_CAN_INVERTER_MISSING].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_CHARGE_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_INTERFACE_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_CELL_CRITICAL_UNDER_VOLTAGE].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_CELL_CRITICAL_OVER_VOLTAGE].level = EVENT_LEVEL_ERROR;
|
||||
|
@ -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!";
|
||||
case EVENT_CONTACTOR_WELDED:
|
||||
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!";
|
||||
case EVENT_CPU_OVERHEATED:
|
||||
return "Battery-Emulator CPU melting! Performing controlled shutdown until temperature drops!";
|
||||
case EVENT_CHARGE_LIMIT_EXCEEDED:
|
||||
return "Inverter is charging faster than battery is allowing.";
|
||||
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!";
|
||||
case EVENT_MODBUS_INVERTER_MISSING:
|
||||
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:
|
||||
return "CELL VOLTAGE CRITICALLY LOW! Not possible to continue. Inspect battery!";
|
||||
case EVENT_CELL_UNDER_VOLTAGE:
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
XX(EVENT_CAN_NATIVE_TX_FAILURE) \
|
||||
XX(EVENT_CHARGE_LIMIT_EXCEEDED) \
|
||||
XX(EVENT_CONTACTOR_WELDED) \
|
||||
XX(EVENT_CPU_OVERHEAT) \
|
||||
XX(EVENT_CPU_OVERHEATING) \
|
||||
XX(EVENT_CPU_OVERHEATED) \
|
||||
XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \
|
||||
XX(EVENT_WATER_INGRESS) \
|
||||
XX(EVENT_12V_LOW) \
|
||||
|
@ -54,6 +55,7 @@
|
|||
XX(EVENT_INVERTER_OPEN_CONTACTOR) \
|
||||
XX(EVENT_INTERFACE_MISSING) \
|
||||
XX(EVENT_MODBUS_INVERTER_MISSING) \
|
||||
XX(EVENT_NO_ENABLE_DETECTED) \
|
||||
XX(EVENT_ERROR_OPEN_CONTACTOR) \
|
||||
XX(EVENT_CELL_CRITICAL_UNDER_VOLTAGE) \
|
||||
XX(EVENT_CELL_CRITICAL_OVER_VOLTAGE) \
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "../include.h"
|
||||
#ifdef SMA_BYD_H_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "SMA-BYD-H-CAN.h"
|
||||
|
||||
/* TODO: Map error bits in 0x158 */
|
||||
|
@ -11,6 +12,8 @@ static unsigned long previousMillis100ms = 0;
|
|||
static uint32_t inverter_time = 0;
|
||||
static uint16_t inverter_voltage = 0;
|
||||
static int16_t inverter_current = 0;
|
||||
static uint16_t timeWithoutInverterAllowsContactorClosing = 0;
|
||||
#define THIRTY_MINUTES 1200
|
||||
|
||||
//Actual content messages
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
//TODO: add all error bits. Sending message with all 0xAA until that.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "../include.h"
|
||||
#ifdef SMA_BYD_HVS_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "SMA-BYD-HVS-CAN.h"
|
||||
|
||||
/* TODO: Map error bits in 0x158 */
|
||||
|
@ -11,6 +12,8 @@ static unsigned long previousMillis100ms = 0;
|
|||
static uint32_t inverter_time = 0;
|
||||
static uint16_t inverter_voltage = 0;
|
||||
static int16_t inverter_current = 0;
|
||||
static uint16_t timeWithoutInverterAllowsContactorClosing = 0;
|
||||
#define THIRTY_MINUTES 1200
|
||||
|
||||
//Actual content messages
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
//TODO: add all error bits. Sending message with all 0xAA until that.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "../include.h"
|
||||
#ifdef SMA_TRIPOWER_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "SMA-TRIPOWER-CAN.h"
|
||||
|
||||
/* TODO:
|
||||
|
@ -32,6 +33,8 @@ static int16_t inverter_current = 0;
|
|||
static bool pairing_completed = false;
|
||||
static int16_t temperature_average = 0;
|
||||
static uint16_t ampere_hours_remaining = 0;
|
||||
static uint16_t timeWithoutInverterAllowsContactorClosing = 0;
|
||||
#define THIRTY_MINUTES 1200
|
||||
|
||||
//Actual content messages
|
||||
CAN_frame SMA_358 = {.FD = false,
|
||||
|
@ -146,6 +149,17 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
|||
} else {
|
||||
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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue