Refactor CAN sending to interface agnostic

This commit is contained in:
Daniel Öster 2024-08-05 23:47:34 +03:00
parent 28703453f9
commit 4f508dba86
8 changed files with 78 additions and 57 deletions

View file

@ -878,3 +878,41 @@ void check_reset_reason() {
break; break;
} }
} }
void transmit_can(CAN_frame_t* tx_frame, int interface) {
switch (interface) {
case CAN_NATIVE:
ESP32Can.CANWriteFrame(tx_frame);
break;
case CANFD_NATIVE:
//TODO for stark
break;
case CAN_ADDON_MCP2515: {
#ifdef DUAL_CAN
//Struct with ACAN2515 library format, needed to use the MCP2515 library for CAN2
CANMessage MCP2515Frame;
MCP2515Frame.id = tx_frame->MsgID;
//MCP2515Frame.ext = false; //TODO: Howto handle this?
MCP2515Frame.len = tx_frame->FIR.B.DLC;
for (uint8_t i = 0; i < MCP2515Frame.len; i++) {
MCP2515Frame.data[i] = tx_frame->data.u8[i];
}
can.tryToSend(MCP2515Frame);
#endif
} break;
case CAN_ADDON_FD_MCP2518:
#ifdef CAN_FD
CANFDMessage MCP2518Frame;
MCP2518Frame.id = tx_frame->MsgID;
//MCP2518Frame.ext = false; //TODO: Howto handle this?
MCP2518Frame.len = tx_frame->FIR.B.DLC;
for (uint8_t i = 0; i < MCP2518Frame.len; i++) {
MCP2518Frame.data[i] = tx_frame->data.u8[i];
}
canfd.tryToSend(MCP2518Frame);
#endif
break;
default:
// Invalid interface sent with function call. TODO: Raise event that coders messed up
break;
}
}

View file

@ -13,10 +13,12 @@ CAN_ADDON_FD_MCP2518 = Add-on CAN-FD MCP2518 connected to GPIO pins
*/ */
volatile CAN_Configuration can_config = { volatile CAN_Configuration can_config = {
.battery = CAN_NATIVE, // Which CAN is your battery connected to? .battery = CAN_NATIVE, // Which CAN is your battery connected to?
.battery_double = CAN_ADDON_MCP2515, // Which CAN is your optional second battery connected to? .inverter = CAN_NATIVE // Which CAN is your inverter connected to? (No need to configure incase you use RS485)
.inverter = CAN_NATIVE // Which CAN is your inverter connected to? (Not needed for RS485 inverters) .battery_double = CAN_ADDON_MCP2515, // (OPTIONAL) Which CAN is your second battery connected to?
}; .charger = CAN_NATIVE; // (OPTIONAL) Which CAN is your charger connected to?
}
;
#ifdef WEBSERVER #ifdef WEBSERVER
volatile uint8_t AccessPointEnabled = true; //Set to either true/false to enable direct wifi access point volatile uint8_t AccessPointEnabled = true; //Set to either true/false to enable direct wifi access point

View file

@ -29,7 +29,7 @@
//#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires DUAL_CAN setup) //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires DUAL_CAN setup)
/* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */
#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus
//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU
//#define LUNA2000_MODBUS //Enable this line to emulate a "Luna2000 battery" over Modbus RTU //#define LUNA2000_MODBUS //Enable this line to emulate a "Luna2000 battery" over Modbus RTU
//#define PYLON_CAN //Enable this line to emulate a "Pylontech battery" over CAN bus //#define PYLON_CAN //Enable this line to emulate a "Pylontech battery" over CAN bus
@ -84,11 +84,12 @@
/* Do not change any code below this line unless you are sure what you are doing */ /* Do not change any code below this line unless you are sure what you are doing */
/* Only change battery specific settings in "USER_SETTINGS.h" */ /* Only change battery specific settings in "USER_SETTINGS.h" */
typedef enum { CAN_NATIVE = 0, CAN_ADDON_MCP2515 = 1, CAN_ADDON_FD_MCP2518 = 2 } CAN_Interface; typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CAN_ADDON_FD_MCP2518 = 3 } CAN_Interface;
typedef struct { typedef struct {
CAN_Interface battery; CAN_Interface battery;
CAN_Interface battery_double; CAN_Interface battery_double;
CAN_Interface inverter; CAN_Interface inverter;
CAN_Interface charger;
} CAN_Configuration; } CAN_Configuration;
extern volatile CAN_Configuration can_config; extern volatile CAN_Configuration can_config;
extern volatile uint8_t AccessPointEnabled; extern volatile uint8_t AccessPointEnabled;

View file

@ -344,17 +344,6 @@ void update_values_battery() { /* This function maps all the values fetched via
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
void CAN_WriteFrame(CAN_frame_t* tx_frame) {
CANMessage MCP2515Frame; //Struct with ACAN2515 library format, needed to use the MCP2515 library for CAN2
MCP2515Frame.id = tx_frame->MsgID;
//MCP2515Frame.ext = tx_frame->FIR.B.FF;
MCP2515Frame.len = tx_frame->FIR.B.DLC;
for (uint8_t i = 0; i < MCP2515Frame.len; i++) {
MCP2515Frame.data[i] = tx_frame->data.u8[i];
}
can.tryToSend(MCP2515Frame);
}
void update_values_battery2() { // Handle the values coming in from battery #2 void update_values_battery2() { // Handle the values coming in from battery #2
/* Start with mapping all values */ /* Start with mapping all values */
@ -611,7 +600,7 @@ void receive_can_battery2(CAN_frame_t rx_frame) {
break; break;
} }
CAN_WriteFrame(&LEAF_NEXT_LINE_REQUEST); // CAN2 transmit_can(&LEAF_NEXT_LINE_REQUEST, can_config.battery_double);
if (battery2_group_7bb == 1) //High precision SOC, Current, voltages etc. if (battery2_group_7bb == 1) //High precision SOC, Current, voltages etc.
{ {
@ -861,8 +850,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
if (stop_battery_query) { //Leafspy is active, stop our own polling if (stop_battery_query) { //Leafspy is active, stop our own polling
break; break;
} }
transmit_can(&LEAF_NEXT_LINE_REQUEST, can_config.battery); //Request the next frame for the group
ESP32Can.CANWriteFrame(&LEAF_NEXT_LINE_REQUEST); //Request the next frame for the group
if (group_7bb == 1) //High precision SOC, Current, voltages etc. if (group_7bb == 1) //High precision SOC, Current, voltages etc.
{ {
@ -1026,10 +1014,10 @@ void send_can_battery() {
LEAF_1D4.data.u8[7] = 0xDE; LEAF_1D4.data.u8[7] = 0xDE;
break; break;
} }
ESP32Can.CANWriteFrame(&LEAF_1D4); transmit_can(&LEAF_1D4, can_config.battery);
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
CAN_WriteFrame(&LEAF_1D4); // CAN2 transmit_can(&LEAF_1D4, can_config.battery_double);
#endif // DOUBLE_BATTERY #endif // DOUBLE_BATTERY
switch (mprun10r) { switch (mprun10r) {
case (0): case (0):
@ -1122,10 +1110,10 @@ void send_can_battery() {
//Only send this message when NISSANLEAF_CHARGER is not defined (otherwise it will collide!) //Only send this message when NISSANLEAF_CHARGER is not defined (otherwise it will collide!)
#ifndef NISSANLEAF_CHARGER #ifndef NISSANLEAF_CHARGER
ESP32Can.CANWriteFrame(&LEAF_1F2); //Contains (CHG_STA_RQ == 1 == Normal Charge) transmit_can(&LEAF_1F2, can_config.battery);
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
CAN_WriteFrame(&LEAF_1F2); // CAN2 transmit_can(&LEAF_1F2, can_config.battery_double);
#endif // DOUBLE_BATTERY #endif // DOUBLE_BATTERY
#endif #endif
mprun10r = (mprun10r + 1) % 20; // 0x1F2 patter repeats after 20 messages. 0-1..19-0 mprun10r = (mprun10r + 1) % 20; // 0x1F2 patter repeats after 20 messages. 0-1..19-0
@ -1145,10 +1133,10 @@ void send_can_battery() {
} }
// VCM message, containing info if battery should sleep or stay awake // VCM message, containing info if battery should sleep or stay awake
ESP32Can.CANWriteFrame(&LEAF_50B); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1 transmit_can(&LEAF_50B, can_config.battery); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
CAN_WriteFrame(&LEAF_50B); // CAN2 transmit_can(&LEAF_50B, can_config.battery_double);
#endif // DOUBLE_BATTERY #endif // DOUBLE_BATTERY
LEAF_50C.data.u8[3] = mprun100; LEAF_50C.data.u8[3] = mprun100;
switch (mprun100) { switch (mprun100) {
@ -1169,10 +1157,10 @@ void send_can_battery() {
LEAF_50C.data.u8[5] = 0x9A; LEAF_50C.data.u8[5] = 0x9A;
break; break;
} }
ESP32Can.CANWriteFrame(&LEAF_50C); transmit_can(&LEAF_50C, can_config.battery);
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
CAN_WriteFrame(&LEAF_50C); // CAN2 transmit_can(&LEAF_50C, can_config.battery_double);
#endif // DOUBLE_BATTERY #endif // DOUBLE_BATTERY
mprun100 = (mprun100 + 1) % 4; // mprun100 cycles between 0-1-2-3-0-1... mprun100 = (mprun100 + 1) % 4; // mprun100 cycles between 0-1-2-3-0-1...
} }
@ -1186,10 +1174,10 @@ void send_can_battery() {
group = (group == 1) ? 2 : (group == 2) ? 4 : 1; group = (group == 1) ? 2 : (group == 2) ? 4 : 1;
// Cycle between group 1, 2, and 4 using ternary operation // Cycle between group 1, 2, and 4 using ternary operation
LEAF_GROUP_REQUEST.data.u8[2] = group; LEAF_GROUP_REQUEST.data.u8[2] = group;
ESP32Can.CANWriteFrame(&LEAF_GROUP_REQUEST); transmit_can(&LEAF_GROUP_REQUEST, can_config.battery);
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
CAN_WriteFrame(&LEAF_GROUP_REQUEST); // CAN2 transmit_can(&LEAF_GROUP_REQUEST, can_config.battery_double);
#endif // DOUBLE_BATTERY #endif // DOUBLE_BATTERY
} }
if (hold_off_with_polling_10seconds > 0) { if (hold_off_with_polling_10seconds > 0) {
@ -1246,9 +1234,8 @@ void setup_battery(void) { // Performs one time setup at startup
#endif #endif
datalayer.battery.info.number_of_cells = 96; datalayer.battery.info.number_of_cells = 96;
datalayer.battery.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV = 4040; // 404.4V
4040; // 404.4V, over this, charging is not possible (goes into forced discharge) datalayer.battery.info.min_design_voltage_dV = 2600; // 260.0V
datalayer.battery.info.min_design_voltage_dV = 2600; // 260.0V under this, discharging further is disabled
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells; datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells;

View file

@ -2,17 +2,15 @@
#define NISSAN_LEAF_BATTERY_H #define NISSAN_LEAF_BATTERY_H
#include "../include.h" #include "../include.h"
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#include "../lib/pierremolinaro-acan2515/ACAN2515.h" #include "../lib/pierremolinaro-acan2515/ACAN2515.h"
extern ACAN2515 can;
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION_MV 500 #define MAX_CELL_DEVIATION_MV 500
uint16_t Temp_fromRAW_to_F(uint16_t temperature); uint16_t Temp_fromRAW_to_F(uint16_t temperature);
bool is_message_corrupt(CAN_frame_t rx_frame); bool is_message_corrupt(CAN_frame_t rx_frame);
void setup_battery(void); void setup_battery(void);
void transmit_can(CAN_frame_t* tx_frame, int interface);
#endif #endif

View file

@ -9,6 +9,14 @@ static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN
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 previousMillis10s = 0; // will store last time a 1s CAN Message was send static unsigned long previousMillis10s = 0; // will store last time a 1s CAN Message was send
CAN_frame_t TEST = {.FIR = {.B =
{
.DLC = 8,
.FF = CAN_frame_std,
}},
.MsgID = 0x123,
.data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}};
void print_units(char* header, int value, char* units) { void print_units(char* header, int value, char* units) {
Serial.print(header); Serial.print(header);
Serial.print(value); Serial.print(value);
@ -87,6 +95,7 @@ void send_can_battery() {
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
// Put fake messages here incase you want to test sending CAN // Put fake messages here incase you want to test sending CAN
transmit_can(&TEST, can_config.battery);
} }
} }

View file

@ -1,10 +1,12 @@
#ifndef TEST_FAKE_BATTERY_H #ifndef TEST_FAKE_BATTERY_H
#define TEST_FAKE_BATTERY_H #define TEST_FAKE_BATTERY_H
#include "../include.h" #include "../include.h"
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION_MV 9999 #define MAX_CELL_DEVIATION_MV 9999
void setup_battery(void); void setup_battery(void);
void transmit_can(CAN_frame_t* tx_frame, int interface);
#endif #endif

View file

@ -3,22 +3,6 @@
#include "../../../USER_SETTINGS.h" #include "../../../USER_SETTINGS.h"
/* Enumeration for CAN interfaces
typedef enum {
CAN_NATIVE = 0,
CANFD_NATIVE = 1,
CAN_ADDON_MCP2515 = 2,
CAN_ADDON_FD_MCP2518 = 3
} CAN_Interface;
/* Struct to hold CAN assignments for components
typedef struct {
CAN_Interface battery;
CAN_Interface battery_double;
CAN_Interface inverter;
} CAN_Configuration;
*/
#if defined(HW_LILYGO) #if defined(HW_LILYGO)
#include "hw_lilygo.h" #include "hw_lilygo.h"
#elif defined(HW_STARK) #elif defined(HW_STARK)