Skip to content

Commit 02d7bef

Browse files
committed
Added support for multiple WiFiClients
1 parent 7eafac0 commit 02d7bef

7 files changed

Lines changed: 245 additions & 167 deletions

File tree

Code/ESP32/include/Enumerations.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,11 @@ enum ResultCode {
3737
EX_CANCEL = 0xE6 // Custom. Transaction/request canceled
3838
};
3939

40-
enum ReplyCode {
41-
REPLY_OFF = 0x01,
42-
REPLY_ECHO = 0x02,
43-
REPLY_NORMAL = 0x03,
44-
REPLY_ERROR = 0x04,
45-
REPLY_UNEXPECTED = 0x05
40+
enum RtuReplyState {
41+
RTU_IDLE = 0x01,
42+
RTU_PENDING = 0x02,
43+
RTU_COMPLETE = 0x03,
44+
RTU_FAILED = 0x04
4645
};
4746

4847
}

Code/ESP32/include/Log.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "esp_log.h"
44
#define TAG "ModbusAdapter"
55

6-
void inline printHexString(char* ptr, int len)
6+
void inline printHexString(byte* ptr, int len)
77
{
88
#if APP_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
99
esp_log_level_set(TAG, ESP_LOG_DEBUG);

Code/ESP32/include/RtuMaster.h

Lines changed: 5 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,11 @@
22
#include "Arduino.h"
33
#include "Enumerations.h"
44

5-
#define RTU_BUFFER_SIZE 264
6-
#define RtuTimeout 1000
7-
#define RtuRetryCount 10
85
#define InterFrameDelay 2
9-
#define MODBUSRTU_TIMEOUT 2000
10-
#define MODBUSRTU_BROADCAST 0
6+
#define MODBUSRTU_TIMEOUT 3000
117

128
namespace ModbusAdapter
139
{
14-
typedef bool (*cbTransaction)(ResultCode res, void* data, uint16_t len); // Callback for requests
15-
16-
struct TAddress {
17-
enum RegType {COIL, ISTS, IREG, HREG};
18-
RegType type;
19-
uint16_t address;
20-
bool operator==(const TAddress &obj) const { // TAddress == TAddress
21-
return type == obj.type && address == obj.address;
22-
}
23-
TAddress& operator++() { // ++TAddress
24-
address++;
25-
return *this;
26-
}
27-
TAddress operator++(int) { // TAddress++
28-
TAddress result(*this);
29-
++(*this);
30-
return result;
31-
}
32-
TAddress& operator+=(const int& inc) { // TAddress += integer
33-
address += inc;
34-
return *this;
35-
}
36-
const TAddress operator+(const int& inc) const { // TAddress + integer
37-
TAddress result(*this);
38-
result.address += inc;
39-
return result;
40-
}
41-
bool isCoil() {
42-
return type == COIL;
43-
}
44-
bool isIsts() {
45-
return type == ISTS;
46-
}
47-
bool isIreg() {
48-
return type == IREG;
49-
}
50-
bool isHreg() {
51-
return type == HREG;
52-
}
53-
};
54-
5510
class RtuMaster
5611
{
5712

@@ -61,19 +16,19 @@ class RtuMaster
6116
int16_t _rtsPin = -1;
6217
uint32_t _timestamp = 0;
6318
uint8_t _sentFunctionCode = 0;
64-
cbTransaction _callBackFunction = nullptr;
19+
void* _callBackFunction = nullptr;
6520
unsigned int _interFrameDelay; // inter-frame delay in mS
6621
uint32_t _lastTimeStamp = 0;
6722
uint16_t _len = 0;
6823

6924
public:
7025
RtuMaster();
71-
void Init(long baudRate, uint8_t mosbussAddress, int16_t rtsPin = -1);
72-
bool Transfer(byte* frame, cbTransaction cb);
26+
void Init(long baudRate, uint8_t mosbussAddress);
27+
bool Transfer(byte* frame, uint16_t len, void* cb);
7328
void run();
29+
void reset();
7430

7531
private:
76-
uint8_t masterPDU(uint8_t* frame, uint8_t* sourceFrame, TAddress startreg, void* output);
7732
bool rawSend(uint8_t slaveId, uint8_t* frame, uint8_t len);
7833
bool cleanup();
7934
uint16_t crc16(uint8_t address, uint8_t* frame, uint8_t pdulen);

Code/ESP32/include/TcpSlave.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,42 @@
55
#include "RtuMaster.h"
66

77
#define MODBUS_DEFAULT_PORT 502
8-
#define MODBUSIP_MAXFRAME 250 // max 125 holding registers
8+
#define MODBUSIP_MAXFRAME 200
9+
#define MODBUSIP_MAX_CLIENTS 4
10+
#define MODBUSIP_MAX_READMS 100
11+
#define MODBUSIP_MAX_RESPMS 2000
912

1013
namespace ModbusAdapter
1114
{
15+
1216
class TcpSlave
1317
{
14-
private:
15-
uint8_t _MBAP[7];
16-
WiFiClient _client;
18+
protected:
19+
typedef union MBAP_t {
20+
struct {
21+
uint16_t transactionId;
22+
uint16_t protocolId;
23+
uint16_t length;
24+
uint8_t unitId;
25+
};
26+
uint8_t raw[7];
27+
}MBAP_u;
28+
29+
uint8_t* _frame = nullptr;
30+
uint16_t _len = 0;
1731
RtuMaster _rtuMaster;
32+
int8_t _clientIndex = -1;
33+
uint16_t _slavePort = 0;
34+
WiFiServer* _pServer;
35+
WiFiClient* _pClients[MODBUSIP_MAX_CLIENTS];
36+
RtuReplyState _rtuState;
37+
void cleanup();
38+
int8_t getFreeClient();
39+
void exceptionResponse(FunctionCode fn, ResultCode excode);
1840

1941
public:
2042
TcpSlave();
43+
void cbResponse(ResultCode res, void *data, uint16_t len);
2144
void init(long baudRate, long tcpPort, uint8_t mosbusAddress);
2245
void close();
2346
void run();

Code/ESP32/platformio.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ build_flags =
3030
-D AP_TIMEOUT=30000
3131

3232
; logs
33-
; -D APP_LOG_LEVEL=ARDUHAL_LOG_LEVEL_WARN
34-
-D APP_LOG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
33+
-D APP_LOG_LEVEL=ARDUHAL_LOG_LEVEL_WARN
34+
; -D APP_LOG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
3535
; -D APP_LOG_LEVEL=ARDUHAL_LOG_LEVEL_INFO
3636
; -D IOTWEBCONF_DEBUG_PWD_TO_SERIAL
3737
; -D IOTWEBCONF_DEBUG_DISABLED

Code/ESP32/src/RtuMaster.cpp

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "RtuMaster.h"
33
#include "Enumerations.h"
44
#include "Log.h"
5+
#include "TcpSlave.h"
56

67
namespace ModbusAdapter
78
{
@@ -31,7 +32,7 @@ RtuMaster::RtuMaster()
3132
{
3233
}
3334

34-
void RtuMaster::Init(long baudRate, uint8_t modbusAddress, int16_t rtsPin)
35+
void RtuMaster::Init(long baudRate, uint8_t modbusAddress)
3536
{
3637
Serial1.begin(baudRate, SERIAL_8N1, GPIO_NUM_16, GPIO_NUM_17, false); // Modbus connection
3738
while (!Serial1)
@@ -40,7 +41,7 @@ void RtuMaster::Init(long baudRate, uint8_t modbusAddress, int16_t rtsPin)
4041
}
4142
_port = &Serial1;
4243
_unitId = modbusAddress;
43-
_rtsPin = rtsPin;
44+
_rtsPin = GPIO_NUM_5;
4445
if (_rtsPin >= 0) {
4546
pinMode(_rtsPin, OUTPUT);
4647
digitalWrite(_rtsPin, LOW);
@@ -52,15 +53,17 @@ void RtuMaster::Init(long baudRate, uint8_t modbusAddress, int16_t rtsPin)
5253
}
5354
}
5455

55-
bool RtuMaster::Transfer(byte* frame, cbTransaction cb)
56+
bool RtuMaster::Transfer(byte* frame, uint16_t len, void* cb)
5657
{
5758
if (_slaveId) return false; // Break if waiting for previous request result
5859
_slaveId = _unitId;
5960
_sentFunctionCode = frame[0];
60-
rawSend(_slaveId, frame, 5);
61+
rawSend(_slaveId, frame, len);
6162
_timestamp = millis();
6263
_callBackFunction = cb;
6364
_len = 0;
65+
// logd("RTU Transfer id: %d, len: %d", _slaveId, len);
66+
// printHexString(frame, len);
6467
return true;
6568
}
6669

@@ -76,24 +79,27 @@ void RtuMaster::run()
7679
return;
7780
}
7881
if (millis() - _lastTimeStamp < _interFrameDelay) return; // Wait data whitespace
79-
uint8_t address = 0;
82+
uint8_t address = _port->read(); //first byte of frame = address
83+
_len--; // Decrease by slaveId byte
84+
if (_len == 0) {
85+
return;
86+
}
8087
if (_slaveId == 0) { // Check if slaveId is set
8188
for (uint8_t i=0 ; i < _len ; i++) _port->read(); // Skip packet if is not expected
8289
_len = 0;
83-
logw("slaveId not set");
8490
return;
8591
}
86-
else
87-
{
88-
uint8_t address = _port->read(); //first byte of frame = address
89-
_len--; // Decrease by slaveId byte
90-
}
91-
92-
if (address != MODBUSRTU_BROADCAST && address != _slaveId) { // SlaveId Check
93-
for (uint8_t i=0 ; i < _len ; i++) _port->read(); // Skip packet if SlaveId doesn't mach
94-
_len = 0;
95-
logw("Invalid slaveId");
96-
return;
92+
if (address != _slaveId) { // SlaveId Check
93+
while (_len != 0) {
94+
address = _port->read(); // filter out non-modbus crap
95+
_len--;
96+
if (address == _slaveId) {
97+
break;
98+
}
99+
}
100+
if (_len == 0) {
101+
return;
102+
}
97103
}
98104
uint8_t* frame = (uint8_t*) malloc(_len);
99105
if (!frame) { // Fail to allocate buffer
@@ -108,8 +114,8 @@ void RtuMaster::run()
108114
_len = _len - 2; // Decrease by CRC 2 bytes
109115
uint16_t crc = crc16(address, frame, _len);
110116
if (frameCrc != crc) { // CRC Check
111-
logw("wrong crc for %d: [0x%x, 0x%x] len %d", address, frameCrc, crc, _len);
112-
printHexString((char *)frame, _len);
117+
// logw("wrong crc for %d: [0x%x, 0x%x] len %d", address, frameCrc, crc, _len);
118+
// printHexString(frame, _len);
113119
free(frame);
114120
frame = nullptr;
115121
_len = 0; // Cleanup if wrong crc
@@ -118,7 +124,8 @@ void RtuMaster::run()
118124
}
119125
if ((frame[0] & 0x7F) == _sentFunctionCode) { // Check if function code the same as requested
120126
if (_callBackFunction) {
121-
_callBackFunction(EX_SUCCESS, frame, _len);
127+
TcpSlave* p =(TcpSlave*) _callBackFunction;
128+
p->cbResponse(EX_SUCCESS, frame, _len);
122129
}
123130
_slaveId = 0;
124131
}
@@ -160,11 +167,18 @@ bool RtuMaster::rawSend(uint8_t slaveId, uint8_t* frame, uint8_t len) {
160167

161168
bool RtuMaster::cleanup() {
162169
if (_slaveId && ((millis() - _timestamp) > MODBUSRTU_TIMEOUT)) {
163-
if (_callBackFunction)
164-
_callBackFunction(EX_TIMEOUT, nullptr, 0);
170+
if (_callBackFunction) {
171+
TcpSlave* p =(TcpSlave*) _callBackFunction;
172+
p->cbResponse(EX_TIMEOUT, nullptr, 0);
173+
}
165174
_slaveId = 0;
166175
return true;
167176
}
168177
return false;
169178
}
179+
180+
void RtuMaster::reset() {
181+
_slaveId = 0;
182+
return;
183+
}
170184
}

0 commit comments

Comments
 (0)