mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 18:29:48 +02:00
Merge branch 'main' into feature/event-CAN-timing
This commit is contained in:
commit
d17e677a90
18 changed files with 171 additions and 66 deletions
|
@ -374,11 +374,19 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
|
||||
system_remaining_capacity_Wh = (battery_energy_content_maximum_kWh * 1000); // Convert kWh to Wh
|
||||
|
||||
system_max_charge_power_W = (battery_max_charge_amperage * system_battery_voltage_dV);
|
||||
if ((battery_max_charge_amperage * system_battery_voltage_dV) > 65000) {
|
||||
system_max_charge_power_W = 65000;
|
||||
} else {
|
||||
system_max_charge_power_W = (battery_max_charge_amperage * system_battery_voltage_dV);
|
||||
}
|
||||
|
||||
system_max_discharge_power_W = (battery_max_discharge_amperage * system_battery_voltage_dV);
|
||||
if ((battery_max_discharge_amperage * system_battery_voltage_dV) > 65000) {
|
||||
system_max_discharge_power_W = 65000;
|
||||
} else {
|
||||
system_max_discharge_power_W = (battery_max_discharge_amperage * system_battery_voltage_dV);
|
||||
}
|
||||
|
||||
battery_power = (system_battery_current_dA * (system_battery_voltage_dV / 10));
|
||||
battery_power = (system_battery_current_dA * (system_battery_voltage_dV / 100));
|
||||
|
||||
system_active_power_W = battery_power;
|
||||
|
||||
|
@ -429,8 +437,8 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
case 0x112: //BMS [10ms] Status Of High-Voltage Battery - 2
|
||||
battery_awake = true;
|
||||
CANstillAlive = 12; //This message is only sent if 30C (Wakeup pin on battery) is energized with 12V
|
||||
battery_current = ((rx_frame.data.u8[1] << 8 | rx_frame.data.u8[0]) / 10) - 819; //Amps
|
||||
battery_volts = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); //500.0 V
|
||||
battery_current = (rx_frame.data.u8[1] << 8 | rx_frame.data.u8[0]) - 8192; //deciAmps (-819.2 to 819.0A)
|
||||
battery_volts = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); //500.0 V
|
||||
battery_HVBatt_SOC = ((rx_frame.data.u8[5] & 0x0F) << 8 | rx_frame.data.u8[4]);
|
||||
battery_request_open_contactors = (rx_frame.data.u8[5] & 0xC0) >> 6;
|
||||
battery_request_open_contactors_instantly = (rx_frame.data.u8[6] & 0x03);
|
||||
|
@ -463,7 +471,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
break;
|
||||
case 0x2BD: //BMS [100ms] Status diagnosis high voltage - 1
|
||||
battery_awake = true;
|
||||
if (calculateCRC(rx_frame, 3, 0x15) != rx_frame.data.u8[0]) {
|
||||
if (calculateCRC(rx_frame, rx_frame.FIR.B.DLC, 0x15) != rx_frame.data.u8[0]) {
|
||||
//If calculated CRC does not match transmitted CRC, increase CANerror counter
|
||||
CANerror++;
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
This is commit 9ab44bd from https://github.com/ayushsharma82/ElegantOTA
|
||||
|
||||
<p><br/></p>
|
||||
<p align="center"><img src="/docs/feature.png?sanitize=true&raw=true" width="700"></p>
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"frameworks": "arduino",
|
||||
"platforms": ["espressif8266", "espressif32", "raspberrypi"]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name=ElegantOTA
|
||||
version=3.1.0
|
||||
version=3.1.1
|
||||
author=Ayush Sharma
|
||||
category=Communication
|
||||
maintainer=Ayush Sharma <asrocks5@gmail.com>
|
||||
|
|
|
@ -16,6 +16,7 @@ import requests
|
|||
import hashlib
|
||||
from urllib.parse import urlparse
|
||||
import time
|
||||
from requests.auth import HTTPDigestAuth
|
||||
Import("env")
|
||||
|
||||
try:
|
||||
|
@ -29,7 +30,9 @@ except ImportError:
|
|||
|
||||
def on_upload(source, target, env):
|
||||
firmware_path = str(source[0])
|
||||
upload_url_compatibility = env.GetProjectOption('upload_url')
|
||||
|
||||
auth = None
|
||||
upload_url_compatibility = env.GetProjectOption('custom_upload_url')
|
||||
upload_url = upload_url_compatibility.replace("/update", "")
|
||||
|
||||
with open(firmware_path, 'rb') as firmware:
|
||||
|
@ -50,12 +53,37 @@ def on_upload(source, target, env):
|
|||
'Referer': f'{upload_url}/update',
|
||||
'Connection': 'keep-alive'
|
||||
}
|
||||
|
||||
start_response = requests.get(start_url, headers=start_headers)
|
||||
|
||||
if start_response.status_code != 200:
|
||||
print("start-request faild " + str(start_response.status_code))
|
||||
return
|
||||
checkAuthResponse = requests.get(f"{upload_url_compatibility}/update")
|
||||
|
||||
if checkAuthResponse.status_code == 401:
|
||||
try:
|
||||
username = env.GetProjectOption('custom_username')
|
||||
password = env.GetProjectOption('custom_password')
|
||||
except:
|
||||
username = None
|
||||
password = None
|
||||
print("No authentication values specified.")
|
||||
print('Please, add some Options in your .ini file like: \n\ncustom_username=username\ncustom_password=password\n')
|
||||
if username is None or password is None:
|
||||
print("Authentication required, but no credentials provided.")
|
||||
return
|
||||
print("Serverconfiguration: authentication needed.")
|
||||
auth = HTTPDigestAuth(username, password)
|
||||
doUpdateAuth = requests.get(start_url, headers=start_headers, auth=auth)
|
||||
|
||||
if doUpdateAuth.status_code != 200:
|
||||
print("authentication faild " + str(doUpdateAuth.status_code))
|
||||
return
|
||||
print("Authentication successfull")
|
||||
else:
|
||||
auth = None
|
||||
print("Serverconfiguration: autentication not needed.")
|
||||
doUpdate = requests.get(start_url, headers=start_headers)
|
||||
|
||||
if doUpdate.status_code != 200:
|
||||
print("start-request faild " + str(doUpdate.status_code))
|
||||
return
|
||||
|
||||
firmware.seek(0)
|
||||
encoder = MultipartEncoder(fields={
|
||||
|
@ -87,7 +115,7 @@ def on_upload(source, target, env):
|
|||
}
|
||||
|
||||
|
||||
response = requests.post(f"{upload_url}/ota/upload", data=monitor, headers=post_headers)
|
||||
response = requests.post(f"{upload_url}/ota/upload", data=monitor, headers=post_headers, auth=auth)
|
||||
|
||||
bar.close()
|
||||
time.sleep(0.1)
|
||||
|
@ -100,4 +128,4 @@ def on_upload(source, target, env):
|
|||
tqdm.write(message)
|
||||
|
||||
|
||||
env.Replace(UPLOADCMD=on_upload)
|
||||
env.Replace(UPLOADCMD=on_upload)
|
|
@ -226,11 +226,11 @@
|
|||
#define ARDUINOJSON_BIN2ALPHA_1111() P
|
||||
#define ARDUINOJSON_BIN2ALPHA_(A, B, C, D) ARDUINOJSON_BIN2ALPHA_##A##B##C##D()
|
||||
#define ARDUINOJSON_BIN2ALPHA(A, B, C, D) ARDUINOJSON_BIN2ALPHA_(A, B, C, D)
|
||||
#define ARDUINOJSON_VERSION "7.0.3"
|
||||
#define ARDUINOJSON_VERSION "7.0.4"
|
||||
#define ARDUINOJSON_VERSION_MAJOR 7
|
||||
#define ARDUINOJSON_VERSION_MINOR 0
|
||||
#define ARDUINOJSON_VERSION_REVISION 3
|
||||
#define ARDUINOJSON_VERSION_MACRO V703
|
||||
#define ARDUINOJSON_VERSION_REVISION 4
|
||||
#define ARDUINOJSON_VERSION_MACRO V704
|
||||
#ifndef ARDUINOJSON_VERSION_NAMESPACE
|
||||
# define ARDUINOJSON_VERSION_NAMESPACE \
|
||||
ARDUINOJSON_CONCAT4(ARDUINOJSON_VERSION_MACRO, \
|
||||
|
@ -7498,11 +7498,11 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE
|
|||
#define ARDUINOJSON_NAMESPACE _Pragma ("GCC warning \"ARDUINOJSON_NAMESPACE is deprecated, use ArduinoJson instead\"") ArduinoJson
|
||||
#define JSON_ARRAY_SIZE(N) _Pragma ("GCC warning \"JSON_ARRAY_SIZE is deprecated, you don't need to compute the size anymore\"") (ArduinoJson::detail::sizeofArray(N))
|
||||
#define JSON_OBJECT_SIZE(N) _Pragma ("GCC warning \"JSON_OBJECT_SIZE is deprecated, you don't need to compute the size anymore\"") (ArduinoJson::detail::sizeofObject(N))
|
||||
#define JSON_STRING_SIZE(N) _Pragma ("GCC warning \"JSON_STRING_SIZE is deprecated, you don't need to compute the size anymore\"") (ArduinoJson::detail::sizeofString(N))
|
||||
#define JSON_STRING_SIZE(N) _Pragma ("GCC warning \"JSON_STRING_SIZE is deprecated, you don't need to compute the size anymore\"") (N+1)
|
||||
#else
|
||||
#define JSON_ARRAY_SIZE(N) (ArduinoJson::detail::sizeofArray(N))
|
||||
#define JSON_OBJECT_SIZE(N) (ArduinoJson::detail::sizeofObject(N))
|
||||
#define JSON_STRING_SIZE(N) (ArduinoJson::detail::sizeofString(N))
|
||||
#define JSON_STRING_SIZE(N) (N+1)
|
||||
#endif
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
template <size_t N>
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
// Return number of coils set to 0 (or OFF)
|
||||
uint16_t coilsSetOFF() const;
|
||||
|
||||
#if !ISLINUX
|
||||
#if !LINUX
|
||||
// Helper function to dump out coils in logical order
|
||||
void print(const char *label, Print& s);
|
||||
#endif
|
||||
|
|
|
@ -29,8 +29,8 @@ public:
|
|||
ModbusBridge();
|
||||
|
||||
// Constructors for the RTU variant. Parameters as are for ModbusServerRTU
|
||||
ModbusBridge(HardwareSerial& serial, uint32_t timeout, int rtsPin = -1);
|
||||
ModbusBridge(HardwareSerial& serial, uint32_t timeout, RTScallback rts);
|
||||
ModbusBridge(uint32_t timeout, int rtsPin = -1);
|
||||
ModbusBridge(uint32_t timeout, RTScallback rts);
|
||||
|
||||
// Destructor
|
||||
~ModbusBridge();
|
||||
|
@ -85,13 +85,13 @@ ModbusBridge<SERVERCLASS>::ModbusBridge() :
|
|||
|
||||
// Constructors for RTU variant
|
||||
template<typename SERVERCLASS>
|
||||
ModbusBridge<SERVERCLASS>::ModbusBridge(HardwareSerial& serial, uint32_t timeout, int rtsPin) :
|
||||
SERVERCLASS(serial, timeout, rtsPin) { }
|
||||
ModbusBridge<SERVERCLASS>::ModbusBridge(uint32_t timeout, int rtsPin) :
|
||||
SERVERCLASS(timeout, rtsPin) { }
|
||||
|
||||
// Alternate constructors for RTU variant
|
||||
template<typename SERVERCLASS>
|
||||
ModbusBridge<SERVERCLASS>::ModbusBridge(HardwareSerial& serial, uint32_t timeout, RTScallback rts) :
|
||||
SERVERCLASS(serial, timeout, rts) { }
|
||||
ModbusBridge<SERVERCLASS>::ModbusBridge(uint32_t timeout, RTScallback rts) :
|
||||
SERVERCLASS(timeout, rts) { }
|
||||
|
||||
// Destructor
|
||||
template<typename SERVERCLASS>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
// #define LOCAL_LOG_LEVEL LOG_LEVEL_VERBOSE
|
||||
#include "Logging.h"
|
||||
|
||||
// Constructor takes Serial reference and optional DE/RE pin
|
||||
// Constructor takes an optional DE/RE pin and queue size
|
||||
ModbusClientRTU::ModbusClientRTU(int8_t rtsPin, uint16_t queueLimit) :
|
||||
ModbusClient(),
|
||||
MR_serial(nullptr),
|
||||
|
@ -32,7 +32,7 @@ ModbusClientRTU::ModbusClientRTU(int8_t rtsPin, uint16_t queueLimit) :
|
|||
}
|
||||
}
|
||||
|
||||
// Alternative constructor takes Serial reference and RTS callback function
|
||||
// Alternative constructor takes an RTS callback function
|
||||
ModbusClientRTU::ModbusClientRTU(RTScallback rts, uint16_t queueLimit) :
|
||||
ModbusClient(),
|
||||
MR_serial(nullptr),
|
||||
|
@ -54,20 +54,20 @@ ModbusClientRTU::~ModbusClientRTU() {
|
|||
}
|
||||
|
||||
// begin: start worker task - general version
|
||||
void ModbusClientRTU::begin(Stream& serial, uint32_t baudRate, int coreID) {
|
||||
void ModbusClientRTU::begin(Stream& serial, uint32_t baudRate, int coreID, uint32_t userInterval) {
|
||||
MR_serial = &serial;
|
||||
doBegin(baudRate, coreID);
|
||||
doBegin(baudRate, coreID, userInterval);
|
||||
}
|
||||
|
||||
// begin: start worker task - HardwareSerial version
|
||||
void ModbusClientRTU::begin(HardwareSerial& serial, int coreID) {
|
||||
void ModbusClientRTU::begin(HardwareSerial& serial, int coreID, uint32_t userInterval) {
|
||||
MR_serial = &serial;
|
||||
uint32_t baudRate = serial.baudRate();
|
||||
serial.setRxFIFOFull(1);
|
||||
doBegin(baudRate, coreID);
|
||||
doBegin(baudRate, coreID, userInterval);
|
||||
}
|
||||
|
||||
void ModbusClientRTU::doBegin(uint32_t baudRate, int coreID) {
|
||||
void ModbusClientRTU::doBegin(uint32_t baudRate, int coreID, uint32_t userInterval) {
|
||||
// Task already running? End it in case
|
||||
end();
|
||||
|
||||
|
@ -77,11 +77,16 @@ void ModbusClientRTU::doBegin(uint32_t baudRate, int coreID) {
|
|||
// Set minimum interval time
|
||||
MR_interval = RTUutils::calculateInterval(baudRate);
|
||||
|
||||
// If user defined interval is longer, use that
|
||||
if (MR_interval < userInterval) {
|
||||
MR_interval = userInterval;
|
||||
}
|
||||
|
||||
// Create unique task name
|
||||
char taskName[18];
|
||||
snprintf(taskName, 18, "Modbus%02XRTU", instanceCounter);
|
||||
// Start task to handle the queue
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&handleConnection, taskName, 4096, this, 6, &worker, coreID >= 0 ? coreID : NULL);
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&handleConnection, taskName, CLIENT_TASK_STACK, this, 6, &worker, coreID >= 0 ? coreID : NULL);
|
||||
|
||||
LOG_D("Client task %d started. Interval=%d\n", (uint32_t)worker, MR_interval);
|
||||
}
|
||||
|
@ -102,6 +107,7 @@ void ModbusClientRTU::end() {
|
|||
// Kill task
|
||||
vTaskDelete(worker);
|
||||
LOG_D("Client task %d killed.\n", (uint32_t)worker);
|
||||
worker = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,6 +146,14 @@ uint32_t ModbusClientRTU::pendingRequests() {
|
|||
return requests.size();
|
||||
}
|
||||
|
||||
// Remove all pending request from queue
|
||||
void ModbusClientRTU::clearQueue()
|
||||
{
|
||||
std::queue<RequestEntry> empty;
|
||||
LOCK_GUARD(lockGuard, qLock);
|
||||
std::swap(requests, empty);
|
||||
}
|
||||
|
||||
// Base addRequest taking a preformatted data buffer and length as parameters
|
||||
Error ModbusClientRTU::addRequestM(ModbusMessage msg, uint32_t token) {
|
||||
Error rc = SUCCESS; // Return value
|
||||
|
|
|
@ -21,19 +21,19 @@ using std::queue;
|
|||
|
||||
class ModbusClientRTU : public ModbusClient {
|
||||
public:
|
||||
// Constructor takes Serial reference and optional DE/RE pin and queue limit
|
||||
// Constructor takes an optional DE/RE pin and queue limit
|
||||
explicit ModbusClientRTU(int8_t rtsPin = -1, uint16_t queueLimit = 100);
|
||||
|
||||
// Alternative Constructor takes Serial reference and RTS line toggle callback
|
||||
// Alternative Constructor takes an RTS line toggle callback
|
||||
explicit ModbusClientRTU(RTScallback rts, uint16_t queueLimit = 100);
|
||||
|
||||
// Destructor: clean up queue, task etc.
|
||||
~ModbusClientRTU();
|
||||
|
||||
// begin: start worker task
|
||||
void begin(Stream& serial, uint32_t baudrate, int coreID = -1);
|
||||
void begin(Stream& serial, uint32_t baudrate, int coreID = -1, uint32_t userInterval = 0);
|
||||
// Special variant for HardwareSerial
|
||||
void begin(HardwareSerial& serial, int coreID = -1);
|
||||
void begin(HardwareSerial& serial, int coreID = -1, uint32_t userInterval = 0);
|
||||
|
||||
// end: stop the worker
|
||||
void end();
|
||||
|
@ -56,6 +56,9 @@ public:
|
|||
// Return number of unprocessed requests in queue
|
||||
uint32_t pendingRequests();
|
||||
|
||||
// Remove all pending request from queue
|
||||
void clearQueue();
|
||||
|
||||
// addBroadcastMessage: create a fire-and-forget message to all servers on the RTU bus
|
||||
Error addBroadcastMessage(const uint8_t *data, uint8_t len);
|
||||
|
||||
|
@ -84,7 +87,7 @@ protected:
|
|||
ModbusMessage receive(const ModbusMessage request);
|
||||
|
||||
// start background task
|
||||
void doBegin(uint32_t baudRate, int coreID);
|
||||
void doBegin(uint32_t baudRate, int coreID, uint32_t userInterval);
|
||||
|
||||
void isInstance() { return; } // make class instantiable
|
||||
queue<RequestEntry> requests; // Queue to hold requests to be processed
|
||||
|
|
|
@ -18,30 +18,48 @@ void ModbusServer::registerWorker(uint8_t serverID, uint8_t functionCode, MBSwor
|
|||
|
||||
// getWorker: if a worker function is registered, return its address, nullptr otherwise
|
||||
MBSworker ModbusServer::getWorker(uint8_t serverID, uint8_t functionCode) {
|
||||
bool serverFound = false;
|
||||
LOG_D("Need worker for %02X-%02X : ", serverID, functionCode);
|
||||
// Search the FC map associated with the serverID
|
||||
auto svmap = workerMap.find(serverID);
|
||||
// Is there one?
|
||||
if (svmap != workerMap.end()) {
|
||||
serverFound = true;
|
||||
// No explicit serverID entry found, but we may have one for ANY_SERVER
|
||||
} else {
|
||||
svmap = workerMap.find(ANY_SERVER);
|
||||
if (svmap != workerMap.end()) {
|
||||
serverFound = true;
|
||||
serverID = ANY_SERVER;
|
||||
}
|
||||
}
|
||||
// Did we find a serverID?
|
||||
if (serverFound) {
|
||||
// Yes. Now look for the function code in the inner map
|
||||
bool functionCodeFound = false;
|
||||
auto fcmap = svmap->second.find(functionCode);;
|
||||
// Found it?
|
||||
if (fcmap != svmap->second.end()) {
|
||||
// Yes. Return the function pointer for it.
|
||||
LOG_D("Worker found for %02X/%02X\n", serverID, functionCode);
|
||||
return fcmap->second;
|
||||
functionCodeFound = true;
|
||||
// No, no explicit worker found, but may be there is one for ANY_FUNCTION_CODE?
|
||||
} else {
|
||||
fcmap = svmap->second.find(ANY_FUNCTION_CODE);;
|
||||
// Found it?
|
||||
if (fcmap != svmap->second.end()) {
|
||||
// Yes. Return the function pointer for it.
|
||||
LOG_D("Worker found for %02X/ANY\n", serverID);
|
||||
return fcmap->second;
|
||||
functionCodeFound = true;
|
||||
functionCode = ANY_FUNCTION_CODE;
|
||||
}
|
||||
}
|
||||
if (functionCodeFound) {
|
||||
// Yes. Return the function pointer for it.
|
||||
LOGRAW_D("Worker found for %02X/%02X\n", serverID, functionCode);
|
||||
return fcmap->second;
|
||||
}
|
||||
}
|
||||
// No matching function pointer found
|
||||
LOG_D("No matching worker found\n");
|
||||
LOGRAW_D("No matching worker found\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -68,16 +86,29 @@ bool ModbusServer::unregisterWorker(uint8_t serverID, uint8_t functionCode) {
|
|||
return (numEntries ? true : false);
|
||||
}
|
||||
|
||||
// isServerFor: if any worker function is registered for the given serverID, return true
|
||||
bool ModbusServer::isServerFor(uint8_t serverID) {
|
||||
// Search the FC map for the serverID
|
||||
auto svmap = workerMap.find(serverID);
|
||||
// Is it there? Then return true
|
||||
if (svmap != workerMap.end()) return true;
|
||||
// No, serverID was not found. Return false
|
||||
// isServerFor: if a worker function is registered for the given serverID, return true
|
||||
// functionCode defaults to ANY_FUNCTION_CODE and will yield true for any function code,
|
||||
// including ANY_FUNCTION_CODE :D
|
||||
bool ModbusServer::isServerFor(uint8_t serverID, uint8_t functionCode) {
|
||||
// Check if there is a non-nullptr function for the given combination
|
||||
if (getWorker(serverID, functionCode)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// isServerFor: short version to look up if the server is known at all
|
||||
bool ModbusServer::isServerFor(uint8_t serverID) {
|
||||
// Check if there is a non-nullptr function for the given combination
|
||||
auto svmap = workerMap.find(serverID);
|
||||
// Is there one?
|
||||
if (svmap != workerMap.end()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// getMessageCount: read number of messages processed
|
||||
uint32_t ModbusServer::getMessageCount() {
|
||||
return messageCount;
|
||||
|
@ -104,6 +135,7 @@ ModbusMessage ModbusServer::localRequest(ModbusMessage msg) {
|
|||
uint8_t functionCode = msg.getFunctionCode();
|
||||
LOG_D("Local request for %02X/%02X\n", serverID, functionCode);
|
||||
HEXDUMP_V("Request", msg.data(), msg.size());
|
||||
messageCount++;
|
||||
// Try to get a worker for the request
|
||||
MBSworker worker = getWorker(serverID, functionCode);
|
||||
// Did we get one?
|
||||
|
@ -129,6 +161,9 @@ ModbusMessage ModbusServer::localRequest(ModbusMessage msg) {
|
|||
}
|
||||
}
|
||||
HEXDUMP_V("Response", m.data(), m.size());
|
||||
if (m.getError() != SUCCESS) {
|
||||
errorCount++;
|
||||
}
|
||||
return m;
|
||||
} else {
|
||||
LOG_D("No worker found. Error response.\n");
|
||||
|
@ -140,11 +175,13 @@ ModbusMessage ModbusServer::localRequest(ModbusMessage msg) {
|
|||
// No. Respond with "Invalid server ID"
|
||||
m.setError(serverID, functionCode, INVALID_SERVER);
|
||||
}
|
||||
errorCount++;
|
||||
return m;
|
||||
}
|
||||
// We should never get here...
|
||||
LOG_C("Internal problem: should not get here!\n");
|
||||
m.setError(serverID, functionCode, UNDEFINED_ERROR);
|
||||
errorCount++;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,10 @@ public:
|
|||
// Returns true if the worker was found and removed
|
||||
bool unregisterWorker(uint8_t serverID, uint8_t functionCode = 0);
|
||||
|
||||
// isServerFor: if any worker function is registered for the given serverID, return true
|
||||
// isServerFor: if a worker function is registered for the given serverID, return true
|
||||
bool isServerFor(uint8_t serverID, uint8_t functionCode);
|
||||
|
||||
// isServerFor: short version to look up if the server is known at all
|
||||
bool isServerFor(uint8_t serverID);
|
||||
|
||||
// getMessageCount: read number of messages processed
|
||||
|
|
|
@ -64,32 +64,37 @@ ModbusServerRTU::~ModbusServerRTU() {
|
|||
}
|
||||
|
||||
// start: create task with RTU server - general version
|
||||
void ModbusServerRTU::begin(Stream& serial, uint32_t baudRate, int coreID) {
|
||||
void ModbusServerRTU::begin(Stream& serial, uint32_t baudRate, int coreID, uint32_t userInterval) {
|
||||
MSRserial = &serial;
|
||||
doBegin(baudRate, coreID);
|
||||
doBegin(baudRate, coreID, userInterval);
|
||||
}
|
||||
|
||||
// start: create task with RTU server - HardwareSerial versions
|
||||
void ModbusServerRTU::begin(HardwareSerial& serial, int coreID) {
|
||||
void ModbusServerRTU::begin(HardwareSerial& serial, int coreID, uint32_t userInterval) {
|
||||
MSRserial = &serial;
|
||||
uint32_t baudRate = serial.baudRate();
|
||||
serial.setRxFIFOFull(1);
|
||||
doBegin(baudRate, coreID);
|
||||
doBegin(baudRate, coreID, userInterval);
|
||||
}
|
||||
|
||||
void ModbusServerRTU::doBegin(uint32_t baudRate, int coreID) {
|
||||
void ModbusServerRTU::doBegin(uint32_t baudRate, int coreID, uint32_t userInterval) {
|
||||
// Task already running? Stop it in case.
|
||||
end();
|
||||
|
||||
// Set minimum interval time
|
||||
MSRinterval = RTUutils::calculateInterval(baudRate);
|
||||
|
||||
// If user defined interval is longer, use that
|
||||
if (MSRinterval < userInterval) {
|
||||
MSRinterval = userInterval;
|
||||
}
|
||||
|
||||
// Create unique task name
|
||||
char taskName[18];
|
||||
snprintf(taskName, 18, "MBsrv%02XRTU", instanceCounter);
|
||||
|
||||
// Start task to handle the client
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&serve, taskName, 4096, this, 8, &serverTask, coreID >= 0 ? coreID : NULL);
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&serve, taskName, SERVER_TASK_STACK, this, 8, &serverTask, coreID >= 0 ? coreID : NULL);
|
||||
|
||||
LOG_D("Server task %d started. Interval=%d\n", (uint32_t)serverTask, MSRinterval);
|
||||
}
|
||||
|
@ -180,10 +185,12 @@ void ModbusServerRTU::serve(ModbusServerRTU *myServer) {
|
|||
}
|
||||
// Is it a broadcast?
|
||||
if (request[0] == 0) {
|
||||
LOG_D("Broadcast!\n");
|
||||
// Yes. Do we have a listener?
|
||||
if (myServer->listener) {
|
||||
// Yes. call it
|
||||
myServer->listener(request);
|
||||
LOG_D("Broadcast served.\n");
|
||||
}
|
||||
// else we simply ignore it
|
||||
} else {
|
||||
|
|
|
@ -32,8 +32,8 @@ public:
|
|||
~ModbusServerRTU();
|
||||
|
||||
// begin: create task with RTU server to accept requests
|
||||
void begin(Stream& serial, uint32_t baudRate, int coreID = -1);
|
||||
void begin(HardwareSerial& serial, int coreID = -1);
|
||||
void begin(Stream& serial, uint32_t baudRate, int coreID = -1, uint32_t userInterval = 0);
|
||||
void begin(HardwareSerial& serial, int coreID = -1, uint32_t userInterval = 0);
|
||||
|
||||
// end: kill server task
|
||||
void end();
|
||||
|
@ -64,7 +64,7 @@ protected:
|
|||
inline void isInstance() { } // Make class instantiable
|
||||
|
||||
// internal common begin function
|
||||
void doBegin(uint32_t baudRate, int coreID);
|
||||
void doBegin(uint32_t baudRate, int coreID, uint32_t userInterval);
|
||||
|
||||
static uint8_t instanceCounter; // Number of RTU servers created (for task names)
|
||||
TaskHandle_t serverTask; // task of the started server
|
||||
|
|
|
@ -50,7 +50,7 @@ FCType FCT::getType(uint8_t functionCode) {
|
|||
return table[functionCode & 0x7F];
|
||||
}
|
||||
|
||||
// setType: change the type of a function code.
|
||||
// redefineType: change the type of a function code.
|
||||
// This is possible only for the codes undefined yet and will return
|
||||
// the effective type
|
||||
FCType FCT::redefineType(uint8_t functionCode, const FCType type) {
|
||||
|
|
|
@ -84,6 +84,9 @@ enum Error : uint8_t {
|
|||
UNDEFINED_ERROR = 0xFF // otherwise uncovered communication error
|
||||
};
|
||||
|
||||
// Readable expression for the "illegal" server ID of 0
|
||||
#define ANY_SERVER 0x00
|
||||
|
||||
#ifndef MINIMAL
|
||||
|
||||
// Constants for float and double re-ordering
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// #define LOCAL_LOG_LEVEL LOG_LEVEL_VERBOSE
|
||||
#include "Logging.h"
|
||||
|
||||
#if HAS_FREERTOS
|
||||
// calcCRC: calculate Modbus CRC16 on a given array of bytes
|
||||
uint16_t RTUutils::calcCRC(const uint8_t *data, uint16_t len) {
|
||||
// CRC16 pre-calculated tables
|
||||
|
@ -463,3 +464,4 @@ const char RTUutils::ASCIIread[] = {
|
|||
const char RTUutils::ASCIIwrite[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#define HAS_ETHERNET 1
|
||||
#define IS_LINUX 0
|
||||
#define NEED_UART_PATCH 1
|
||||
const unsigned int SERVER_TASK_STACK = 4096;
|
||||
const unsigned int CLIENT_TASK_STACK = 4096;
|
||||
|
||||
/* === ESP8266 DEFINITIONS AND MACROS === */
|
||||
#elif defined(ESP8266)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue