Merge pull request #1378 from jonny5532/feature/modbus-inverter-ram-usage

Make Modbus inverters allocate their own register memory as required
This commit is contained in:
Daniel Öster 2025-08-15 20:30:36 +03:00 committed by GitHub
commit 73834cceeb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 307 additions and 237 deletions

View file

@ -2,22 +2,9 @@
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/hal/hal.h" #include "../devboard/hal/hal.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "../lib/eModbus-eModbus/RTUutils.h"
#include "../lib/eModbus-eModbus/scripts/mbServerFCs.h"
// For modbus register definitions, see https://gitlab.com/pelle8/inverter_resources/-/blob/main/byd_registers_modbus_rtu.md // For modbus register definitions, see https://gitlab.com/pelle8/inverter_resources/-/blob/main/byd_registers_modbus_rtu.md
#define HISTORY_LENGTH 3 // Amount of samples(minutes) that needs to match for register to be considered stale
static unsigned long previousMillis60s = 0; // will store last time a 60s event occured
static uint32_t user_configured_max_discharge_W = 0;
static uint32_t user_configured_max_charge_W = 0;
static uint32_t max_discharge_W = 0;
static uint32_t max_charge_W = 0;
static uint16_t register_401_history[HISTORY_LENGTH] = {0};
static uint8_t history_index = 0;
static uint8_t bms_char_dis_status = STANDBY;
static bool all_401_values_equal = false;
void BydModbusInverter::update_values() { void BydModbusInverter::update_values() {
verify_temperature(); verify_temperature();
verify_inverter_modbus(); verify_inverter_modbus();
@ -41,14 +28,20 @@ void BydModbusInverter::handle_static_data() {
static uint16_t i = 100; static uint16_t i = 100;
for (uint8_t arr_idx = 0; arr_idx < sizeof(data_array_pointers) / sizeof(uint16_t*); arr_idx++) { for (uint8_t arr_idx = 0; arr_idx < sizeof(data_array_pointers) / sizeof(uint16_t*); arr_idx++) {
uint16_t data_size = data_sizes[arr_idx]; uint16_t data_size = data_sizes[arr_idx];
memcpy(&mbPV[i], data_array_pointers[arr_idx], data_size); for (int j = 0; j < data_size / sizeof(uint16_t); j++) {
mbPV[i + j] = data_array_pointers[arr_idx][j];
}
i += data_size / sizeof(uint16_t); i += data_size / sizeof(uint16_t);
} }
static uint16_t init_p201[13] = {0, 0, 0, MAX_POWER, MAX_POWER, 0, 0, 53248, 10, 53248, 10, 0, 0}; static uint16_t init_p201[13] = {0, 0, 0, MAX_POWER, MAX_POWER, 0, 0, 53248, 10, 53248, 10, 0, 0};
memcpy(&mbPV[200], init_p201, sizeof(init_p201)); for (int i = 0; i < sizeof(init_p201) / sizeof(uint16_t); i++) {
mbPV[200 + i] = init_p201[i];
}
static uint16_t init_p301[24] = {0, 0, 128, 0, 0, 0, 0, 0, 0, 2000, 0, 2000, static uint16_t init_p301[24] = {0, 0, 128, 0, 0, 0, 0, 0, 0, 2000, 0, 2000,
75, 95, 0, 0, 16, 22741, 0, 0, 13, 52064, 230, 9900}; 75, 95, 0, 0, 16, 22741, 0, 0, 13, 52064, 230, 9900};
memcpy(&mbPV[300], init_p301, sizeof(init_p301)); for (int i = 0; i < sizeof(init_p301) / sizeof(uint16_t); i++) {
mbPV[300 + i] = init_p301[i];
}
} }
void BydModbusInverter::handle_update_data_modbusp201_byd() { void BydModbusInverter::handle_update_data_modbusp201_byd() {
@ -150,10 +143,8 @@ bool BydModbusInverter::setup(void) { // Performs one time setup at startup ove
// Init Static data to the RTU Modbus // Init Static data to the RTU Modbus
handle_static_data(); handle_static_data();
#if HAS_FREERTOS
// Init Serial2 connected to the RTU Modbus // Init Serial2 connected to the RTU Modbus
RTUutils::prepareHardwareSerial(Serial2); RTUutils::prepareHardwareSerial(Serial2);
#endif
auto rx_pin = esp32hal->RS485_RX_PIN(); auto rx_pin = esp32hal->RS485_RX_PIN();
auto tx_pin = esp32hal->RS485_TX_PIN(); auto tx_pin = esp32hal->RS485_TX_PIN();
@ -163,16 +154,9 @@ bool BydModbusInverter::setup(void) { // Performs one time setup at startup ove
} }
Serial2.begin(9600, SERIAL_8N1, rx_pin, tx_pin); Serial2.begin(9600, SERIAL_8N1, rx_pin, tx_pin);
#if HAS_FREERTOS
// Register served function code worker for server
MBserver->registerWorker(MBTCP_ID, READ_HOLD_REGISTER, &FC03);
MBserver->registerWorker(MBTCP_ID, WRITE_HOLD_REGISTER, &FC06);
MBserver->registerWorker(MBTCP_ID, WRITE_MULT_REGISTERS, &FC16);
MBserver->registerWorker(MBTCP_ID, R_W_MULT_REGISTERS, &FC23);
// Start ModbusRTU background task // Start ModbusRTU background task
((ModbusServerRTU*)MBserver)->begin(Serial2, esp32hal->MODBUS_CORE()); MBserver.begin(Serial2, esp32hal->MODBUS_CORE());
#endif
return true; return true;
} }

View file

@ -5,10 +5,12 @@
#define SELECTED_INVERTER_CLASS BydModbusInverter #define SELECTED_INVERTER_CLASS BydModbusInverter
#endif #endif
#include "../devboard/utils/types.h"
#include "ModbusInverterProtocol.h" #include "ModbusInverterProtocol.h"
class BydModbusInverter : public ModbusInverterProtocol { class BydModbusInverter : public ModbusInverterProtocol {
public: public:
BydModbusInverter() : ModbusInverterProtocol(21) {}
const char* name() override { return Name; } const char* name() override { return Name; }
bool setup() override; bool setup() override;
void update_values(); void update_values();
@ -23,6 +25,18 @@ class BydModbusInverter : public ModbusInverterProtocol {
//BYD Modbus specific value //BYD Modbus specific value
const uint16_t MAX_POWER = 40960; const uint16_t MAX_POWER = 40960;
static const int HISTORY_LENGTH =
3; // Amount of samples(minutes) that needs to match for register to be considered stale
unsigned long previousMillis60s = 0; // will store last time a 60s event occured
uint32_t user_configured_max_discharge_W = 0;
uint32_t user_configured_max_charge_W = 0;
uint32_t max_discharge_W = 0;
uint32_t max_charge_W = 0;
uint16_t register_401_history[HISTORY_LENGTH] = {0};
uint8_t history_index = 0;
uint8_t bms_char_dis_status = STANDBY;
bool all_401_values_equal = false;
}; };
#endif #endif

View file

@ -1,10 +1,181 @@
#include "ModbusInverterProtocol.h" #include "ModbusInverterProtocol.h"
#include "../devboard/utils/logging.h"
#include "../lib/eModbus-eModbus/ModbusServerRTU.h" #include "../lib/eModbus-eModbus/ModbusServerRTU.h"
static const int MB_RTU_NUM_VALUES = 13100; // Creates a ModbusRTU server instance with 2000ms timeout
uint16_t mbPV[MB_RTU_NUM_VALUES]; // Process variable memory ModbusInverterProtocol::ModbusInverterProtocol(int serverId) : MBserver(2000) {
_serverId = serverId;
ModbusInverterProtocol::ModbusInverterProtocol() { MBserver.registerWorker(_serverId, READ_HOLD_REGISTER,
mbPV = ::mbPV; [this](ModbusMessage request) -> ModbusMessage { return FC03(request); });
MBserver = new ModbusServerRTU(2000); MBserver.registerWorker(_serverId, WRITE_HOLD_REGISTER,
[this](ModbusMessage request) -> ModbusMessage { return FC06(request); });
MBserver.registerWorker(_serverId, WRITE_MULT_REGISTERS,
[this](ModbusMessage request) -> ModbusMessage { return FC16(request); });
MBserver.registerWorker(_serverId, R_W_MULT_REGISTERS,
[this](ModbusMessage request) -> ModbusMessage { return FC23(request); });
}
ModbusInverterProtocol::~ModbusInverterProtocol() {
MBserver.unregisterWorker(_serverId, READ_HOLD_REGISTER);
MBserver.unregisterWorker(_serverId, WRITE_HOLD_REGISTER);
MBserver.unregisterWorker(_serverId, WRITE_MULT_REGISTERS);
MBserver.unregisterWorker(_serverId, R_W_MULT_REGISTERS);
}
// Server function to handle FC 0x03
ModbusMessage ModbusInverterProtocol::FC03(ModbusMessage request) {
ModbusMessage response; // The Modbus message we are going to give back
uint16_t addr = 0; // Start address
uint16_t words = 0; // # of words requested
request.get(2, addr); // read address from request
request.get(4, words); // read # of words from request
// Address overflow?
if ((addr + words) > MBPV_MAX) {
// Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
#ifdef DEBUG_LOG
logging.printf("Modbus FC03 error: illegal request addr=%d words=%d\n", addr, words);
#endif
return response;
}
// Set up response
response.add(request.getServerID(), request.getFunctionCode(), (uint8_t)(words * 2));
for (uint8_t i = 0; i < words; ++i) {
// send increasing data values
response.add((uint16_t)(mbPV[addr + i]));
}
// #ifdef DEBUG_LOG
// logging.printf("Modbus FC03 response: %d %d\n", addr, mbPV[addr]);
// #endif
return response;
}
// Server function to handle FC 0x06
ModbusMessage ModbusInverterProtocol::FC06(ModbusMessage request) {
ModbusMessage response; // The Modbus message we are going to give back
uint16_t addr = 0; // Start address
uint16_t val = 0; // value to write
request.get(2, addr); // read address from request
request.get(4, val); // read # of words from request
// Address overflow?
if ((addr) > MBPV_MAX) {
// Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
#ifdef DEBUG_LOG
logging.printf("Modbus FC06 error: illegal request addr=%d val=%d\n", addr, val);
#endif
return response;
}
// Do the write
mbPV[addr] = val;
// Set up response
response.add(request.getServerID(), request.getFunctionCode(), mbPV[addr]);
return response;
}
// Server function to handle FC 0x10 (FC16)
ModbusMessage ModbusInverterProtocol::FC16(ModbusMessage request) {
ModbusMessage response; // The Modbus message we are going to give back
uint16_t addr = 0; // Start address
uint16_t words = 0; // total words to write
uint8_t bytes = 0; // # of data bytes in request
uint16_t val = 0; // value to be written
request.get(2, addr); // read address from request
request.get(4, words); // read # of words from request
request.get(6, bytes); // read # of data bytes from request (seems redundant with # of words)
// # of registers proper?
if ((bytes != (words * 2)) // byte count in request must match # of words in request
|| (words > 123)) // can't support more than this in request packet
{ // Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_VALUE);
#ifdef DEBUG_LOG
logging.printf("Modbus FC16 error: bad registers addr=%d words=%d bytes=%d\n", addr, words, bytes);
#endif
return response;
}
// Address overflow?
if ((addr + words) > MBPV_MAX) {
// Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
#ifdef DEBUG_LOG
logging.printf("Modbus FC16 error: overflow addr=%d words=%d\n", addr, words);
#endif
return response;
}
// Do the writes
for (uint8_t i = 0; i < words; ++i) {
request.get(7 + (i * 2), val); //data starts at byte 6 in request packet
mbPV[addr + i] = val;
}
// Set up response
response.add(request.getServerID(), request.getFunctionCode(), addr, words);
return response;
}
// Server function to handle FC 0x17 (FC23)
ModbusMessage ModbusInverterProtocol::FC23(ModbusMessage request) {
ModbusMessage response; // The Modbus message we are going to give back
uint16_t read_addr = 0; // Start address for read
uint16_t read_words = 0; // # of words requested for read
uint16_t write_addr = 0; // Start address for write
uint16_t write_words = 0; // total words to write
uint8_t write_bytes = 0; // # of data bytes in write request
uint16_t write_val = 0; // value to be written
request.get(2, read_addr); // read address from request
request.get(4, read_words); // read # of words from request
request.get(6, write_addr); // read address from request
request.get(8, write_words); // read # of words from request
request.get(10, write_bytes); // read # of data bytes from request (seems redundant with # of words)
// ERROR CHECKS
// # of registers proper?
if ((write_bytes != (write_words * 2)) // byte count in request must match # of words in request
|| (write_words > 121) // can't fit more than this in the packet for FC23
|| (read_words > 125)) // can't fit more than this in the response packet
{ // Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_VALUE);
#ifdef DEBUG_LOG
logging.printf("Modbus FC23 error: bad registers write_addr=%d write_words=%d write_bytes=%d read_words=%d\n",
write_addr, write_words, write_bytes, read_words);
#endif
return response;
}
// Address overflow?
if (((write_addr + write_words) > MBPV_MAX) ||
((read_addr + read_words) > MBPV_MAX)) { // Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
#ifdef DEBUG_LOG
logging.printf("Modbus FC23 error: overflow write_addr=%d write_words=%d read_addr=%d read_words=%d\n", write_addr,
write_words, read_addr, read_words);
#endif
return response;
}
//WRITE SECTION - write is done before read for FC23
// Do the writes
for (uint8_t i = 0; i < write_words; ++i) {
request.get(11 + (i * 2), write_val); //data starts at byte 6 in request packet
mbPV[write_addr + i] = write_val;
}
// READ SECTION
// Set up response
response.add(request.getServerID(), request.getFunctionCode(), (uint8_t)(read_words * 2));
for (uint8_t i = 0; i < read_words; ++i) {
// send increasing data values
response.add((uint16_t)(mbPV[read_addr + i]));
}
return response;
} }

View file

@ -1,12 +1,14 @@
#ifndef MODBUS_INVERTER_PROTOCOL_H #ifndef MODBUS_INVERTER_PROTOCOL_H
#define MODBUS_INVERTER_PROTOCOL_H #define MODBUS_INVERTER_PROTOCOL_H
#include <HardwareSerial.h> #include "../lib/eModbus-eModbus/ModbusMessage.h"
#include <stdint.h> #include "../lib/eModbus-eModbus/ModbusServerRTU.h"
#include "../lib/eModbus-eModbus/ModbusServer.h"
#include "InverterProtocol.h" #include "InverterProtocol.h"
extern uint16_t mbPV[]; #include <HardwareSerial.h>
#include <stdint.h>
#include <map>
// The abstract base class for all Modbus inverter protocols // The abstract base class for all Modbus inverter protocols
class ModbusInverterProtocol : public InverterProtocol { class ModbusInverterProtocol : public InverterProtocol {
@ -14,15 +16,22 @@ class ModbusInverterProtocol : public InverterProtocol {
InverterInterfaceType interface_type() { return InverterInterfaceType::Modbus; } InverterInterfaceType interface_type() { return InverterInterfaceType::Modbus; }
protected: protected:
// Create a ModbusRTU server instance with 2000ms timeout ModbusInverterProtocol(int serverId);
ModbusInverterProtocol(); ~ModbusInverterProtocol();
static const int MB_RTU_NUM_VALUES = 13100; ModbusMessage FC03(ModbusMessage request);
ModbusMessage FC06(ModbusMessage request);
ModbusMessage FC16(ModbusMessage request);
ModbusMessage FC23(ModbusMessage request);
// Modbus register file // The highest Modbus register we allow reads/writes from
uint16_t* mbPV; static const int MBPV_MAX = 30000;
// The Modbus server ID we respond to
int _serverId;
// The Modbus registers themselves
std::map<uint16_t, uint16_t> mbPV;
ModbusServer* MBserver; ModbusServerRTU MBserver;
}; };
#endif #endif

View file

@ -440,7 +440,7 @@ ModbusMessage RTUutils::receive(uint8_t caller, Stream& serial, uint32_t timeout
} }
// Lower 7 bit ASCII characters - all invalid are set to 0xFF // Lower 7 bit ASCII characters - all invalid are set to 0xFF
const char RTUutils::ASCIIread[] = { const uint8_t RTUutils::ASCIIread[] = {
/* 00-07 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 00-07 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/* 08-0F */ 0xFF, 0xFF, 0xF2, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, // LF + CR /* 08-0F */ 0xFF, 0xFF, 0xF2, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, // LF + CR
/* 10-17 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 10-17 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

View file

@ -60,7 +60,7 @@ static void prepareHardwareSerial(HardwareSerial& s, uint16_t bufferSize = 260)
protected: protected:
// Printable characters for ASCII protocol: 012345678ABCDEF // Printable characters for ASCII protocol: 012345678ABCDEF
static const char ASCIIwrite[]; static const char ASCIIwrite[];
static const char ASCIIread[]; static const uint8_t ASCIIread[];
RTUutils() = delete; RTUutils() = delete;

View file

@ -1 +0,0 @@
The scripts in this folder originate from [eModbus discussion 147](https://github.com/eModbus/eModbus/discussions/147).

View file

@ -1,173 +0,0 @@
#include "mbServerFCs.h"
#include "../Logging.h"
//modbus register memory - declared in main.cpp
extern uint16_t mbPV[MBPV_MAX];
// Server function to handle FC 0x03
ModbusMessage FC03(ModbusMessage request) {
//Serial.println(request);
ModbusMessage response; // The Modbus message we are going to give back
uint16_t addr = 0; // Start address
uint16_t words = 0; // # of words requested
request.get(2, addr); // read address from request
request.get(4, words); // read # of words from request
char debugString[1000];
LOG_D("FC03 received: read %d words @ %d\r\n", words, addr);
// Address overflow?
if ((addr + words) > MBPV_MAX) {
// Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
LOG_D("ERROR - ILLEGAL DATA ADDRESS\r\n");
return response;
}
// Set up response
response.add(request.getServerID(), request.getFunctionCode(), (uint8_t)(words * 2));
sprintf(debugString, "Read : ");
for (uint8_t i = 0; i < words; ++i) {
// send increasing data values
response.add((uint16_t)(mbPV[addr + i]));
sprintf(debugString + strlen(debugString), "%i ", mbPV[addr + i]);
}
LOG_V("%s\r\n", debugString);
return response;
}
// Server function to handle FC 0x06
ModbusMessage FC06(ModbusMessage request) {
//Serial.println(request);
ModbusMessage response; // The Modbus message we are going to give back
uint16_t addr = 0; // Start address
uint16_t val = 0; // value to write
request.get(2, addr); // read address from request
request.get(4, val); // read # of words from request
LOG_D("FC06 received: write 1 word @ %d\r\n", addr);
// Address overflow?
if ((addr) > MBPV_MAX) {
// Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
LOG_D("ERROR - ILLEGAL DATA ADDRESS\r\n");
return response;
}
// Do the write
mbPV[addr] = val;
LOG_V("Write : %i", val);
// Set up response
response.add(request.getServerID(), request.getFunctionCode(), mbPV[addr]);
return response;
}
// Server function to handle FC 0x10 (FC16)
ModbusMessage FC16(ModbusMessage request) {
//Serial.println(request);
ModbusMessage response; // The Modbus message we are going to give back
uint16_t addr = 0; // Start address
uint16_t words = 0; // total words to write
uint8_t bytes = 0; // # of data bytes in request
uint16_t val = 0; // value to be written
request.get(2, addr); // read address from request
request.get(4, words); // read # of words from request
request.get(6, bytes); // read # of data bytes from request (seems redundant with # of words)
char debugString[1000];
LOG_D("FC16 received: write %d words @ %d\r\n", words, addr);
// # of registers proper?
if ((bytes != (words * 2)) // byte count in request must match # of words in request
|| (words > 123)) // can't support more than this in request packet
{ // Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_VALUE);
LOG_D("ERROR - ILLEGAL DATA VALUE\r\n");
return response;
}
// Address overflow?
if ((addr + words) > MBPV_MAX) {
// Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
LOG_D("ERROR - ILLEGAL DATA ADDRESS\r\n");
return response;
}
// Do the writes
sprintf(debugString, "Write : ");
for (uint8_t i = 0; i < words; ++i) {
request.get(7 + (i * 2), val); //data starts at byte 6 in request packet
mbPV[addr + i] = val;
sprintf(debugString + strlen(debugString), "%i ", mbPV[addr + i]);
}
LOG_V("%s\r\n", debugString);
// Set up response
response.add(request.getServerID(), request.getFunctionCode(), addr, words);
return response;
}
// Server function to handle FC 0x17 (FC23)
ModbusMessage FC23(ModbusMessage request) {
//Serial.println(request);
ModbusMessage response; // The Modbus message we are going to give back
uint16_t read_addr = 0; // Start address for read
uint16_t read_words = 0; // # of words requested for read
uint16_t write_addr = 0; // Start address for write
uint16_t write_words = 0; // total words to write
uint8_t write_bytes = 0; // # of data bytes in write request
uint16_t write_val = 0; // value to be written
request.get(2, read_addr); // read address from request
request.get(4, read_words); // read # of words from request
request.get(6, write_addr); // read address from request
request.get(8, write_words); // read # of words from request
request.get(10, write_bytes); // read # of data bytes from request (seems redundant with # of words)
char debugString[1000];
LOG_D("FC23 received: write %d @ %d, read %d @ %d\r\n", write_words, write_addr, read_words, read_addr);
// ERROR CHECKS
// # of registers proper?
if ((write_bytes != (write_words * 2)) // byte count in request must match # of words in request
|| (write_words > 121) // can't fit more than this in the packet for FC23
|| (read_words > 125)) // can't fit more than this in the response packet
{ // Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_VALUE);
LOG_D("ERROR - ILLEGAL DATA VALUE\r\n");
return response;
}
// Address overflow?
if (((write_addr + write_words) > MBPV_MAX) ||
((read_addr + read_words) > MBPV_MAX)) { // Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
LOG_D("ERROR - ILLEGAL DATA ADDRESS\r\n");
return response;
}
//WRITE SECTION - write is done before read for FC23
// Do the writes
sprintf(debugString, "Write: ");
for (uint8_t i = 0; i < write_words; ++i) {
request.get(11 + (i * 2), write_val); //data starts at byte 6 in request packet
mbPV[write_addr + i] = write_val;
sprintf(debugString + strlen(debugString), "%i ", mbPV[write_addr + i]);
}
LOG_V("%s\r\n", debugString);
// READ SECTION
// Set up response
sprintf(debugString, "Read: ");
response.add(request.getServerID(), request.getFunctionCode(), (uint8_t)(read_words * 2));
for (uint8_t i = 0; i < read_words; ++i) {
// send increasing data values
response.add((uint16_t)(mbPV[read_addr + i]));
sprintf(debugString + strlen(debugString), "%i ", mbPV[read_addr + i]);
}
LOG_V("%s\r\n", debugString);
return response;
}

View file

@ -1,9 +0,0 @@
#include "../ModbusServerRTU.h"
#define MBTCP_ID 21 // modbus TCP server ID
#define MBPV_MAX 30000
ModbusMessage FC03(ModbusMessage request);
ModbusMessage FC06(ModbusMessage request);
ModbusMessage FC16(ModbusMessage request);
ModbusMessage FC23(ModbusMessage request);

View file

@ -62,7 +62,7 @@ include_directories("${source_dir}/googletest/include"
include_directories(emul) include_directories(emul)
# For eModBus # For eModBus
add_compile_definitions(__linux__ HW_LILYGO NISSAN_LEAF_BATTERY) add_compile_definitions(ESP32 HW_LILYGO NISSAN_LEAF_BATTERY)
# add the executable # add the executable
add_executable(tests add_executable(tests
@ -74,9 +74,12 @@ add_executable(tests
../Software/src/devboard/utils/events.cpp ../Software/src/devboard/utils/events.cpp
../Software/src/datalayer/datalayer.cpp ../Software/src/datalayer/datalayer.cpp
../Software/src/datalayer/datalayer_extended.cpp ../Software/src/datalayer/datalayer_extended.cpp
../Software/src/lib/eModbus-eModbus/ModbusMessage.cpp
../Software/src/lib/eModbus-eModbus/ModbusTypeDefs.cpp
../Software/src/lib/eModbus-eModbus/Logging.cpp ../Software/src/lib/eModbus-eModbus/Logging.cpp
../Software/src/lib/eModbus-eModbus/ModbusMessage.cpp
../Software/src/lib/eModbus-eModbus/ModbusServer.cpp
../Software/src/lib/eModbus-eModbus/ModbusServerRTU.cpp
../Software/src/lib/eModbus-eModbus/ModbusTypeDefs.cpp
../Software/src/lib/eModbus-eModbus/RTUutils.cpp
# ../Software/src/lib/eModbus-eModbus/scripts/mbServerFCs.cpp # ../Software/src/lib/eModbus-eModbus/scripts/mbServerFCs.cpp
../Software/USER_SETTINGS.cpp ../Software/USER_SETTINGS.cpp
../Software/src/battery/BATTERIES.cpp ../Software/src/battery/BATTERIES.cpp
@ -90,6 +93,7 @@ add_executable(tests
emul/time.cpp emul/time.cpp
emul/serial.cpp emul/serial.cpp
emul/Arduino.cpp emul/Arduino.cpp
emul/freertos/FreeRTOS.cpp
) )
target_link_libraries(tests target_link_libraries(tests

View file

@ -1,5 +1,16 @@
#include "Arduino.h" #include "Arduino.h"
void delay(unsigned long ms) {}
void delayMicroseconds(unsigned long us) {}
int digitalRead(uint8_t pin) {
return 0;
}
void digitalWrite(uint8_t pin, uint8_t val) {}
unsigned long micros() {
return 0;
}
void pinMode(uint8_t pin, uint8_t mode) {}
int max(int a, int b) { int max(int a, int b) {
return (a > b) ? a : b; return (a > b) ? a : b;
} }

View file

@ -1,7 +1,13 @@
#ifndef ARDUINO_H #ifndef ARDUINO_H
#define ARDUINO_H #define ARDUINO_H
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "HardwareSerial.h"
#include "Print.h"
#include "esp-hal-gpio.h" #include "esp-hal-gpio.h"
@ -9,10 +15,13 @@ 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);
unsigned long micros();
// Can be previously declared as a macro in stupid eModbus // Can be previously declared as a macro in stupid eModbus
#undef millis #undef millis
unsigned long millis(); unsigned long millis();
void delay(unsigned long ms);
void delayMicroseconds(unsigned long us);
int max(int a, int b); int max(int a, int b);
#endif #endif

View file

@ -2,6 +2,8 @@
#define HARDWARESERIAL_H #define HARDWARESERIAL_H
#include <stdint.h> #include <stdint.h>
#include <cstddef>
#include "Print.h"
#include "Stream.h" #include "Stream.h"
enum SerialConfig { enum SerialConfig {
@ -33,11 +35,18 @@ enum SerialConfig {
class HardwareSerial : public Stream { class HardwareSerial : public Stream {
public: public:
int available() { return 0; }
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 setRxBufferSize(uint16_t size) {}
bool setRxFIFOFull(uint8_t fifoBytes) { return false; }
size_t write(uint8_t) { return 0; }
}; };
extern HardwareSerial Serial0; extern HardwareSerial Serial;
extern HardwareSerial Serial1; extern HardwareSerial Serial1;
extern HardwareSerial Serial2; extern HardwareSerial Serial2;

View file

@ -1,6 +1,13 @@
#ifndef PRINT_H #ifndef PRINT_H
#define PRINT_H #define PRINT_H
class Print {}; class Print {
public:
virtual void flush() {}
void printf(const char* format, ...) {}
virtual size_t write(uint8_t) = 0;
virtual size_t write(const char* s) { return 0; }
virtual size_t write(const uint8_t* buffer, size_t size) { return 0; }
};
#endif #endif

View file

@ -1,6 +1,12 @@
#ifndef STREAM_H #ifndef STREAM_H
#define STREAM_H #define STREAM_H
class Stream {}; #include "Print.h"
class Stream : public Print {
public:
virtual int available() = 0;
virtual int read() = 0;
};
#endif #endif

View file

@ -0,0 +1,10 @@
#include "FreeRTOS.h"
extern "C" {
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pxTaskCode, const char* const pcName, const uint32_t ulStackDepth,
void* const pvParameters, UBaseType_t uxPriority, TaskHandle_t* const pxCreatedTask,
const BaseType_t xCoreID) {
return 0;
}
void vTaskDelete(TaskHandle_t xTaskToDelete) {}
}

View file

@ -0,0 +1,21 @@
#ifndef _FREERTOS_H_
#define _FREERTOS_H_
#include "task.h"
#include <stdint.h>
typedef int BaseType_t;
typedef unsigned int UBaseType_t;
const BaseType_t tskNO_AFFINITY = -1;
extern "C" {
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pxTaskCode, const char* const pcName, const uint32_t ulStackDepth,
void* const pvParameters, UBaseType_t uxPriority, TaskHandle_t* const pxCreatedTask,
const BaseType_t xCoreID);
void vTaskDelete(TaskHandle_t xTaskToDelete);
}
#endif

View file

@ -0,0 +1,2 @@
typedef void* TaskHandle_t;
typedef void (*TaskFunction_t)(void*);

View file

@ -1,5 +1,5 @@
#include "HardwareSerial.h" #include "HardwareSerial.h"
HardwareSerial Serial0; HardwareSerial Serial;
HardwareSerial Serial1; HardwareSerial Serial1;
HardwareSerial Serial2; HardwareSerial Serial2;

View file

@ -3,7 +3,6 @@
#include "../Software/src/datalayer/datalayer.h" #include "../Software/src/datalayer/datalayer.h"
#include "../Software/src/devboard/safety/safety.h" #include "../Software/src/devboard/safety/safety.h"
#include "../Software/src/devboard/utils/events.h" #include "../Software/src/devboard/utils/events.h"
#include "../Software/src/inverter/ModbusInverterProtocol.h"
TEST(SafetyTests, ShouldSetEventWhenTemperatureTooHigh) { TEST(SafetyTests, ShouldSetEventWhenTemperatureTooHigh) {
init_events(); init_events();

View file

@ -4,7 +4,6 @@
#include "../Software/src/datalayer/datalayer.h" #include "../Software/src/datalayer/datalayer.h"
#include "../Software/src/devboard/safety/safety.h" #include "../Software/src/devboard/safety/safety.h"
#include "../Software/src/devboard/utils/events.h" #include "../Software/src/devboard/utils/events.h"
#include "../Software/src/inverter/ModbusInverterProtocol.h"
int main(int argc, char** argv) { int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
@ -12,5 +11,3 @@ int main(int argc, char** argv) {
} }
void store_settings_equipment_stop(void) {} void store_settings_equipment_stop(void) {}
ModbusInverterProtocol::ModbusInverterProtocol() {}