mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 08:19:52 +03:00
196 lines
6.0 KiB
C++
196 lines
6.0 KiB
C++
// =================================================================================================
|
|
// 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
|