mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 00:39:50 +03:00
159 lines
5.0 KiB
C++
159 lines
5.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_ASYNC_H
|
|
#define _MODBUS_CLIENT_TCP_ASYNC_H
|
|
#include <Arduino.h>
|
|
#if defined ESP32
|
|
#include <AsyncTCP.h>
|
|
#elif defined ESP8266
|
|
#include <ESPAsyncTCP.h>
|
|
#endif
|
|
#include "options.h"
|
|
#include "ModbusMessage.h"
|
|
#include "ModbusClient.h"
|
|
#include <list>
|
|
#include <map>
|
|
#include <vector>
|
|
#if USE_MUTEX
|
|
#include <mutex> // NOLINT
|
|
#endif
|
|
|
|
using std::vector;
|
|
|
|
#define DEFAULTTIMEOUT 10000
|
|
#define DEFAULTIDLETIME 60000
|
|
|
|
class ModbusClientTCPasync : public ModbusClient {
|
|
public:
|
|
// Constructor takes address and port
|
|
explicit ModbusClientTCPasync(IPAddress address, uint16_t port = 502, uint16_t queueLimit = 100);
|
|
|
|
// Destructor: clean up queue, task etc.
|
|
~ModbusClientTCPasync();
|
|
|
|
// optionally manually connect to modbus server. Otherwise connection will be made upon first request
|
|
void connect();
|
|
// Connect to another Modbus server
|
|
void connect(IPAddress host, uint16_t port = 502);
|
|
|
|
// manually disconnect from modbus server. Connection will also auto close after idle time
|
|
void disconnect(bool force = false);
|
|
|
|
// Set timeout value
|
|
void setTimeout(uint32_t timeout);
|
|
|
|
// Set idle timeout value (time before connection auto closes after being idle)
|
|
void setIdleTimeout(uint32_t timeout);
|
|
|
|
// Set maximum amount of messages awaiting a response. Subsequent messages will be queued.
|
|
void setMaxInflightRequests(uint32_t maxInflightRequests);
|
|
|
|
// Remove all pending request from queue
|
|
void clearQueue();
|
|
|
|
protected:
|
|
|
|
// 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;
|
|
ModbusTCPhead head;
|
|
uint32_t sentTime;
|
|
bool isSyncRequest;
|
|
RequestEntry(uint32_t t, ModbusMessage m, bool syncReq = false) :
|
|
token(t),
|
|
msg(m),
|
|
head(ModbusTCPhead()),
|
|
sentTime(0),
|
|
isSyncRequest(syncReq) {}
|
|
};
|
|
|
|
// Base addRequest and syncRequest both must be present
|
|
Error addRequestM(ModbusMessage msg, uint32_t token);
|
|
ModbusMessage syncRequestM(ModbusMessage msg, uint32_t token);
|
|
|
|
// addToQueue: send freshly created request to queue
|
|
bool addToQueue(int32_t token, ModbusMessage request, bool syncReq = false);
|
|
|
|
// send: send request via Client connection
|
|
bool send(RequestEntry *request);
|
|
|
|
// receive: get response via Client connection
|
|
// TCPResponse* receive(uint8_t* data, size_t length);
|
|
|
|
void isInstance() { return; } // make class instantiable
|
|
|
|
// TCP handling code, all static taking a class instancs as param
|
|
void onConnected();
|
|
void onDisconnected();
|
|
void onACError(AsyncClient* c, int8_t error);
|
|
// void onTimeout(uint32_t time);
|
|
// void onAck(size_t len, uint32_t time);
|
|
void onPacket(uint8_t* data, size_t length);
|
|
void onPoll();
|
|
void handleSendingQueue();
|
|
|
|
std::list<RequestEntry*> txQueue; // Queue to hold requests to be sent
|
|
std::map<uint16_t, RequestEntry*> rxQueue; // Queue to hold requests to be processed
|
|
#if USE_MUTEX
|
|
std::mutex sLock; // Mutex to protect state
|
|
std::mutex qLock; // Mutex to protect queues
|
|
#endif
|
|
|
|
AsyncClient MTA_client; // Async TCP client
|
|
uint32_t MTA_timeout; // Standard timeout value taken
|
|
uint32_t MTA_idleTimeout; // Standard timeout value taken
|
|
uint16_t MTA_qLimit; // Maximum number of requests to accept in queue
|
|
uint32_t MTA_maxInflightRequests; // Maximum number of inflight requests
|
|
uint32_t MTA_lastActivity; // Last time there was activity (disabled when queues are not empty)
|
|
enum {
|
|
DISCONNECTED,
|
|
CONNECTING,
|
|
CONNECTED
|
|
} MTA_state; // TCP connection state
|
|
IPAddress MTA_host;
|
|
uint16_t MTA_port;
|
|
};
|
|
|
|
#endif
|