mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 18:29:48 +02:00
Merge branch 'main' into improvement/can-overrun-refactoring
This commit is contained in:
commit
bdc28b34a7
14 changed files with 149 additions and 29 deletions
29
Software/src/battery/BATTERIES.cpp
Normal file
29
Software/src/battery/BATTERIES.cpp
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
24
Software/src/inverter/INVERTERS.cpp
Normal file
24
Software/src/inverter/INVERTERS.cpp
Normal 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
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue