Merge branch 'main' into improvement/can-overrun-refactoring

This commit is contained in:
Daniel Öster 2025-05-01 13:54:21 +03:00
commit bdc28b34a7
14 changed files with 149 additions and 29 deletions

View file

@ -0,0 +1,29 @@
#include "../include.h"
// These functions adapt the old C-style global functions battery-API to the
// object-oriented battery API.
#ifdef OO_BATTERY_SELECTED
static CanBattery* battery;
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();
battery->setup();
}
void update_values_battery() {
battery->update_values();
}
void transmit_can_battery(unsigned long currentMillis) {
battery->transmit_can(currentMillis);
}
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
battery->handle_incoming_can_frame(rx_frame);
}
#endif

View file

@ -2,6 +2,19 @@
#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);

View file

@ -195,7 +195,10 @@ static uint8_t alive_counter_5000ms = 0;
static uint8_t BMW_1D0_counter = 0;
static uint8_t BMW_13E_counter = 0;
static uint8_t BMW_380_counter = 0;
static uint32_t BMW_328_counter = 0;
static uint32_t BMW_328_seconds = 243785948; // Initialized to make the battery think vehicle was made 7.7years ago
static uint16_t BMW_328_days =
9244; //Time since 1.1.2000. Hacky implementation to make it think current date is 23rd April 2025
static uint32_t BMS_328_seconds_to_day = 0; //Counter to keep track of days uptime
static bool battery_awake = false;
static bool battery2_awake = false;
@ -966,12 +969,23 @@ void transmit_can_battery(unsigned long currentMillis) {
// Send 1000ms CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis;
BMW_328_counter++; // Used to increment seconds
BMW_328.data.u8[0] = BMW_328_counter;
BMW_328.data.u8[1] = BMW_328_counter << 8;
BMW_328.data.u8[2] = BMW_328_counter << 16;
BMW_328.data.u8[3] = BMW_328_counter << 24;
//BMW_328 byte0-3 = Second Counter (T_SEC_COU_REL) time_second_counter_relative
// This signal shows the time in seconds since the system time was started (typically in the factory)
BMW_328_seconds++; // Used to increment seconds
BMW_328.data.u8[0] = (uint8_t)(BMW_328_seconds & 0xFF);
BMW_328.data.u8[1] = (uint8_t)((BMW_328_seconds >> 8) & 0xFF);
BMW_328.data.u8[2] = (uint8_t)((BMW_328_seconds >> 16) & 0xFF);
BMW_328.data.u8[3] = (uint8_t)((BMW_328_seconds >> 24) & 0xFF);
//BMW_328 byte 4-5 = Day Counter (T_DAY_COU_ABSL) time_day_counter_absolute
//This value goes from 1 ... 65543
// Day 1 = 1.1.2000 ... Day 65543 = year 2179
BMS_328_seconds_to_day++;
if (BMS_328_seconds_to_day > 86400) {
BMW_328_days++;
BMS_328_seconds_to_day = 0;
}
BMW_328.data.u8[4] = (uint8_t)(BMW_328_days & 0xFF);
BMW_328.data.u8[5] = (uint8_t)((BMW_328_days >> 8) & 0xFF);
BMW_1D0.data.u8[1] = ((BMW_1D0.data.u8[1] & 0xF0) + alive_counter_1000ms);
BMW_1D0.data.u8[0] = calculateCRC(BMW_1D0, 8, 0xF9);

View file

@ -4,6 +4,8 @@
#include "../devboard/utils/events.h"
#include "RENAULT-ZOE-GEN1-BATTERY.h"
void transmit_can_frame(CAN_frame* tx_frame, int interface);
/* Information in this file is based of the OVMS V3 vehicle_renaultzoe.cpp component
https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/blob/master/vehicle/OVMS.V3/components/vehicle_renaultzoe/src/vehicle_renaultzoe.cpp
The Zoe BMS apparently does not send total pack voltage, so we use the polled 96x cellvoltages summed up as total voltage
@ -75,7 +77,8 @@ static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN
static unsigned long previousMillis250 = 0; // will store last time a 250ms CAN Message was sent
static uint8_t counter_423 = 0;
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
void RenaultZoeGen1Battery::
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
datalayer.battery.status.soh_pptt = (LB_SOH * 100); // Increase range from 99% -> 99.00%
datalayer.battery.status.real_soc = SOC_polled;
@ -134,7 +137,7 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.voltage_dV = static_cast<uint32_t>((calculated_total_pack_voltage_mV / 100)); // mV to dV
}
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x155: //10ms - Charging power, current and SOC
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
@ -490,7 +493,8 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
}
}
void transmit_can_battery(unsigned long currentMillis) {
void RenaultZoeGen1Battery::transmit_can(unsigned long currentMillis) {
// Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis;
@ -537,7 +541,7 @@ void transmit_can_battery(unsigned long currentMillis) {
}
}
void setup_battery(void) { // Performs one time setup at startup
void RenaultZoeGen1Battery::setup(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen1 22/40kWh", 63);
datalayer.system.info.battery_protocol[63] = '\0';
datalayer.system.status.battery_allows_contactor_closing = true;

View file

@ -3,13 +3,22 @@
#include "../include.h"
#define BATTERY_SELECTED
// 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 MIN_PACK_VOLTAGE_DV 3000
#define MAX_CELL_DEVIATION_MV 150
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
#define MIN_CELL_VOLTAGE_MV 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 RenaultZoeGen1Battery : public CanBattery {
public:
virtual void setup(void);
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
virtual void update_values();
virtual void transmit_can(unsigned long currentMillis);
};
#endif

View file

@ -6,11 +6,11 @@
#define BATTERY_SELECTED
#define MAX_PACK_VOLTAGE_108S_DV 4540
#define MIN_PACK_VOLTAGE_108S_DV 2938
#define MAX_PACK_VOLTAGE_96S_DV 4030
#define MAX_PACK_VOLTAGE_96S_DV 4080
#define MIN_PACK_VOLTAGE_96S_DV 2620
#define MAX_CELL_DEVIATION_MV 250
#define MAX_CELL_VOLTAGE_MV 4210 //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 MAX_CELL_VOLTAGE_MV 4260 // Charging is halted if one cell goes above this
#define MIN_CELL_VOLTAGE_MV 2700 // Charging is halted if one cell goes below this
void setup_battery(void);
void transmit_can_frame(CAN_frame* tx_frame, int interface);

View file

@ -1,6 +1,8 @@
#include "obd.h"
#include "comm_can.h"
void transmit_can_frame(CAN_frame* tx_frame, int interface);
void show_dtc(uint8_t byte0, uint8_t byte1);
void show_dtc(uint8_t byte0, uint8_t byte1) {

View file

@ -30,10 +30,8 @@ void init_rs485() {
Serial2.begin(RS485_BAUDRATE, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN);
#endif // RS485_INVERTER_SELECTED || RS485_BATTERY_SELECTED
#ifdef MODBUS_INVERTER_SELECTED
#ifdef BYD_MODBUS
// Init Static data to the RTU Modbus
handle_static_data_modbus_byd();
#endif // BYD_MODBUS
handle_static_data_modbus();
// Init Serial2 connected to the RTU Modbus
RTUutils::prepareHardwareSerial(Serial2);
Serial2.begin(9600, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN);

View file

@ -52,7 +52,7 @@ GPIOs on extra header
#define BMS_POWER 23
// SMA CAN contactor pins
#define INVERTER_CONTACTOR_ENABLE_PIN 19
#define INVERTER_CONTACTOR_ENABLE_PIN 2
// LED
#define LED_PIN 4

View file

@ -11,6 +11,8 @@
#include "../utils/timer.h"
#include "esp_task_wdt.h"
void transmit_can_frame(CAN_frame* tx_frame, int interface);
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

View file

@ -17,14 +17,20 @@ static uint8_t history_index = 0;
static uint8_t bms_char_dis_status = STANDBY;
static bool all_401_values_equal = false;
void update_modbus_registers_inverter() {
void verify_inverter_modbus();
void verify_temperature_modbus();
void handle_update_data_modbusp201_byd();
void handle_update_data_modbusp301_byd();
void handle_static_data_modbus_byd();
void BydModbusInverter::update_modbus_registers() {
verify_temperature_modbus();
verify_inverter_modbus();
handle_update_data_modbusp201_byd();
handle_update_data_modbusp301_byd();
}
void handle_static_data_modbus_byd() {
void BydModbusInverter::handle_static_data() {
// Store the data into the array
static uint16_t si_data[] = {21321, 1};
static uint16_t byd_data[] = {16985, 17408, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@ -144,8 +150,10 @@ void verify_inverter_modbus() {
history_index = (history_index + 1) % HISTORY_LENGTH;
}
}
void setup_inverter(void) { // Performs one time setup at startup over CAN bus
void BydModbusInverter::setup(void) { // Performs one time setup at startup over CAN bus
strncpy(datalayer.system.info.inverter_protocol, "BYD 11kWh HVM battery over Modbus RTU", 63);
datalayer.system.info.inverter_protocol[63] = '\0';
}
#endif

View file

@ -3,16 +3,18 @@
#include "../include.h"
#define MODBUS_INVERTER_SELECTED
#define OO_INVERTER_PROTOCOL_SELECTED
#define MB_RTU_NUM_VALUES 13100
#define MAX_POWER 40960 //BYD Modbus specific value
extern uint16_t mbPV[MB_RTU_NUM_VALUES];
void handle_static_data_modbus_byd();
void verify_temperature_modbus();
void verify_inverter_modbus();
void handle_update_data_modbusp201_byd();
void handle_update_data_modbusp301_byd();
void setup_inverter(void);
class BydModbusInverter : public ModbusInverterProtocol {
public:
void setup();
void update_modbus_registers();
void handle_static_data();
};
#endif

View file

@ -0,0 +1,24 @@
#include "../include.h"
// These functions adapt the old C-style global functions inverter-API to the
// object-oriented inverter protocol API.
#ifdef OO_INVERTER_PROTOCOL_SELECTED
ModbusInverterProtocol* inverter;
void setup_inverter() {
// Currently only a single inverter protocol is implemented as a class
inverter = new BydModbusInverter();
inverter->setup();
}
void update_modbus_registers_inverter() {
inverter->update_modbus_registers();
}
void handle_static_data_modbus() {
inverter->handle_static_data();
}
#endif

View file

@ -1,6 +1,19 @@
#ifndef INVERTERS_H
#define INVERTERS_H
// The abstract base class for all inverter protocols
class InverterProtocol {
public:
virtual void setup() = 0;
};
// The abstract base class for all Modbus inverter protocols
class ModbusInverterProtocol : public InverterProtocol {
public:
virtual void update_modbus_registers() = 0;
virtual void handle_static_data();
};
#include "../../USER_SETTINGS.h"
#ifdef AFORE_CAN
@ -87,6 +100,8 @@ void transmit_can_inverter(unsigned long currentMillis);
#ifdef MODBUS_INVERTER_SELECTED
void update_modbus_registers_inverter();
void setup_inverter();
void handle_static_data_modbus();
#endif
#ifdef RS485_INVERTER_SELECTED