mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 08:49:52 +03:00
feat: add Modbus support
This commit is contained in:
195
lib/eModbus/src/ModbusClientTCP.h
Normal file
195
lib/eModbus/src/ModbusClientTCP.h
Normal file
@@ -0,0 +1,195 @@
|
||||
// =================================================================================================
|
||||
// eModbus: Copyright 2020 by Michael Harwerth, Bert Melis and the contributors to eModbus
|
||||
// MIT license - see license.md for details
|
||||
// =================================================================================================
|
||||
#ifndef _MODBUS_CLIENT_TCP_H
|
||||
#define _MODBUS_CLIENT_TCP_H
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#if HAS_FREERTOS || IS_LINUX
|
||||
#if HAS_FREERTOS
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#include "ModbusClient.h"
|
||||
#include "Client.h"
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
using std::queue;
|
||||
|
||||
#define TARGETHOSTINTERVAL 10
|
||||
#define DEFAULTTIMEOUT 2000
|
||||
|
||||
class ModbusClientTCP : public ModbusClient {
|
||||
public:
|
||||
// Constructor takes reference to Client (EthernetClient or WiFiClient)
|
||||
explicit ModbusClientTCP(Client& client, uint16_t queueLimit = 100);
|
||||
|
||||
// Alternative Constructor takes reference to Client (EthernetClient or WiFiClient) plus initial target host
|
||||
ModbusClientTCP(Client& client, IPAddress host, uint16_t port, uint16_t queueLimit = 100);
|
||||
|
||||
// Destructor: clean up queue, task etc.
|
||||
~ModbusClientTCP();
|
||||
|
||||
// begin: start worker task
|
||||
void begin(int coreID = -1);
|
||||
|
||||
// end: stop worker task
|
||||
void end();
|
||||
|
||||
// Set default timeout value (and interval)
|
||||
void setTimeout(uint32_t timeout = DEFAULTTIMEOUT, uint32_t interval = TARGETHOSTINTERVAL);
|
||||
|
||||
// Switch target host (if necessary)
|
||||
bool setTarget(IPAddress host, uint16_t port, uint32_t timeout = 0, uint32_t interval = 0);
|
||||
|
||||
// Return number of unprocessed requests in queue
|
||||
uint32_t pendingRequests();
|
||||
|
||||
// Remove all pending request from queue
|
||||
void clearQueue();
|
||||
|
||||
protected:
|
||||
// class describing a target server
|
||||
struct TargetHost {
|
||||
IPAddress host; // IP address
|
||||
uint16_t port; // Port number
|
||||
uint32_t timeout; // Time in ms waiting for a response
|
||||
uint32_t interval; // Time in ms to wait between requests
|
||||
|
||||
inline TargetHost& operator=(TargetHost& t) {
|
||||
host = t.host;
|
||||
port = t.port;
|
||||
timeout = t.timeout;
|
||||
interval = t.interval;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline TargetHost(TargetHost& t) :
|
||||
host(t.host),
|
||||
port(t.port),
|
||||
timeout(t.timeout),
|
||||
interval(t.interval) {}
|
||||
|
||||
inline TargetHost() :
|
||||
host(IPAddress(0, 0, 0, 0)),
|
||||
port(0),
|
||||
timeout(0),
|
||||
interval(0)
|
||||
{ }
|
||||
|
||||
inline TargetHost(IPAddress host, uint16_t port, uint32_t timeout, uint32_t interval) :
|
||||
host(host),
|
||||
port(port),
|
||||
timeout(timeout),
|
||||
interval(interval)
|
||||
{ }
|
||||
|
||||
inline bool operator==(TargetHost& t) {
|
||||
if (host != t.host) return false;
|
||||
if (port != t.port) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool operator!=(TargetHost& t) {
|
||||
if (host != t.host) return true;
|
||||
if (port != t.port) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// class describing the TCP header of Modbus packets
|
||||
class ModbusTCPhead {
|
||||
public:
|
||||
ModbusTCPhead() :
|
||||
transactionID(0),
|
||||
protocolID(0),
|
||||
len(0) {}
|
||||
|
||||
ModbusTCPhead(uint16_t tid, uint16_t pid, uint16_t _len) :
|
||||
transactionID(tid),
|
||||
protocolID(pid),
|
||||
len(_len) {}
|
||||
|
||||
uint16_t transactionID; // Caller-defined identification
|
||||
uint16_t protocolID; // const 0x0000
|
||||
uint16_t len; // Length of remainder of TCP packet
|
||||
|
||||
inline explicit operator const uint8_t *() {
|
||||
uint8_t *cp = headRoom;
|
||||
*cp++ = (transactionID >> 8) & 0xFF;
|
||||
*cp++ = transactionID & 0xFF;
|
||||
*cp++ = (protocolID >> 8) & 0xFF;
|
||||
*cp++ = protocolID & 0xFF;
|
||||
*cp++ = (len >> 8) & 0xFF;
|
||||
*cp++ = len & 0xFF;
|
||||
return headRoom;
|
||||
}
|
||||
|
||||
inline ModbusTCPhead& operator= (ModbusTCPhead& t) {
|
||||
transactionID = t.transactionID;
|
||||
protocolID = t.protocolID;
|
||||
len = t.len;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t headRoom[6]; // Buffer to hold MSB-first TCP header
|
||||
};
|
||||
|
||||
struct RequestEntry {
|
||||
uint32_t token;
|
||||
ModbusMessage msg;
|
||||
TargetHost target;
|
||||
ModbusTCPhead head;
|
||||
bool isSyncRequest;
|
||||
RequestEntry(uint32_t t, ModbusMessage m, TargetHost tg, bool syncReq = false) :
|
||||
token(t),
|
||||
msg(m),
|
||||
target(tg),
|
||||
head(ModbusTCPhead()),
|
||||
isSyncRequest(syncReq) {}
|
||||
};
|
||||
|
||||
// Base addRequest and syncRequest must be present
|
||||
Error addRequestM(ModbusMessage msg, uint32_t token);
|
||||
ModbusMessage syncRequestM(ModbusMessage msg, uint32_t token);
|
||||
// TCP-specific addition "...MT()" including adhoc target - used by bridge
|
||||
Error addRequestMT(ModbusMessage msg, uint32_t token, IPAddress targetHost, uint16_t targetPort);
|
||||
ModbusMessage syncRequestMT(ModbusMessage msg, uint32_t token, IPAddress targetHost, uint16_t targetPort);
|
||||
|
||||
// addToQueue: send freshly created request to queue
|
||||
bool addToQueue(uint32_t token, ModbusMessage request, TargetHost target, bool syncReq = false);
|
||||
|
||||
// handleConnection: worker task method
|
||||
static void handleConnection(ModbusClientTCP *instance);
|
||||
#if IS_LINUX
|
||||
static void *pHandle(void *p);
|
||||
#endif
|
||||
|
||||
// send: send request via Client connection
|
||||
void send(RequestEntry *request);
|
||||
|
||||
// receive: get response via Client connection
|
||||
ModbusMessage receive(RequestEntry *request);
|
||||
|
||||
void isInstance() { return; } // make class instantiable
|
||||
queue<RequestEntry *> requests; // Queue to hold requests to be processed
|
||||
#if USE_MUTEX
|
||||
mutex qLock; // Mutex to protect queue
|
||||
#endif
|
||||
Client& MT_client; // Client reference for Internet connections (EthernetClient or WifiClient)
|
||||
TargetHost MT_lastTarget; // last used server
|
||||
TargetHost MT_target; // Description of target server
|
||||
uint32_t MT_defaultTimeout; // Standard timeout value taken if no dedicated was set
|
||||
uint32_t MT_defaultInterval; // Standard interval value taken if no dedicated was set
|
||||
uint16_t MT_qLimit; // Maximum number of requests to accept in queue
|
||||
|
||||
// Let any ModbusBridge class use protected members
|
||||
template<typename SERVERCLASS> friend class ModbusBridge;
|
||||
};
|
||||
|
||||
#endif // HAS_FREERTOS
|
||||
|
||||
#endif // INCLUDE GUARD
|
||||
Reference in New Issue
Block a user