Skip to content

Commit ce90804

Browse files
committed
Added transaction buffering
1 parent 02d7bef commit ce90804

3 files changed

Lines changed: 130 additions & 21 deletions

File tree

Code/ESP32/include/TcpSlave.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
#pragma once
22

33
#include <Arduino.h>
4+
#include <vector>
45
#include <WiFiServer.h>
56
#include "RtuMaster.h"
67

78
#define MODBUS_DEFAULT_PORT 502
89
#define MODBUSIP_MAXFRAME 200
910
#define MODBUSIP_MAX_CLIENTS 4
1011
#define MODBUSIP_MAX_READMS 100
11-
#define MODBUSIP_MAX_RESPMS 2000
12+
#define MODBUSIP_MAX_RESPMS 500
13+
#define TRANSACTION_LIFESPAN 60000
1214

1315
namespace ModbusAdapter
1416
{
1517

18+
typedef struct Transaction {
19+
uint32_t timestamp;
20+
uint8_t* _requestFrame = nullptr;
21+
uint16_t _requestFrameLen = 0;
22+
uint8_t* _responseFrame = nullptr;
23+
uint16_t _responseFrameLen = 0;
24+
}TransactionT;
25+
1626
class TcpSlave
1727
{
1828
protected:
@@ -25,7 +35,7 @@ class TcpSlave
2535
};
2636
uint8_t raw[7];
2737
}MBAP_u;
28-
38+
std::vector<Transaction> _trans;
2939
uint8_t* _frame = nullptr;
3040
uint16_t _len = 0;
3141
RtuMaster _rtuMaster;
@@ -37,6 +47,8 @@ class TcpSlave
3747
void cleanup();
3848
int8_t getFreeClient();
3949
void exceptionResponse(FunctionCode fn, ResultCode excode);
50+
Transaction* searchTransaction(uint8_t* frame);
51+
boolean SupportedFunction(uint8_t fcode);
4052

4153
public:
4254
TcpSlave();

Code/ESP32/src/IOT.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ void handleRoot()
6363
s += _iotWebConf.getThingName();
6464
s += "</title></head><body>";
6565
s += _iotWebConf.getThingName();
66+
s += " (Free Memory: ";
67+
s += ESP.getFreeHeap();
68+
s += ")";
6669
s += "<ul>";
6770
s += "<li>Modbus port: ";
6871
s += _modbusPort;

Code/ESP32/src/TcpSlave.cpp

Lines changed: 113 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,43 @@ void TcpSlave::cbResponse(ResultCode res, void *data, uint16_t len)
3636
}
3737
else
3838
{
39-
//respond to TCP master
40-
// uint16_t ll = len +2;
41-
// _MBAP[4] = ll >> 8;
42-
// _MBAP[5] = ll & 0xff;
43-
// _MBAP[6] = 0x01;
44-
// uint8_t _buf[MODBUSIP_MAXFRAME];
45-
// memcpy(_buf,_MBAP, 7);
46-
// memcpy(&(_buf[7]),data, len);
47-
// // _client.write((byte*)_MBAP, 7);
48-
// _client.clearWriteError();
49-
// _client.write((byte*)_buf, len+7);
50-
// _client.flush();
51-
39+
Transaction *trans = searchTransaction(_frame);
40+
if (trans)
41+
{
42+
uint8_t *mem = (uint8_t *)malloc(len);
43+
if (mem)
44+
{
45+
free(trans->_responseFrame);
46+
trans->_responseFrame = mem;
47+
memcpy(trans->_responseFrame, data, len);
48+
trans->_responseFrameLen = len;
49+
trans->timestamp = millis();
50+
}
51+
}
52+
else
53+
{
54+
Transaction newEntry;
55+
newEntry.timestamp = millis();
56+
uint8_t *memReq = (uint8_t *)malloc(_len);
57+
if (memReq)
58+
{
59+
newEntry._requestFrame = memReq;
60+
memcpy(newEntry._requestFrame, _frame, _len);
61+
newEntry._requestFrameLen = _len;
62+
uint8_t *memResp = (uint8_t *)malloc(len);
63+
if (memResp)
64+
{
65+
newEntry._responseFrame = memResp;
66+
memcpy(newEntry._responseFrame, data, len);
67+
newEntry._responseFrameLen = len;
68+
_trans.push_back(newEntry);
69+
}
70+
else
71+
{
72+
free(memReq);
73+
}
74+
}
75+
}
5276
free(_frame);
5377
_len = len;
5478
_frame = (uint8_t *)malloc(len);
@@ -129,11 +153,30 @@ void TcpSlave::run()
129153
{
130154
if (_pClients[_clientIndex]->localPort() == _slavePort)
131155
{
156+
if (!SupportedFunction(_frame[0])) {
157+
exceptionResponse((FunctionCode)_frame[0], EX_ILLEGAL_FUNCTION);
158+
}
132159
// forward incoming frame to RTU master
133-
if (_rtuMaster.Transfer(_frame, _len, this) == false)
160+
else if (_rtuMaster.Transfer(_frame, _len, this) == false)
134161
{
135-
exceptionResponse((FunctionCode)_frame[0], EX_SLAVE_DEVICE_BUSY);
136-
_rtuState = RTU_IDLE;
162+
Transaction *trans = searchTransaction(_frame);
163+
if (trans)
164+
{
165+
uint8_t *mem = (uint8_t *)malloc(trans->_responseFrameLen);
166+
if (mem)
167+
{
168+
_len = trans->_responseFrameLen;
169+
free(_frame);
170+
_frame = mem;
171+
memcpy(_frame, trans->_responseFrame, _len);
172+
_rtuState = RTU_COMPLETE;
173+
}
174+
}
175+
else
176+
{
177+
exceptionResponse((FunctionCode)_frame[0], EX_DEVICE_FAILED_TO_RESPOND);
178+
_rtuState = RTU_IDLE;
179+
}
137180
}
138181
else
139182
{
@@ -145,9 +188,25 @@ void TcpSlave::run()
145188
}
146189
if (_rtuState != RTU_COMPLETE)
147190
{ // did not complete?
148-
exceptionResponse((FunctionCode)_frame[0], _rtuState == RTU_FAILED ? EX_GENERAL_FAILURE : EX_TIMEOUT);
149-
_rtuState = RTU_IDLE;
150-
_rtuMaster.reset();
191+
Transaction *trans = searchTransaction(_frame);
192+
if (trans)
193+
{
194+
uint8_t *mem = (uint8_t *)malloc(trans->_responseFrameLen);
195+
if (mem)
196+
{
197+
_len = trans->_responseFrameLen;
198+
free(_frame);
199+
_frame = mem;
200+
memcpy(_frame, trans->_responseFrame, _len);
201+
_rtuState = RTU_COMPLETE;
202+
}
203+
}
204+
else
205+
{
206+
exceptionResponse((FunctionCode)_frame[0], _rtuState == RTU_FAILED ? EX_GENERAL_FAILURE : EX_DATA_MISMACH);
207+
_rtuState = RTU_IDLE;
208+
_rtuMaster.reset();
209+
}
151210
}
152211
}
153212
}
@@ -204,5 +263,40 @@ void TcpSlave::cleanup()
204263
_pClients[i] = nullptr;
205264
}
206265
}
266+
// remove old transactions
267+
for (auto it = _trans.begin(); it != _trans.end();)
268+
{
269+
if (millis() - it->timestamp > TRANSACTION_LIFESPAN)
270+
{
271+
free(it->_requestFrame);
272+
free(it->_responseFrame);
273+
it = _trans.erase(it);
274+
}
275+
else
276+
it++;
277+
}
278+
}
279+
Transaction *TcpSlave::searchTransaction(uint8_t *frame)
280+
{
281+
std::vector<Transaction>::iterator it = std::find_if(_trans.begin(), _trans.end(), [frame](Transaction &trans) { return memcmp(trans._requestFrame, frame, trans._requestFrameLen) == 0; });
282+
if (it != _trans.end())
283+
return &*it;
284+
return nullptr;
285+
}
286+
287+
boolean TcpSlave::SupportedFunction(uint8_t fcode) {
288+
bool rVal = false;
289+
switch (fcode) {
290+
case FC_READ_REGS:
291+
case FC_READ_COILS:
292+
case FC_READ_INPUT_STAT:
293+
case FC_READ_INPUT_REGS:
294+
rVal = true;
295+
break;
296+
297+
default:
298+
rVal = false;
299+
}
300+
return rVal;
207301
}
208302
} // namespace ModbusAdapter

0 commit comments

Comments
 (0)