mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 02:09:30 +02:00
Update eModbus to v1.7.4
This commit is contained in:
parent
a1557b955a
commit
024dae7c64
15 changed files with 154 additions and 35 deletions
|
@ -47,6 +47,8 @@ CoilData::~CoilData() {
|
|||
|
||||
// Assignment operator
|
||||
CoilData& CoilData::operator=(const CoilData& m) {
|
||||
// Avoid self-assignment
|
||||
if (this == &m) return *this;
|
||||
// Remove old data
|
||||
if (CDbuffer) {
|
||||
delete CDbuffer;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#undef LOCAL_LOG_LEVEL
|
||||
// #define LOCAL_LOG_LEVEL LOG_LEVEL_ERROR
|
||||
#include "Logging.h"
|
||||
#include <algorithm>
|
||||
|
||||
// Default Constructor - takes optional size of MM_data to allocate memory
|
||||
ModbusMessage::ModbusMessage(uint16_t dataLen) {
|
||||
|
@ -146,7 +147,7 @@ void ModbusMessage::setServerID(uint8_t serverID) {
|
|||
}
|
||||
|
||||
void ModbusMessage::setFunctionCode(uint8_t FC) {
|
||||
if (MM_data.size() < 2) {
|
||||
if (MM_data.size() < 2) {
|
||||
MM_data.resize(2); // Resize to at least 2 to ensure indices 0 and 1 are valid
|
||||
MM_data[0] = 0; // Optional: Invalid server ID as a placeholder
|
||||
}
|
||||
|
@ -155,10 +156,10 @@ void ModbusMessage::setFunctionCode(uint8_t FC) {
|
|||
|
||||
// add() variant to copy a buffer into MM_data. Returns updated size
|
||||
uint16_t ModbusMessage::add(const uint8_t *arrayOfBytes, uint16_t count) {
|
||||
uint16_t originalSize = MM_data.size();
|
||||
MM_data.resize(originalSize + count);
|
||||
// Copy it
|
||||
while (count--) {
|
||||
MM_data.push_back(*arrayOfBytes++);
|
||||
}
|
||||
std::copy(arrayOfBytes, arrayOfBytes + count, MM_data.begin() + originalSize);
|
||||
// Return updated size (logical length of message so far)
|
||||
return MM_data.size();
|
||||
}
|
||||
|
@ -179,7 +180,7 @@ uint8_t ModbusMessage::determineFloatOrder() {
|
|||
uint32_t i = 77230; // int value to go into a float without rounding error
|
||||
float f = i; // assign it
|
||||
uint8_t *b = (uint8_t *)&f; // Pointer to bytes of f
|
||||
uint8_t expect[floatSize] = { 0x47, 0x96, 0xd7, 0x00 }; // IEEE754 representation
|
||||
const uint8_t expect[floatSize] = { 0x47, 0x96, 0xd7, 0x00 }; // IEEE754 representation
|
||||
uint8_t matches = 0; // number of bytes successfully matched
|
||||
|
||||
// Loop over the bytes of the expected sequence
|
||||
|
@ -223,7 +224,7 @@ uint8_t ModbusMessage::determineDoubleOrder() {
|
|||
uint64_t i = 5791007487489389; // int64 value to go into a double without rounding error
|
||||
double f = i; // assign it
|
||||
uint8_t *b = (uint8_t *)&f; // Pointer to bytes of f
|
||||
uint8_t expect[doubleSize] = { 0x43, 0x34, 0x92, 0xE4, 0x00, 0x2E, 0xF5, 0x6D }; // IEEE754 representation
|
||||
const uint8_t expect[doubleSize] = { 0x43, 0x34, 0x92, 0xE4, 0x00, 0x2E, 0xF5, 0x6D }; // IEEE754 representation
|
||||
uint8_t matches = 0; // number of bytes successfully matched
|
||||
|
||||
// Loop over the bytes of the expected sequence
|
||||
|
@ -304,10 +305,7 @@ double ModbusMessage::swapDouble(double& f, int swapRule) {
|
|||
|
||||
// add() variant for a vector of uint8_t
|
||||
uint16_t ModbusMessage::add(vector<uint8_t> v) {
|
||||
for (auto& b: v) {
|
||||
MM_data.push_back(b);
|
||||
}
|
||||
return MM_data.size();
|
||||
return add(v.data(), v.size());
|
||||
}
|
||||
|
||||
// add() variants for float and double values
|
||||
|
|
|
@ -30,7 +30,6 @@ MBSworker ModbusServer::getWorker(uint8_t serverID, uint8_t functionCode) {
|
|||
svmap = workerMap.find(ANY_SERVER);
|
||||
if (svmap != workerMap.end()) {
|
||||
serverFound = true;
|
||||
serverID = ANY_SERVER;
|
||||
}
|
||||
}
|
||||
// Did we find a serverID?
|
||||
|
@ -49,7 +48,6 @@ MBSworker ModbusServer::getWorker(uint8_t serverID, uint8_t functionCode) {
|
|||
if (fcmap != svmap->second.end()) {
|
||||
// Yes. Return the function pointer for it.
|
||||
functionCodeFound = true;
|
||||
functionCode = ANY_FUNCTION_CODE;
|
||||
}
|
||||
}
|
||||
if (functionCodeFound) {
|
||||
|
@ -104,6 +102,11 @@ bool ModbusServer::isServerFor(uint8_t serverID) {
|
|||
// Is there one?
|
||||
if (svmap != workerMap.end()) {
|
||||
return true;
|
||||
} else {
|
||||
svmap = workerMap.find(ANY_SERVER);
|
||||
if (svmap != workerMap.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -68,15 +68,12 @@ protected:
|
|||
ModbusServer();
|
||||
|
||||
// Destructor
|
||||
~ModbusServer();
|
||||
virtual ~ModbusServer();
|
||||
|
||||
// Prevent copy construction or assignment
|
||||
ModbusServer(ModbusServer& other) = delete;
|
||||
ModbusServer& operator=(ModbusServer& other) = delete;
|
||||
|
||||
// Virtual function to prevent this class being instantiated
|
||||
virtual void isInstance() = 0;
|
||||
|
||||
std::map<uint8_t, std::map<uint8_t, MBSworker>> workerMap; // map on serverID->functionCode->worker function
|
||||
uint32_t messageCount; // Number of Requests processed
|
||||
uint32_t errorCount; // Number of errors responded
|
||||
|
|
|
@ -12,8 +12,15 @@
|
|||
#undef SERVER_END
|
||||
#define SERVER_END // NIL for Ethernet
|
||||
|
||||
// Create own non-virtual EthernetServer class
|
||||
class EthernetServerEM : public EthernetServer {
|
||||
public:
|
||||
explicit EthernetServerEM(uint16_t port) : EthernetServer(port) { }
|
||||
void begin(uint16_t port = 0) override { }
|
||||
};
|
||||
|
||||
#include "ModbusServerTCPtemp.h"
|
||||
using ModbusServerEthernet = ModbusServerTCP<EthernetServer, EthernetClient>;
|
||||
using ModbusServerEthernet = ModbusServerTCP<EthernetServerEM, EthernetClient>;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -94,7 +94,7 @@ void ModbusServerRTU::doBegin(uint32_t baudRate, int coreID, uint32_t userInterv
|
|||
snprintf(taskName, 18, "MBsrv%02XRTU", instanceCounter);
|
||||
|
||||
// Start task to handle the client
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&serve, taskName, SERVER_TASK_STACK, this, 8, &serverTask, coreID >= 0 ? coreID : NULL);
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&serve, taskName, SERVER_TASK_STACK, this, 8, &serverTask, coreID >= 0 ? coreID : tskNO_AFFINITY);
|
||||
|
||||
LOG_D("Server task %d started. Interval=%d\n", (uint32_t)serverTask, MSRinterval);
|
||||
}
|
||||
|
@ -126,6 +126,12 @@ bool ModbusServerRTU::isModbusASCII() {
|
|||
return MSRuseASCII;
|
||||
}
|
||||
|
||||
// set timeout
|
||||
void ModbusServerRTU::setModbusTimeout(unsigned long timeout)
|
||||
{
|
||||
serverTimeout = timeout;
|
||||
}
|
||||
|
||||
// Toggle skipping of leading 0x00 byte
|
||||
void ModbusServerRTU::skipLeading0x00(bool onOff) {
|
||||
MSRskipLeadingZeroByte = onOff;
|
||||
|
@ -231,8 +237,8 @@ void ModbusServerRTU::serve(ModbusServerRTU *myServer) {
|
|||
response = m;
|
||||
}
|
||||
} else {
|
||||
// No callback. Is at least the serverID valid and no broadcast?
|
||||
if (myServer->isServerFor(request[0]) && request[0] != 0x00) {
|
||||
// No callback. Is at least the serverID valid?
|
||||
if (myServer->isServerFor(request[0])) {
|
||||
// Yes. Send back a ILLEGAL_FUNCTION error
|
||||
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_FUNCTION);
|
||||
}
|
||||
|
@ -256,9 +262,7 @@ void ModbusServerRTU::serve(ModbusServerRTU *myServer) {
|
|||
if (request[0] != TIMEOUT) {
|
||||
// Any other error could be important for debugging, so print it
|
||||
ModbusError me((Error)request[0]);
|
||||
#ifdef DEBUG_VIA_USB
|
||||
LOG_E("RTU receive: %02X - %s\n", (int)me, (const char *)me);
|
||||
#endif //DEBUG_VIA_USB
|
||||
}
|
||||
}
|
||||
// Give scheduler room to breathe
|
||||
|
|
|
@ -47,6 +47,9 @@ public:
|
|||
// Inquire protocol mode
|
||||
bool isModbusASCII();
|
||||
|
||||
// set timeout
|
||||
void setModbusTimeout(unsigned long timeout);
|
||||
|
||||
// Toggle skipping of leading 0x00 byte
|
||||
void skipLeading0x00(bool onOff = true);
|
||||
|
||||
|
@ -61,8 +64,6 @@ protected:
|
|||
ModbusServerRTU(ModbusServerRTU& m) = delete;
|
||||
ModbusServerRTU& operator=(ModbusServerRTU& m) = delete;
|
||||
|
||||
inline void isInstance() { } // Make class instantiable
|
||||
|
||||
// internal common begin function
|
||||
void doBegin(uint32_t baudRate, int coreID, uint32_t userInterval);
|
||||
|
||||
|
|
|
@ -109,8 +109,8 @@ const uint8_t swapTables[8][8] = {
|
|||
enum FCType : uint8_t {
|
||||
FC01_TYPE, // Two uint16_t parameters (FC 0x01, 0x02, 0x03, 0x04, 0x05, 0x06)
|
||||
FC07_TYPE, // no additional parameter (FCs 0x07, 0x0b, 0x0c, 0x11)
|
||||
FC0F_TYPE, // two uint16_t parameters, a uint8_t length byte and a uint16_t* pointer to array of bytes (FC 0x0f)
|
||||
FC10_TYPE, // two uint16_t parameters, a uint8_t length byte and a uint8_t* pointer to array of words (FC 0x10)
|
||||
FC0F_TYPE, // two uint16_t parameters, a uint8_t length byte and a uint8_t* pointer to array of bytes (FC 0x0f)
|
||||
FC10_TYPE, // two uint16_t parameters, a uint8_t length byte and a uint16_t* pointer to array of words (FC 0x10)
|
||||
FC16_TYPE, // three uint16_t parameters (FC 0x16)
|
||||
FC18_TYPE, // one uint16_t parameter (FC 0x18)
|
||||
FCGENERIC, // for FCs not yet explicitly coded (or too complex)
|
||||
|
|
26
Software/src/lib/eModbus-eModbus/README.md
Normal file
26
Software/src/lib/eModbus-eModbus/README.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
<img src=https://github.com/eModbus/eModbus/blob/master/eModbusLogo.png width="33%" alt="eModbus">
|
||||
|
||||
**Read the docs at http://emodbus.github.io!**
|
||||
|
||||

|
||||
|
||||
This is a library to provide Modbus client (formerly known as master), server (formerly slave) and bridge/gateway functionalities for Modbus RTU, ASCII and TCP protocols.
|
||||
|
||||
For Modbus protocol specifications, please refer to the [Modbus.org site](https://www.modbus.org/specs.php)!
|
||||
|
||||
Modbus communication is done in separate tasks, so Modbus requests and responses are non-blocking. Callbacks are provided to prepare or receive the responses asynchronously.
|
||||
|
||||
Key features:
|
||||
- for use in the Arduino framework
|
||||
- designed for ESP32, various interfaces supported; async versions run also on ESP8266
|
||||
- non blocking / asynchronous API
|
||||
- server, client and bridge modes
|
||||
- TCP (Ethernet, WiFi and Async), ASCII and RTU interfaces
|
||||
- all common and user-defined Modbus standard function codes
|
||||
|
||||
This has been developed by enthusiasts. While we do our utmost best to make robust software, do not expect any bullet-proof, industry deployable, guaranteed software. [**See the license**](https://github.com/eModbus/eModbus/blob/master/license.md) to learn about liabilities etc.
|
||||
|
||||
We do welcome any ideas, suggestions, bug reports or questions. Please use the "[Issues](https://github.com/eModbus/eModbus/issues)" tab to report bugs and request new features and visit the "[Discussions](https://github.com/eModbus/eModbus/discussions)" tab for all else.
|
||||
|
||||
Have fun!
|
|
@ -3,13 +3,13 @@
|
|||
// MIT license - see license.md for details
|
||||
// =================================================================================================
|
||||
#include "options.h"
|
||||
#if HAS_FREERTOS
|
||||
#include "ModbusMessage.h"
|
||||
#include "RTUutils.h"
|
||||
#undef LOCAL_LOG_LEVEL
|
||||
// #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
|
||||
|
@ -57,10 +57,9 @@ uint16_t RTUutils::calcCRC(const uint8_t *data, uint16_t len) {
|
|||
|
||||
uint8_t crcHi = 0xFF;
|
||||
uint8_t crcLo = 0xFF;
|
||||
uint8_t index;
|
||||
|
||||
while (len--) {
|
||||
index = crcLo ^ *data++;
|
||||
uint8_t index = crcLo ^ *data++;
|
||||
crcLo = crcHi ^ crcHiTable[index];
|
||||
crcHi = crcLoTable[index];
|
||||
}
|
||||
|
@ -464,4 +463,5 @@ 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
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
#ifndef _RTU_UTILS_H
|
||||
#define _RTU_UTILS_H
|
||||
#include <stdint.h>
|
||||
#if NEED_UART_PATCH
|
||||
#include <soc/uart_struct.h>
|
||||
#endif
|
||||
#include <vector>
|
||||
#include "Stream.h"
|
||||
#include "ModbusTypeDefs.h"
|
||||
|
@ -52,11 +49,13 @@ public:
|
|||
// RTSauto: dummy callback for auto half duplex RS485 boards
|
||||
inline static void RTSauto(bool level) { return; } // NOLINT
|
||||
|
||||
#if HAS_FREERTOS
|
||||
// Necessary preparations for a HardwareSerial
|
||||
static void prepareHardwareSerial(HardwareSerial& s, uint16_t bufferSize = 260) {
|
||||
s.setRxBufferSize(bufferSize);
|
||||
s.setTxBufferSize(bufferSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Printable characters for ASCII protocol: 012345678ABCDEF
|
||||
|
|
69
Software/src/lib/eModbus-eModbus/library.json
Normal file
69
Software/src/lib/eModbus-eModbus/library.json
Normal file
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"name": "eModbus",
|
||||
"version": "1.7.4",
|
||||
"keywords": "Arduino, ESP32, Modbus, RTU, ASCII, ModbusASCII, ModbusRTU, ModbusTCP",
|
||||
"description": "ModbusRTU, ModbusASCII and ModbusTCP functions for ESP32",
|
||||
"homepage": "https://emodbus.github.io",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bert Melis",
|
||||
"url": "https://github.com/bertmelis",
|
||||
"maintainer": true
|
||||
},
|
||||
{
|
||||
"name": "Michael Harwerth",
|
||||
"url": "https://github.com/Miq1",
|
||||
"email": "miq1@gmx.de",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/eModbus/eModbus",
|
||||
"branch": "master"
|
||||
},
|
||||
"dependencies": [
|
||||
{
|
||||
"owner": "ESP32Async",
|
||||
"name": "AsyncTCP",
|
||||
"version": "^3.3.8",
|
||||
"platforms": ["espressif32"]
|
||||
},
|
||||
{
|
||||
"owner": "ESP32Async",
|
||||
"name": "ESPAsyncTCP",
|
||||
"version": "^2.0.0",
|
||||
"platforms": ["espressif8266"]
|
||||
},
|
||||
{
|
||||
"name": "Ethernet",
|
||||
"version": "https://github.com/arduino-libraries/Ethernet.git",
|
||||
"platforms": ["espressif32"]
|
||||
}
|
||||
],
|
||||
"export": {
|
||||
"include":
|
||||
[
|
||||
"src/*.cpp",
|
||||
"src/*.h",
|
||||
"examples/*",
|
||||
"Test/*",
|
||||
".gitignore",
|
||||
"README.md",
|
||||
"license.md",
|
||||
"keywords.txt",
|
||||
"library.properties",
|
||||
"library.json"
|
||||
]
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": [
|
||||
"espressif32",
|
||||
"espressif8266"
|
||||
],
|
||||
"build":
|
||||
{
|
||||
"lib_ldf_Mode": "deep+"
|
||||
}
|
||||
}
|
9
Software/src/lib/eModbus-eModbus/library.properties
Normal file
9
Software/src/lib/eModbus-eModbus/library.properties
Normal file
|
@ -0,0 +1,9 @@
|
|||
name=eModbus
|
||||
version=1.7.4
|
||||
author=bertmelis,Miq1 <miq1@gmx.de>
|
||||
maintainer=Miq1 <miq1@gmx.de>
|
||||
sentence=eModbus provides Modbus RTU, ASCII and TCP functions for ESP32.
|
||||
paragraph=This library is non-blocking for the program using it. Modbus requests and responses will be returned to user-supplied callback functions. All Modbus function codes are supported implicitly, the codes specified by the Modbus specs are parameter-checked.
|
||||
category=Communication
|
||||
url=https://github.com/eModbus/eModbus
|
||||
architectures=esp32,FreeRTOS
|
7
Software/src/lib/eModbus-eModbus/license.md
Normal file
7
Software/src/lib/eModbus-eModbus/license.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
#### Copyright 2020 Michael Harwerth, Bert Melis and the contributors to eModbus (MIT license)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
#### The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -12,7 +12,6 @@
|
|||
#define HAS_FREERTOS 1
|
||||
#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;
|
||||
|
||||
|
@ -23,7 +22,6 @@ const unsigned int CLIENT_TASK_STACK = 4096;
|
|||
#define HAS_FREERTOS 0
|
||||
#define HAS_ETHERNET 0
|
||||
#define IS_LINUX 0
|
||||
#define NEED_UART_PATCH 0
|
||||
|
||||
/* === LINUX DEFINITIONS AND MACROS === */
|
||||
#elif defined(__linux__)
|
||||
|
@ -31,7 +29,6 @@ const unsigned int CLIENT_TASK_STACK = 4096;
|
|||
#define HAS_FREERTOS 0
|
||||
#define HAS_ETHERNET 0
|
||||
#define IS_LINUX 1
|
||||
#define NEED_UART_PATCH 0
|
||||
#include <cstdio> // for printf()
|
||||
#include <cstring> // for memcpy(), strlen() etc.
|
||||
#include <cinttypes> // for uint32_t etc.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue