Make tests pass

This commit is contained in:
Daniel Öster 2025-09-01 21:27:09 +03:00
parent 024ff58965
commit 12cc542a42
44 changed files with 362 additions and 259 deletions

View file

@ -37,7 +37,7 @@ uint8_t BmwIXBattery::increment_alive_counter(uint8_t counter) {
return counter; return counter;
} }
static byte increment_C0_counter(byte counter) { static uint8_t increment_C0_counter(uint8_t counter) {
counter++; counter++;
// Reset to 0xF0 if it exceeds 0xFE // Reset to 0xF0 if it exceeds 0xFE
if (counter > 0xFE) { if (counter > 0xFE) {
@ -459,10 +459,12 @@ void BmwIXBattery::setup(void) { // Performs one time setup at startup
void BmwIXBattery::HandleIncomingUserRequest(void) { void BmwIXBattery::HandleIncomingUserRequest(void) {
// Debug user request to open or close the contactors // Debug user request to open or close the contactors
logging.print("User request: contactor close: "); if (userRequestContactorClose) {
logging.print(userRequestContactorClose); logging.printf("User request: contactor close");
logging.print(" User request: contactor open: "); }
logging.println(userRequestContactorOpen); if (userRequestContactorOpen) {
logging.printf("User request: contactor open");
}
if ((userRequestContactorClose == false) && (userRequestContactorOpen == false)) { if ((userRequestContactorClose == false) && (userRequestContactorOpen == false)) {
// do nothing // do nothing
} else if ((userRequestContactorClose == true) && (userRequestContactorOpen == false)) { } else if ((userRequestContactorClose == true) && (userRequestContactorOpen == false)) {

View file

@ -1,5 +1,6 @@
#include "BMW-PHEV-BATTERY.h" #include "BMW-PHEV-BATTERY.h"
#include <Arduino.h> #include <Arduino.h>
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"
@ -149,15 +150,6 @@ uint8_t BmwPhevBattery::increment_alive_counter(uint8_t counter) {
return counter; return counter;
} }
static byte increment_0C0_counter(byte counter) {
counter++;
// Reset to 0xF0 if it exceeds 0xFE
if (counter > 0xFE) {
counter = 0xF0;
}
return counter;
}
void BmwPhevBattery::processCellVoltages() { void BmwPhevBattery::processCellVoltages() {
const int startByte = 3; // Start reading at byte 3 const int startByte = 3; // Start reading at byte 3
const int numVoltages = 96; // Number of cell voltage values to process const int numVoltages = 96; // Number of cell voltage values to process
@ -469,7 +461,7 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
#endif // DEBUG_LOG && UDS_LOG #endif // DEBUG_LOG && UDS_LOG
transmit_can_frame(&BMW_6F1_REQUEST_CONTINUE_MULTIFRAME); transmit_can_frame(&BMW_6F1_REQUEST_CONTINUE_MULTIFRAME);
gUDSContext.receivedInBatch = 0; // Reset batch count gUDSContext.receivedInBatch = 0; // Reset batch count
Serial.println("Sent FC for next batch of 3 frames."); logging.println("Sent FC for next batch of 3 frames.");
} }
break; break;
@ -513,18 +505,18 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
battery_current = ((int32_t)((gUDSContext.UDS_buffer[3] << 24) | (gUDSContext.UDS_buffer[4] << 16) | battery_current = ((int32_t)((gUDSContext.UDS_buffer[3] << 24) | (gUDSContext.UDS_buffer[4] << 16) |
(gUDSContext.UDS_buffer[5] << 8) | gUDSContext.UDS_buffer[6])) * (gUDSContext.UDS_buffer[5] << 8) | gUDSContext.UDS_buffer[6])) *
0.1; 0.1;
logging.print("Received current/amps measurement data: "); logging.printf("Received current/amps measurement data: ");
logging.print(battery_current); logging.print(battery_current);
logging.print(" - "); logging.printf(" - ");
for (uint16_t i = 0; i < gUDSContext.UDS_bytesReceived; i++) { for (uint16_t i = 0; i < gUDSContext.UDS_bytesReceived; i++) {
// Optional leading zero for single-digit hex // Optional leading zero for single-digit hex
if (gUDSContext.UDS_buffer[i] < 0x10) { if (gUDSContext.UDS_buffer[i] < 0x10) {
logging.print("0"); logging.printf("0");
} }
logging.print(gUDSContext.UDS_buffer[i], HEX); logging.print(gUDSContext.UDS_buffer[i]);
logging.print(" "); logging.printf(" ");
} }
logging.println(); // new line at the end logging.println(""); // new line at the end
} }
//Cell Min/Max //Cell Min/Max
@ -540,14 +532,14 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
max_cell_voltage = (gUDSContext.UDS_buffer[11] << 8 | gUDSContext.UDS_buffer[12]) / 10; max_cell_voltage = (gUDSContext.UDS_buffer[11] << 8 | gUDSContext.UDS_buffer[12]) / 10;
} else { } else {
logging.println("Cell Min Max Invalid 65535 or 0..."); logging.println("Cell Min Max Invalid 65535 or 0...");
logging.print("Received data: "); logging.printf("Received data: ");
for (uint16_t i = 0; i < gUDSContext.UDS_bytesReceived; i++) { for (uint16_t i = 0; i < gUDSContext.UDS_bytesReceived; i++) {
// Optional leading zero for single-digit hex // Optional leading zero for single-digit hex
if (gUDSContext.UDS_buffer[i] < 0x10) { if (gUDSContext.UDS_buffer[i] < 0x10) {
logging.print("0"); logging.printf("0");
} }
logging.print(gUDSContext.UDS_buffer[i], HEX); logging.print(gUDSContext.UDS_buffer[i]);
logging.print(" "); logging.printf(" ");
} }
logging.println(); // new line at the end logging.println(); // new line at the end
} }
@ -678,7 +670,7 @@ void BmwPhevBattery::transmit_can(unsigned long currentMillis) {
} }
void BmwPhevBattery::setup(void) { // Performs one time setup at startup void BmwPhevBattery::setup(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, "BMW PHEV Battery", 63); strncpy(datalayer.system.info.battery_protocol, Name, 63);
datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.info.battery_protocol[63] = '\0';
//Wakeup the SME //Wakeup the SME
wake_battery_via_canbus(); wake_battery_via_canbus();

View file

@ -10,6 +10,8 @@ class BmwPhevBattery : public CanBattery {
virtual void update_values(); virtual void update_values();
virtual void transmit_can(unsigned long currentMillis); virtual void transmit_can(unsigned long currentMillis);
static constexpr const char* Name = "BMW PHEV Battery";
BatteryHtmlRenderer& get_status_renderer() { return renderer; } BatteryHtmlRenderer& get_status_renderer() { return renderer; }
private: private:

View file

@ -1,4 +1,5 @@
#include "BOLT-AMPERA-BATTERY.h" #include "BOLT-AMPERA-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"

View file

@ -1,4 +1,5 @@
#include "BYD-ATTO-3-BATTERY.h" #include "BYD-ATTO-3-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"

View file

@ -120,7 +120,7 @@ void ChademoBattery::process_vehicle_charging_session(CAN_frame rx_frame) {
uint8_t chargingrate = 0; uint8_t chargingrate = 0;
if (x100_chg_lim.ConstantOfChargingRateIndication > 0) { if (x100_chg_lim.ConstantOfChargingRateIndication > 0) {
chargingrate = x102_chg_session.StateOfCharge / x100_chg_lim.ConstantOfChargingRateIndication * 100; chargingrate = x102_chg_session.StateOfCharge / x100_chg_lim.ConstantOfChargingRateIndication * 100;
logging.print("Charge Rate (kW): "); logging.printf("Charge Rate (kW): ");
logging.println(chargingrate); logging.println(chargingrate);
} }
@ -220,9 +220,9 @@ void ChademoBattery::process_vehicle_charging_limits(CAN_frame rx_frame) {
if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage && CHADEMO_Status > CHADEMO_NEGOTIATE) { if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage && CHADEMO_Status > CHADEMO_NEGOTIATE) {
logging.println("x200 minimum discharge voltage met or exceeded, stopping."); logging.println("x200 minimum discharge voltage met or exceeded, stopping.");
logging.print("Measured: "); logging.printf("Measured: ");
logging.print(get_measured_voltage()); logging.print(get_measured_voltage());
logging.print("Minimum voltage: "); logging.printf("Minimum voltage: ");
logging.print(x200_discharge_limits.MinimumDischargeVoltage); logging.print(x200_discharge_limits.MinimumDischargeVoltage);
CHADEMO_Status = CHADEMO_STOP; CHADEMO_Status = CHADEMO_STOP;
} }
@ -240,9 +240,9 @@ void ChademoBattery::process_vehicle_discharge_estimate(CAN_frame rx_frame) {
if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { if (currentMillis - previousMillis5000 >= INTERVAL_5_S) {
previousMillis5000 = currentMillis; previousMillis5000 = currentMillis;
logging.print("x201 availabile vehicle energy, completion time: "); logging.printf("x201 availabile vehicle energy, completion time: ");
logging.println(x201_discharge_estimate.AvailableVehicleEnergy); logging.println(x201_discharge_estimate.AvailableVehicleEnergy);
logging.print("x201 approx vehicle completion time: "); logging.printf("x201 approx vehicle completion time: ");
logging.println(x201_discharge_estimate.ApproxDischargeCompletionTime); logging.println(x201_discharge_estimate.ApproxDischargeCompletionTime);
} }
} }
@ -766,7 +766,7 @@ void ChademoBattery::handle_chademo_sequence() {
/* check whether contactors ready, because externally dependent upon inverter allow during discharge */ /* check whether contactors ready, because externally dependent upon inverter allow during discharge */
if (contactors_ready) { if (contactors_ready) {
logging.println("Contactors ready"); logging.println("Contactors ready");
logging.print("Voltage: "); logging.printf("Voltage: ");
logging.println(get_measured_voltage()); logging.println(get_measured_voltage());
/* transition to POWERFLOW state if discharge compatible on both sides */ /* transition to POWERFLOW state if discharge compatible on both sides */
if (x109_evse_state.discharge_compatible && x102_chg_session.s.status.StatusVehicleDischargeCompatible && if (x109_evse_state.discharge_compatible && x102_chg_session.s.status.StatusVehicleDischargeCompatible &&

View file

@ -22,7 +22,6 @@
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "CHADEMO-BATTERY.h" #include "CHADEMO-BATTERY.h"
#include "src/devboard/utils/logging.h"
/* Initial frames received from ISA shunts provide invalid during initialization */ /* Initial frames received from ISA shunts provide invalid during initialization */
static int framecount = 0; static int framecount = 0;
@ -87,17 +86,6 @@ void ISA_handleFrame(CAN_frame* frame) {
case 0x510: case 0x510:
case 0x511: case 0x511:
logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D
logging.print(" ");
logging.print(frame->ID, HEX);
logging.print(" ");
logging.print(frame->DLC);
logging.print(" ");
for (int i = 0; i < frame->DLC; ++i) {
logging.print(frame->data.u8[i], HEX);
logging.print(" ");
}
logging.println("");
break; break;
case 0x521: case 0x521:
@ -245,7 +233,7 @@ void ISA_initialize() {
ISA_STOP(); ISA_STOP();
delay(500); delay(500);
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
logging.print("ISA Initialization "); logging.printf("ISA Initialization ");
logging.println(i); logging.println(i);
outframe.data.u8[0] = (0x20 + i); outframe.data.u8[0] = (0x20 + i);
@ -382,7 +370,7 @@ void ISA_initCurrent() {
} }
void ISA_getCONFIG(uint8_t i) { void ISA_getCONFIG(uint8_t i) {
logging.print("ISA Get Config "); logging.printf("ISA Get Config ");
logging.println(i); logging.println(i);
outframe.data.u8[0] = (0x60 + i); outframe.data.u8[0] = (0x60 + i);
@ -398,7 +386,7 @@ void ISA_getCONFIG(uint8_t i) {
} }
void ISA_getCAN_ID(uint8_t i) { void ISA_getCAN_ID(uint8_t i) {
logging.print("ISA Get CAN ID "); logging.printf("ISA Get CAN ID ");
logging.println(i); logging.println(i);
outframe.data.u8[0] = (0x50 + i); outframe.data.u8[0] = (0x50 + i);
@ -418,8 +406,8 @@ void ISA_getCAN_ID(uint8_t i) {
} }
void ISA_getINFO(uint8_t i) { void ISA_getINFO(uint8_t i) {
logging.print("ISA Get INFO "); logging.printf("ISA Get INFO ");
logging.println(i, HEX); logging.println(i);
outframe.data.u8[0] = (0x70 + i); outframe.data.u8[0] = (0x70 + i);
outframe.data.u8[1] = 0x00; outframe.data.u8[1] = 0x00;

View file

@ -1,4 +1,5 @@
#include "CMFA-EV-BATTERY.h" #include "CMFA-EV-BATTERY.h"
#include <cstring> //unit tests memcpy
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"

View file

@ -16,7 +16,7 @@ static uint16_t voltage_dV = 0;
static uint32_t remaining_capacity_mAh = 0; static uint32_t remaining_capacity_mAh = 0;
static uint16_t cellvoltages_mV[48] = {0}; static uint16_t cellvoltages_mV[48] = {0};
static uint16_t cellvoltage_min_mV = 3700; static uint16_t cellvoltage_min_mV = 3700;
static uint16_t cellvoltage_max_mV = 3700; static uint16_t cellvoltage_max_mV = 0;
static uint16_t cell_count = 0; static uint16_t cell_count = 0;
static uint16_t SOC = 0; static uint16_t SOC = 0;
static bool has_fault = false; static bool has_fault = false;
@ -109,12 +109,12 @@ uint32_t decode_uint32be(uint8_t data[8], uint8_t offset) {
} }
void dump_buff(const char* msg, uint8_t* buff, uint8_t len) { void dump_buff(const char* msg, uint8_t* buff, uint8_t len) {
logging.print("[DALY-BMS] "); logging.printf("[DALY-BMS] ");
logging.print(msg); logging.printf(msg);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
logging.print(buff[i] >> 4, HEX); logging.print(buff[i] >> 4);
logging.print(buff[i] & 0xf, HEX); logging.print(buff[i] & 0xf);
logging.print(" "); logging.printf(" ");
} }
logging.println(); logging.println();
} }

View file

@ -1,4 +1,5 @@
#include "FOXESS-BATTERY.h" #include "FOXESS-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"

View file

@ -1,4 +1,5 @@
#include "GEELY-GEOMETRY-C-BATTERY.h" #include "GEELY-GEOMETRY-C-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"

View file

@ -1,6 +1,7 @@
#ifndef _GEELY_GEOMETRY_C_HTML_H #ifndef _GEELY_GEOMETRY_C_HTML_H
#define _GEELY_GEOMETRY_C_HTML_H #define _GEELY_GEOMETRY_C_HTML_H
#include <cstring> //For unit test
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"
#include "../devboard/webserver/BatteryHtmlRenderer.h" #include "../devboard/webserver/BatteryHtmlRenderer.h"

View file

@ -1,4 +1,5 @@
#include "IMIEV-CZERO-ION-BATTERY.h" #include "IMIEV-CZERO-ION-BATTERY.h"
#include <cstring> //for unit tests
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
@ -76,17 +77,8 @@ void ImievCZeroIonBattery::
if (!BMU_Detected) { if (!BMU_Detected) {
logging.println("BMU not detected, check wiring!"); logging.println("BMU not detected, check wiring!");
//TODO: Raise event
} }
logging.println("Battery Values");
logging.print("BMU SOC: ");
logging.print(BMU_SOC);
logging.print(" BMU Current: ");
logging.print(BMU_Current);
logging.print(" BMU Battery Voltage: ");
logging.print(BMU_PackVoltage);
logging.print(" BMU_Power: ");
logging.print(BMU_Power);
} }
void ImievCZeroIonBattery::handle_incoming_can_frame(CAN_frame rx_frame) { void ImievCZeroIonBattery::handle_incoming_can_frame(CAN_frame rx_frame) {

View file

@ -1,4 +1,5 @@
#include "JAGUAR-IPACE-BATTERY.h" #include "JAGUAR-IPACE-BATTERY.h"
#include <cstring> //for unit tests
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
@ -57,9 +58,9 @@ CAN_frame ipace_keep_alive = {.FD = false,
.data = {0x9E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};*/ .data = {0x9E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};*/
static void print_units(const char* header, int value, const char* units) { static void print_units(const char* header, int value, const char* units) {
logging.print(header); logging.printf(header);
logging.print(value); logging.printf("%d", value);
logging.print(units); logging.printf(units);
} }
void JaguarIpaceBattery::update_values() { void JaguarIpaceBattery::update_values() {

View file

@ -55,18 +55,6 @@ uint16_t KiaEGmpBattery::estimateSOC(uint16_t packVoltage, uint16_t cellCount, i
// Calculate average cell voltage in millivolts // Calculate average cell voltage in millivolts
uint16_t avgCellVoltage = compensatedPackVoltageMv / cellCount; uint16_t avgCellVoltage = compensatedPackVoltageMv / cellCount;
logging.print("Pack: ");
logging.print(packVoltage / 10.0);
logging.print("V, Current: ");
logging.print(currentAmps / 10.0);
logging.print("A, Drop: ");
logging.print(voltageDrop / 1000.0);
logging.print("V, Comp Pack: ");
logging.print(compensatedPackVoltageMv / 1000.0);
logging.print("V, Avg Cell: ");
logging.print(avgCellVoltage);
logging.println("mV");
// Use the cell voltage lookup table to estimate SOC // Use the cell voltage lookup table to estimate SOC
return estimateSOCFromCell(avgCellVoltage); return estimateSOCFromCell(avgCellVoltage);
} }
@ -182,65 +170,6 @@ void KiaEGmpBattery::update_values() {
if (leadAcidBatteryVoltage < 110) { if (leadAcidBatteryVoltage < 110) {
set_event(EVENT_12V_LOW, leadAcidBatteryVoltage); set_event(EVENT_12V_LOW, leadAcidBatteryVoltage);
} }
/* Safeties verified. Perform USB serial printout if configured to do so */
logging.println(); //sepatator
logging.println("Values from battery: ");
logging.print("SOC BMS: ");
logging.print((uint16_t)SOC_BMS / 10.0, 1);
logging.print("% | SOC Display: ");
logging.print((uint16_t)SOC_Display / 10.0, 1);
logging.print("% | SOH ");
logging.print((uint16_t)batterySOH / 10.0, 1);
logging.println("%");
logging.print((int16_t)batteryAmps / 10.0, 1);
logging.print(" Amps | ");
logging.print((uint16_t)batteryVoltage / 10.0, 1);
logging.print(" Volts | ");
logging.print((int16_t)datalayer.battery.status.active_power_W);
logging.println(" Watts");
logging.print("Allowed Charge ");
logging.print((uint16_t)allowedChargePower * 10);
logging.print(" W | Allowed Discharge ");
logging.print((uint16_t)allowedDischargePower * 10);
logging.println(" W");
logging.print("MaxCellVolt ");
logging.print(CellVoltMax_mV);
logging.print(" mV No ");
logging.print(CellVmaxNo);
logging.print(" | MinCellVolt ");
logging.print(CellVoltMin_mV);
logging.print(" mV No ");
logging.println(CellVminNo);
logging.print("TempHi ");
logging.print((int16_t)temperatureMax);
logging.print("°C TempLo ");
logging.print((int16_t)temperatureMin);
logging.print("°C WaterInlet ");
logging.print((int8_t)temperature_water_inlet);
logging.print("°C PowerRelay ");
logging.print((int8_t)powerRelayTemperature * 2);
logging.println("°C");
logging.print("Aux12volt: ");
logging.print((int16_t)leadAcidBatteryVoltage / 10.0, 1);
logging.println("V | ");
logging.print("BmsManagementMode ");
logging.print((uint8_t)batteryManagementMode, BIN);
if (bitRead((uint8_t)BMS_ign, 2) == 1) {
logging.print(" | BmsIgnition ON");
} else {
logging.print(" | BmsIgnition OFF");
}
if (bitRead((uint8_t)batteryRelay, 0) == 1) {
logging.print(" | PowerRelay ON");
} else {
logging.print(" | PowerRelay OFF");
}
logging.print(" | Inverter ");
logging.print(inverterVoltage);
logging.println(" Volts");
} }
// Getter implementations for HTML renderer // Getter implementations for HTML renderer
@ -321,14 +250,10 @@ void KiaEGmpBattery::handle_incoming_can_frame(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 0x7EC: case 0x7EC:
// print_canfd_frame(frame);
switch (rx_frame.data.u8[0]) { switch (rx_frame.data.u8[0]) {
case 0x10: //"PID Header" case 0x10: //"PID Header"
// logging.println ("Send ack");
poll_data_pid = rx_frame.data.u8[4]; poll_data_pid = rx_frame.data.u8[4];
// if (rx_frame.data.u8[4] == poll_data_pid) { transmit_can_frame(&EGMP_7E4_ack); //Send ack to BMS
transmit_can_frame(&EGMP_7E4_ack); //Send ack to BMS if the same frame is sent as polled
// }
break; break;
case 0x21: //First frame in PID group case 0x21: //First frame in PID group
if (poll_data_pid == 1) { if (poll_data_pid == 1) {

View file

@ -1,4 +1,5 @@
#include "KIA-HYUNDAI-64-BATTERY.h" #include "KIA-HYUNDAI-64-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"

View file

@ -1,6 +1,7 @@
#ifndef _KIA_HYUNDAI_64_HTML_H #ifndef _KIA_HYUNDAI_64_HTML_H
#define _KIA_HYUNDAI_64_HTML_H #define _KIA_HYUNDAI_64_HTML_H
#include <cstring> //For unit test
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"
#include "../devboard/webserver/BatteryHtmlRenderer.h" #include "../devboard/webserver/BatteryHtmlRenderer.h"

View file

@ -1,4 +1,5 @@
#include "KIA-HYUNDAI-HYBRID-BATTERY.h" #include "KIA-HYUNDAI-HYBRID-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"

View file

@ -1,6 +1,7 @@
#include "MEB-BATTERY.h" #include "MEB-BATTERY.h"
#include <Arduino.h> #include <Arduino.h>
#include <algorithm> // For std::min and std::max #include <algorithm> // For std::min and std::max
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../communication/can/obd.h" #include "../communication/can/obd.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
@ -1262,8 +1263,6 @@ void MebBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
handle_obd_frame(rx_frame); handle_obd_frame(rx_frame);
break; break;
default: default:
logging.printf("Unknown CAN frame received:\n");
dump_can_frame(rx_frame, MSG_RX);
break; break;
} }
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;

View file

@ -1,4 +1,5 @@
#include "MG-5-BATTERY.h" #include "MG-5-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
@ -112,7 +113,7 @@ void Mg5Battery::transmit_can(unsigned long currentMillis) {
} }
void Mg5Battery::setup(void) { // Performs one time setup at startup void Mg5Battery::setup(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, "MG 5 battery", 63); strncpy(datalayer.system.info.battery_protocol, Name, 63);
datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.info.battery_protocol[63] = '\0';
datalayer.system.status.battery_allows_contactor_closing = true; datalayer.system.status.battery_allows_contactor_closing = true;
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;

View file

@ -1,10 +1,11 @@
#include "MG-HS-PHEV-BATTERY.h" #include "MG-HS-PHEV-BATTERY.h"
#include <cmath> //For unit test
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../communication/contactorcontrol/comm_contactorcontrol.h" #include "../communication/contactorcontrol/comm_contactorcontrol.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "../devboard/utils/logging.h" #include "../devboard/utils/logging.h"
/* /*
MG HS PHEV 16.6kWh battery integration MG HS PHEV 16.6kWh battery integration

View file

@ -1,13 +1,13 @@
#include "NISSAN-LEAF-BATTERY.h" #include "NISSAN-LEAF-BATTERY.h"
#include <cstring> //For unit test
#include "../charger/CHARGERS.h"
#include "../charger/CanCharger.h"
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage #include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "../devboard/utils/logging.h" #include "../devboard/utils/logging.h"
#include "../charger/CHARGERS.h"
#include "../charger/CanCharger.h"
uint16_t Temp_fromRAW_to_F(uint16_t temperature); uint16_t Temp_fromRAW_to_F(uint16_t temperature);
//Cryptographic functions //Cryptographic functions
void decodeChallengeData(unsigned int SeedInput, unsigned char* Crypt_Output_Buffer); void decodeChallengeData(unsigned int SeedInput, unsigned char* Crypt_Output_Buffer);

View file

@ -1,8 +1,8 @@
#include "RANGE-ROVER-PHEV-BATTERY.h" #include "RANGE-ROVER-PHEV-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
/* TODO /* TODO
- LOG files from vehicle needed to determine CAN content needed to send towards battery! - LOG files from vehicle needed to determine CAN content needed to send towards battery!
- BCCM_PMZ_A (0x18B 50ms) - BCCM_PMZ_A (0x18B 50ms)

View file

@ -1,5 +1,6 @@
#include "RENAULT-TWIZY.h" #include "RENAULT-TWIZY.h"
#include <cstdint> #include <cstdint>
#include <cstring> //For unit test
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"

View file

@ -1,10 +1,9 @@
#include "RENAULT-ZOE-GEN1-BATTERY.h" #include "RENAULT-ZOE-GEN1-BATTERY.h"
#include <cstring> //For unit test
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.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 /* 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 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 The Zoe BMS apparently does not send total pack voltage, so we use the polled 96x cellvoltages summed up as total voltage

View file

@ -1,8 +1,8 @@
#include "SANTA-FE-PHEV-BATTERY.h" #include "SANTA-FE-PHEV-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
/* Credits go to maciek16c for these findings! /* Credits go to maciek16c for these findings!
https://github.com/maciek16c/hyundai-santa-fe-phev-battery https://github.com/maciek16c/hyundai-santa-fe-phev-battery
https://openinverter.org/forum/viewtopic.php?p=62256 https://openinverter.org/forum/viewtopic.php?p=62256

View file

@ -1,8 +1,8 @@
#include "SIMPBMS-BATTERY.h" #include "SIMPBMS-BATTERY.h"
#include <cstring> //For unit test
#include "../battery/BATTERIES.h" #include "../battery/BATTERIES.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
void SimpBmsBattery::update_values() { void SimpBmsBattery::update_values() {
datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00 datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00

View file

@ -1,4 +1,5 @@
#include "SONO-BATTERY.h" #include "SONO-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"

View file

@ -1,4 +1,5 @@
#include "TESLA-BATTERY.h" #include "TESLA-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" //For Advanced Battery Insights webpage #include "../datalayer/datalayer_extended.h" //For Advanced Battery Insights webpage
@ -995,52 +996,52 @@ void TeslaBattery::
} }
printFaultCodesIfActive(); printFaultCodesIfActive();
logging.print("BMS Contactors State: "); logging.printf("BMS Contactors State: ");
logging.print(getBMSContactorState(battery_contactor)); // Display what state the BMS thinks the contactors are in logging.printf(getBMSContactorState(battery_contactor)); // Display what state the BMS thinks the contactors are in
logging.print(", HVIL: "); logging.printf(", HVIL: ");
logging.print(getHvilStatusState(battery_hvil_status)); logging.printf(getHvilStatusState(battery_hvil_status));
logging.print(", NegativeState: "); logging.printf(", NegativeState: ");
logging.print(getContactorState(battery_packContNegativeState)); logging.printf(getContactorState(battery_packContNegativeState));
logging.print(", PositiveState: "); logging.printf(", PositiveState: ");
logging.println(getContactorState(battery_packContPositiveState)); logging.println(getContactorState(battery_packContPositiveState));
logging.print("HVP Contactors setState: "); logging.printf("HVP Contactors setState: ");
logging.print( logging.printf(
getContactorText(battery_packContactorSetState)); // Display what state the HVP has set the contactors to be in getContactorText(battery_packContactorSetState)); // Display what state the HVP has set the contactors to be in
logging.print(", Closing blocked: "); logging.printf(", Closing blocked: ");
logging.print(getNoYes(battery_packCtrsClosingBlocked)); logging.printf(getNoYes(battery_packCtrsClosingBlocked));
if (battery_packContactorSetState == 5) { if (battery_packContactorSetState == 5) {
logging.print(" (already CLOSED)"); logging.printf(" (already CLOSED)");
} }
logging.print(", Pyrotest: "); logging.printf(", Pyrotest: ");
logging.println(getNoYes(battery_pyroTestInProgress)); logging.println(getNoYes(battery_pyroTestInProgress));
logging.print("Battery values: "); logging.printf("Battery values: ");
logging.print("Real SOC: "); logging.printf("Real SOC: ");
logging.print(battery_soc_ui / 10.0, 1); logging.print(battery_soc_ui / 10.0, 1);
logging.print(", Battery voltage: "); logging.printf(", Battery voltage: ");
logging.print(battery_volts / 10.0, 1); logging.print(battery_volts / 10.0, 1);
logging.print("V"); logging.printf("V");
logging.print(", Battery HV current: "); logging.printf(", Battery HV current: ");
logging.print(battery_amps / 10.0, 1); logging.print(battery_amps / 10.0, 1);
logging.print("A"); logging.printf("A");
logging.print(", Fully charged?: "); logging.printf(", Fully charged?: ");
if (battery_full_charge_complete) if (battery_full_charge_complete)
logging.print("YES, "); logging.printf("YES, ");
else else
logging.print("NO, "); logging.printf("NO, ");
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
logging.print("LFP chemistry detected!"); logging.printf("LFP chemistry detected!");
} }
logging.println(""); logging.println("");
logging.print("Cellstats, Max: "); logging.printf("Cellstats, Max: ");
logging.print(battery_cell_max_v); logging.print(battery_cell_max_v);
logging.print("mV (cell "); logging.printf("mV (cell ");
logging.print(battery_BrickVoltageMaxNum); logging.print(battery_BrickVoltageMaxNum);
logging.print("), Min: "); logging.printf("), Min: ");
logging.print(battery_cell_min_v); logging.print(battery_cell_min_v);
logging.print("mV (cell "); logging.printf("mV (cell ");
logging.print(battery_BrickVoltageMinNum); logging.print(battery_BrickVoltageMinNum);
logging.print("), Imbalance: "); logging.printf("), Imbalance: ");
logging.print(battery_cell_deviation_mV); logging.print(battery_cell_deviation_mV);
logging.println("mV."); logging.println("mV.");

View file

@ -3,12 +3,6 @@
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/logging.h" #include "../devboard/utils/logging.h"
static void print_units(const char* header, int value, const char* units) {
logging.print(header);
logging.print(value);
logging.print(units);
}
void TestFakeBattery:: void TestFakeBattery::
update_values() { /* This function puts fake values onto the parameters sent towards the inverter */ update_values() { /* This function puts fake values onto the parameters sent towards the inverter */

View file

@ -1,10 +1,10 @@
#include "VOLVO-SPA-BATTERY.h" #include "VOLVO-SPA-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage #include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "../devboard/utils/logging.h" #include "../devboard/utils/logging.h"
void VolvoSpaBattery:: void VolvoSpaBattery::
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter

View file

@ -1,10 +1,10 @@
#include "VOLVO-SPA-HYBRID-BATTERY.h" #include "VOLVO-SPA-HYBRID-BATTERY.h"
#include <cstring> //For unit test
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage #include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "../devboard/utils/logging.h" #include "../devboard/utils/logging.h"
void VolvoSpaHybridBattery:: void VolvoSpaHybridBattery::
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter
uint8_t cnt = 0; uint8_t cnt = 0;

View file

@ -8,7 +8,6 @@
#ifndef UNIT_TEST #ifndef UNIT_TEST
// Real implementation for production // Real implementation for production
#include <Print.h>
class Logging : public Print { class Logging : public Print {
void add_timestamp(size_t size); void add_timestamp(size_t size);
@ -51,12 +50,61 @@ class Logging {
(void)fmt; (void)fmt;
} }
// Overloaded print methods for different data types
static void print(const char* str) { (void)str; }
static void print(char c) { (void)c; }
static void print(int8_t num) { (void)num; }
static void print(uint8_t num) { (void)num; }
static void print(int16_t num) { (void)num; }
static void print(uint16_t num) { (void)num; }
static void print(int32_t num) { (void)num; }
static void print(uint32_t num) { (void)num; }
static void print(int64_t num) { (void)num; }
static void print(uint64_t num) { (void)num; }
static void print(float num) { (void)num; }
static void print(double num) { (void)num; }
static void print(bool b) { (void)b; }
static void print(double num, int precision) {
(void)num;
(void)precision;
}
static void print(float num, int precision) {
(void)num;
(void)precision;
}
static void print(int32_t num, int base) {
(void)num;
(void)base;
}
static void print(uint32_t num, int base) {
(void)num;
(void)base;
}
static void println(const char* str) { (void)str; } static void println(const char* str) { (void)str; }
static void println(char c) { (void)c; }
static void println(int8_t num) { (void)num; }
static void println(uint8_t num) { (void)num; }
static void println(int16_t num) { (void)num; }
static void println(uint16_t num) { (void)num; }
static void println(int32_t num) { (void)num; }
static void println(uint32_t num) { (void)num; }
static void println(int64_t num) { (void)num; }
static void println(uint64_t num) { (void)num; }
static void println(float num) { (void)num; }
static void println(double num) { (void)num; }
static void println(bool b) { (void)b; }
static void println() {} // Empty println
Logging() {} Logging() {}
}; };
// Test macros - empty implementations // Test macros - empty implementations
#define DEBUG_PRINT(fmt, ...) ((void)0)
#define DEBUG_PRINTF(fmt, ...) ((void)0) #define DEBUG_PRINTF(fmt, ...) ((void)0)
#define DEBUG_PRINTLN(str) ((void)0) #define DEBUG_PRINTLN(str) ((void)0)

View file

@ -14,18 +14,18 @@ void KostalInverterProtocol::float2frame(uint8_t* arr, float value, uint8_t fram
} }
static void dbg_timestamp(void) { static void dbg_timestamp(void) {
logging.print("["); logging.printf("[");
logging.print(millis()); logging.print(millis());
logging.print(" ms] "); logging.printf(" ms] ");
} }
static void dbg_frame(uint8_t* frame, int len, const char* prefix) { static void dbg_frame(uint8_t* frame, int len, const char* prefix) {
dbg_timestamp(); dbg_timestamp();
logging.print(prefix); logging.print(prefix);
logging.print(": "); logging.printf(": ");
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
if (frame[i] < 0x10) { if (frame[i] < 0x10) {
logging.print("0"); logging.printf("0");
} }
logging.print(frame[i], HEX); logging.print(frame[i], HEX);
logging.print(" "); logging.print(" ");

View file

@ -20,7 +20,6 @@ class KostalInverterProtocol : public Rs485InverterProtocol {
int baud_rate() { return 57600; } int baud_rate() { return 57600; }
void float2frame(uint8_t* arr, float value, uint8_t framepointer); void float2frame(uint8_t* arr, float value, uint8_t framepointer);
bool check_kostal_frame_crc(int len); bool check_kostal_frame_crc(int len);
// How many value updates we can go without inverter gets reported as missing \ // How many value updates we can go without inverter gets reported as missing \
// e.g. value set to 12, 12*5sec=60seconds without comm before event is raised // e.g. value set to 12, 12*5sec=60seconds without comm before event is raised
const int RS485_HEALTHY = 12; const int RS485_HEALTHY = 12;

View file

@ -137,17 +137,6 @@ void SmaTripowerInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
} }
} }
void SmaTripowerInverter::pushFrame(CAN_frame* frame, std::function<void(void)> callback) {
if (listLength >= 20) {
return; //TODO: scream.
}
framesToSend[listLength] = {
.frame = frame,
.callback = callback,
};
listLength++;
}
void SmaTripowerInverter::transmit_can(unsigned long currentMillis) { void SmaTripowerInverter::transmit_can(unsigned long currentMillis) {
// Send CAN Message only if we're enabled by inverter // Send CAN Message only if we're enabled by inverter
@ -155,18 +144,6 @@ void SmaTripowerInverter::transmit_can(unsigned long currentMillis) {
return; return;
} }
if (listLength > 0 && currentMillis - previousMillis250ms >= INTERVAL_250_MS) {
previousMillis250ms = currentMillis;
// Send next frame.
Frame frame = framesToSend[0];
transmit_can_frame(frame.frame);
frame.callback();
for (int i = 0; i < listLength - 1; i++) {
framesToSend[i] = framesToSend[i + 1];
}
listLength--;
}
if (!pairing_completed) { if (!pairing_completed) {
return; return;
} }
@ -174,19 +151,19 @@ void SmaTripowerInverter::transmit_can(unsigned long currentMillis) {
// Send CAN Message every 2s // Send CAN Message every 2s
if (currentMillis - previousMillis2s >= INTERVAL_2_S) { if (currentMillis - previousMillis2s >= INTERVAL_2_S) {
previousMillis2s = currentMillis; previousMillis2s = currentMillis;
pushFrame(&SMA_358); transmit_can_frame(&SMA_358);
} }
// Send CAN Message every 10s // Send CAN Message every 10s
if (currentMillis - previousMillis10s >= INTERVAL_10_S) { if (currentMillis - previousMillis10s >= INTERVAL_10_S) {
previousMillis10s = currentMillis; previousMillis10s = currentMillis;
pushFrame(&SMA_518); transmit_can_frame(&SMA_518);
pushFrame(&SMA_4D8); transmit_can_frame(&SMA_4D8);
pushFrame(&SMA_3D8); transmit_can_frame(&SMA_3D8);
} }
// Send CAN Message every 60s (potentially SMA_458 is not required for stable operation) // Send CAN Message every 60s (potentially SMA_458 is not required for stable operation)
if (currentMillis - previousMillis60s >= INTERVAL_60_S) { if (currentMillis - previousMillis60s >= INTERVAL_60_S) {
previousMillis60s = currentMillis; previousMillis60s = currentMillis;
pushFrame(&SMA_458); transmit_can_frame(&SMA_458);
} }
} }
@ -195,18 +172,17 @@ void SmaTripowerInverter::completePairing() {
} }
void SmaTripowerInverter::transmit_can_init() { void SmaTripowerInverter::transmit_can_init() {
listLength = 0; // clear all frames
pushFrame(&SMA_558); //Pairing start - Vendor transmit_can_frame(&SMA_558); //Pairing start - Vendor
pushFrame(&SMA_598); //Serial transmit_can_frame(&SMA_598); //Serial
pushFrame(&SMA_5D8); //BYD transmit_can_frame(&SMA_5D8); //BYD
pushFrame(&SMA_618_0); //BATTERY transmit_can_frame(&SMA_618_0); //BATTERY
pushFrame(&SMA_618_1); //-Box Pr transmit_can_frame(&SMA_618_1); //-Box Pr
pushFrame(&SMA_618_2); //emium H transmit_can_frame(&SMA_618_2); //emium H
pushFrame(&SMA_618_3); //VS transmit_can_frame(&SMA_618_3); //VS
pushFrame(&SMA_358); transmit_can_frame(&SMA_358);
pushFrame(&SMA_3D8); transmit_can_frame(&SMA_3D8);
pushFrame(&SMA_458); transmit_can_frame(&SMA_458);
pushFrame(&SMA_4D8); transmit_can_frame(&SMA_4D8);
pushFrame(&SMA_518, [this]() { this->completePairing(); }); transmit_can_frame(&SMA_518);
} }

View file

@ -24,7 +24,6 @@ class SmaTripowerInverter : public SmaInverterBase {
const int THIRTY_MINUTES = 1200; const int THIRTY_MINUTES = 1200;
void transmit_can_init(); void transmit_can_init();
void pushFrame(CAN_frame* frame, std::function<void(void)> callback = []() {});
void completePairing(); void completePairing();
unsigned long previousMillis250ms = 0; // will store last time a 250ms CAN Message was send unsigned long previousMillis250ms = 0; // will store last time a 250ms CAN Message was send
@ -33,14 +32,6 @@ class SmaTripowerInverter : public SmaInverterBase {
unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send
unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send
typedef struct {
CAN_frame* frame;
std::function<void(void)> callback;
} Frame;
unsigned short listLength = 0;
Frame framesToSend[20];
uint32_t inverter_time = 0; uint32_t inverter_time = 0;
uint16_t inverter_voltage = 0; uint16_t inverter_voltage = 0;
int16_t inverter_current = 0; int16_t inverter_current = 0;

View file

@ -292,9 +292,8 @@ bool SofarInverter::setup() { // Performs one time setup at startup over CAN bu
init_frame(SOFAR_783, 0x783); init_frame(SOFAR_783, 0x783);
init_frame(SOFAR_784, 0x784); init_frame(SOFAR_784, 0x784);
String tempStr(datalayer.battery.settings.sofar_user_specified_battery_id); snprintf(datalayer.system.info.inverter_brand, sizeof(datalayer.system.info.inverter_brand), "%s",
strncpy(datalayer.system.info.inverter_brand, tempStr.c_str(), 7); datalayer.battery.settings.sofar_user_specified_battery_id);
datalayer.system.info.inverter_brand[7] = '\0';
return true; return true;
} }

View file

@ -85,11 +85,80 @@ add_executable(tests
../Software/USER_SETTINGS.cpp ../Software/USER_SETTINGS.cpp
../Software/src/battery/BATTERIES.cpp ../Software/src/battery/BATTERIES.cpp
../Software/src/battery/Battery.cpp ../Software/src/battery/Battery.cpp
../Software/src/battery/BMW-I3-BATTERY.cpp
../Software/src/battery/BMW-I3-HTML.cpp
../Software/src/battery/BMW-IX-BATTERY.cpp
../Software/src/battery/BMW-IX-HTML.cpp
../Software/src/battery/BMW-PHEV-BATTERY.cpp
../Software/src/battery/BMW-SBOX.cpp
../Software/src/battery/BOLT-AMPERA-BATTERY.cpp
../Software/src/battery/BYD-ATTO-3-BATTERY.cpp
../Software/src/battery/CanBattery.cpp ../Software/src/battery/CanBattery.cpp
../Software/src/battery/CELLPOWER-BMS.cpp
../Software/src/battery/CHADEMO-BATTERY.cpp
../Software/src/battery/CHADEMO-SHUNTS.cpp
../Software/src/battery/CMFA-EV-BATTERY.cpp
../Software/src/battery/DALY-BMS.cpp
../Software/src/battery/ECMP-BATTERY.cpp
../Software/src/battery/FOXESS-BATTERY.cpp
../Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp
../Software/src/battery/HYUNDAI-IONIQ-28-BATTERY-HTML.cpp
../Software/src/battery/HYUNDAI-IONIQ-28-BATTERY.cpp
../Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp
../Software/src/battery/JAGUAR-IPACE-BATTERY.cpp
../Software/src/battery/KIA-E-GMP-BATTERY.cpp
../Software/src/battery/KIA-E-GMP-HTML.cpp
../Software/src/battery/KIA-64FD-BATTERY.cpp
../Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp
../Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp
../Software/src/battery/MEB-BATTERY.cpp
../Software/src/battery/MG-5-BATTERY.cpp
../Software/src/battery/MG-HS-PHEV-BATTERY.cpp
../Software/src/battery/NISSAN-LEAF-BATTERY.cpp ../Software/src/battery/NISSAN-LEAF-BATTERY.cpp
../Software/src/inverter/INVERTERS.cpp ../Software/src/battery/ORION-BMS.cpp
../Software/src/battery/PYLON-BATTERY.cpp
../Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp
../Software/src/battery/RELION-LV-BATTERY.cpp
../Software/src/battery/RENAULT-KANGOO-BATTERY.cpp
../Software/src/battery/RENAULT-TWIZY.cpp
../Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp
../Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp
../Software/src/battery/RJXZS-BMS.cpp
../Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp
../Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp
../Software/src/battery/Shunts.cpp
../Software/src/battery/SIMPBMS-BATTERY.cpp
../Software/src/battery/SONO-BATTERY.cpp
../Software/src/battery/TESLA-BATTERY.cpp
../Software/src/battery/TEST-FAKE-BATTERY.cpp
../Software/src/battery/VOLVO-SPA-BATTERY.cpp
../Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp
../Software/src/inverter/AFORE-CAN.cpp
../Software/src/inverter/BYD-CAN.cpp
../Software/src/inverter/BYD-MODBUS.cpp ../Software/src/inverter/BYD-MODBUS.cpp
../Software/src/inverter/FERROAMP-CAN.cpp
../Software/src/inverter/FOXESS-CAN.cpp
../Software/src/inverter/GROWATT-HV-CAN.cpp
../Software/src/inverter/GROWATT-LV-CAN.cpp
../Software/src/inverter/GROWATT-WIT-CAN.cpp
../Software/src/inverter/INVERTERS.cpp
../Software/src/inverter/KOSTAL-RS485.cpp
../Software/src/inverter/ModbusInverterProtocol.cpp
../Software/src/inverter/PYLON-CAN.cpp
../Software/src/inverter/PYLON-LV-CAN.cpp
../Software/src/inverter/SCHNEIDER-CAN.cpp
../Software/src/inverter/SMA-BYD-H-CAN.cpp
../Software/src/inverter/SMA-BYD-HVS-CAN.cpp
../Software/src/inverter/SMA-LV-CAN.cpp
../Software/src/inverter/SMA-TRIPOWER-CAN.cpp
../Software/src/inverter/SOFAR-CAN.cpp
../Software/src/inverter/SOL-ARK-LV-CAN.cpp
../Software/src/inverter/SOLAX-CAN.cpp
../Software/src/inverter/SOLXPOW-CAN.cpp
../Software/src/inverter/SUNGROW-CAN.cpp
../Software/src/charger/CHARGERS.cpp ../Software/src/charger/CHARGERS.cpp
../Software/src/charger/CHEVY-VOLT-CHARGER.cpp
../Software/src/charger/NISSAN-LEAF-CHARGER.cpp
emul/can.cpp emul/can.cpp
emul/time.cpp emul/time.cpp
emul/serial.cpp emul/serial.cpp

View file

@ -15,4 +15,22 @@ int max(int a, int b) {
return (a > b) ? a : b; return (a > b) ? a : b;
} }
// Mock implementation for OBD
#include "../../Software/src/communication/can/obd.h"
void handle_obd_frame(CAN_frame& frame) {
(void)frame;
}
void transmit_obd_can_frame(unsigned int address, int interface, bool canFD) {
(void)interface;
}
void start_bms_reset() {}
#include "../../Software/src/communication/rs485/comm_rs485.h"
// Mock implementation
void register_receiver(Rs485Receiver* receiver) {
(void)receiver; // Silence unused parameter warning
}
ESPClass ESP; ESPClass ESP;

View file

@ -6,15 +6,97 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "HardwareSerial.h" #include "HardwareSerial.h"
#include "Logging.h" #include "Logging.h"
#include "Print.h" #include "Print.h"
#include "esp-hal-gpio.h" #include "esp-hal-gpio.h"
// Arduino base constants for print formatting
constexpr int BIN = 2;
constexpr int OCT = 8;
constexpr int DEC = 10;
constexpr int HEX = 16;
// Arduino type aliases
using byte = uint8_t;
#define boolean bool
// Arduino random functions
inline long random(long max) {
(void)max;
return 0; // Return a predictable value for testing
}
inline long random(long min, long max) {
(void)min;
(void)max;
return min; // Return the minimum value for predictability
}
// Also add randomSeed for completeness
inline void randomSeed(unsigned long seed) {
(void)seed;
}
inline uint16_t word(uint8_t highByte, uint8_t lowByte) {
return (static_cast<uint16_t>(highByte) << 8) | lowByte;
}
inline uint16_t word(uint16_t w) {
return w;
}
// Bit manipulation functions
inline uint8_t bitRead(uint8_t value, uint8_t bit) {
return (value >> bit) & 0x01;
}
inline void bitSet(uint8_t& value, uint8_t bit) {
value |= (1UL << bit);
}
inline void bitClear(uint8_t& value, uint8_t bit) {
value &= ~(1UL << bit);
}
inline void bitWrite(uint8_t& value, uint8_t bit, uint8_t bitvalue) {
if (bitvalue) {
bitSet(value, bit);
} else {
bitClear(value, bit);
}
}
// Byte extraction functions
inline uint8_t lowByte(uint16_t w) {
return static_cast<uint8_t>(w & 0xFF);
}
inline uint8_t highByte(uint16_t w) {
return static_cast<uint8_t>(w >> 8);
}
template <typename T>
inline const T& min(const T& a, const T& b) {
return (a < b) ? a : b;
}
template <typename T>
inline const T& max(const T& a, const T& b) {
return (a > b) ? a : b;
}
void pinMode(uint8_t pin, uint8_t mode); void pinMode(uint8_t pin, uint8_t mode);
void digitalWrite(uint8_t pin, uint8_t val); void digitalWrite(uint8_t pin, uint8_t val);
int digitalRead(uint8_t pin); int digitalRead(uint8_t pin);
inline int analogRead(uint8_t pin) {
(void)pin;
return 0; // Return 0 for predictable tests
}
unsigned long micros(); unsigned long micros();
// Can be previously declared as a macro in stupid eModbus // Can be previously declared as a macro in stupid eModbus

View file

@ -35,17 +35,28 @@ enum SerialConfig {
class HardwareSerial : public Stream { class HardwareSerial : public Stream {
public: public:
int available() { return 0; } // Implement ALL pure virtual functions from base classes
int available() override { return 0; }
int read() override { return -1; }
int peek() override { return -1; }
void flush() override {} // Implement flush from Print
size_t write(uint8_t) override { return 0; } // Implement write from Print
// Your existing methods
uint32_t baudRate() { return 9600; } uint32_t baudRate() { return 9600; }
void begin(unsigned long baud, uint32_t config = SERIAL_8N1, int8_t rxPin = -1, int8_t txPin = -1, void begin(unsigned long baud, uint32_t config = SERIAL_8N1, int8_t rxPin = -1, int8_t txPin = -1,
bool invert = false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 120) {} bool invert = false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 120) {}
int read() { return 0; }
void setTxBufferSize(uint16_t size) {} void setTxBufferSize(uint16_t size) {}
void setRxBufferSize(uint16_t size) {} void setRxBufferSize(uint16_t size) {}
bool setRxFIFOFull(uint8_t fifoBytes) { return false; } bool setRxFIFOFull(uint8_t fifoBytes) { return false; }
size_t write(uint8_t) { return 0; }
};
// Add the buffer write method
size_t write(const uint8_t* buffer, size_t size) override {
(void)buffer;
(void)size;
return 0;
}
};
extern HardwareSerial Serial; extern HardwareSerial Serial;
extern HardwareSerial Serial1; extern HardwareSerial Serial1;
extern HardwareSerial Serial2; extern HardwareSerial Serial2;

View file

@ -5,7 +5,7 @@ class Print {
public: public:
virtual void flush() {} virtual void flush() {}
void printf(const char* format, ...) {} void printf(const char* format, ...) {}
virtual size_t write(uint8_t) = 0; virtual size_t write(uint8_t) { return 0; }
virtual size_t write(const char* s) { return 0; } virtual size_t write(const char* s) { return 0; }
virtual size_t write(const uint8_t* buffer, size_t size) { return 0; } virtual size_t write(const uint8_t* buffer, size_t size) { return 0; }
}; };

View file

@ -5,8 +5,10 @@
class Stream : public Print { class Stream : public Print {
public: public:
virtual int available() = 0; virtual int available() { return 0; }
virtual int read() = 0; virtual int read() { return -1; }
virtual int peek() { return -1; }
// flush() is already inherited from Print
}; };
#endif #endif