26
26
27
27
***************************************************************** */
28
28
29
- #define ADDRESS_POS (6 * !localConfig.enableRtuOverTcp) // position of slave address in the TCP/UDP message (0 for Modbus RTU over TCP/UDP and 6 for Modbus RTU over TCP/UDP)
29
+ #define ADDRESS_POS (6 * !localConfig.enableRtuOverTcp) // position of slave address in the incoming TCP/UDP message (0 for Modbus RTU over TCP/UDP and 6 for Modbus RTU over TCP/UDP)
30
+
31
+ enum status : byte {
32
+ STAT_OK,
33
+ STAT_ERROR_0X,
34
+ STAT_ERROR_0A,
35
+ STAT_ERROR_0B,
36
+ STAT_NUM // Number of status flags in this enum. Must be the last element within this enum!!
37
+ };
38
+
39
+ // bool arrays for storing Modbus RTU status of individual slaves
40
+ uint8_t stat[STAT_NUM][(maxSlaves + 1 + 7 ) / 8 ];
30
41
31
42
// bool arrays for storing Modbus RTU status (responging or not responding). Array index corresponds to slave address.
32
- uint8_t responding[(maxSlaves + 1 + 7 ) / 8 ];
33
- uint8_t error[(maxSlaves + 1 + 7 ) / 8 ];
43
+ // uint8_t statOk[(maxSlaves + 1 + 7) / 8];
44
+ // uint8_t statError0B[(maxSlaves + 1 + 7) / 8];
45
+
34
46
uint8_t masks[8 ] = { 1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 };
35
47
36
48
typedef struct {
37
49
byte tid[2 ]; // MBAP Transaction ID
38
- byte uid; // MBAP Unit ID (address)
39
- byte PDUlen; // lenght of PDU (func + data) stored in queuePDUs
50
+ byte msgLen; // lenght of Modbus message stored in queuePDUs
40
51
IPAddress remIP; // remote IP for UDP client (UDP response is sent back to remote IP)
41
52
unsigned int remPort; // remote port for UDP client (UDP response is sent back to remote port)
42
53
byte clientNum; // TCP client who sent the request, UDP_REQUEST (0xFF) designates UDP client
54
+ byte atts; // attempts counter
43
55
} header;
44
56
45
57
// each request is stored in 3 queues (all queues are written to, read and deleted in sync)
46
58
CircularBuffer<header, reqQueueCount> queueHeaders; // queue of requests' headers and metadata (MBAP transaction ID, MBAP unit ID, PDU length, remIP, remPort, TCP client)
47
59
CircularBuffer<byte, reqQueueSize> queuePDUs; // queue of PDU data (function code, data)
48
- CircularBuffer<byte, reqQueueCount> queueRetries; // queue of retry counters
49
60
50
61
void recvUdp () {
51
62
unsigned int msgLength = Udp.parsePacket ();
@@ -128,9 +139,15 @@ void processRequests() {
128
139
// Insert scan request into queue
129
140
if (scanCounter != 0 && queueHeaders.available () > 1 && queuePDUs.available () > sizeof (scanCommand) + 1 ) {
130
141
// Store scan request in request queue
131
- queueHeaders.push (header{ { 0x00 , 0x00 }, scanCounter, sizeof (scanCommand) + 1 , {}, 0 , SCAN_REQUEST });
132
- queueRetries.push (localConfig.serialAttempts - 1 ); // scan requests are only sent once, so set "queueRetries" to one attempt below limit
133
- queuePDUs.push (scanCounter); // address of the scanned slave
142
+ queueHeaders.push (header{
143
+ { 0x00 , 0x00 }, // tid[2]
144
+ sizeof (scanCommand) + 1 , // msgLen
145
+ {}, // remIP
146
+ 0 , // remPort
147
+ SCAN_REQUEST, // clientNum
148
+ localConfig.serialAttempts - 1 , // atts
149
+ });
150
+ queuePDUs.push (scanCounter); // address of the scanned slave
134
151
for (byte i = 0 ; i < sizeof (scanCommand); i++) {
135
152
queuePDUs.push (scanCommand[i]);
136
153
}
@@ -140,24 +157,21 @@ void processRequests() {
140
157
// Optimize queue (prioritize requests from responding slaves) and trigger sending via serial
141
158
if (serialState == IDLE) { // send new data over serial only if we are not waiting for response
142
159
if (!queueHeaders.isEmpty ()) {
143
- boolean queueHasRespondingSlaves; // true if queue holds at least one request to responding slaves
144
- for (byte i = 0 ; i < queueHeaders.size (); i++) {
145
- if (getSlaveStatus (queueHeaders[i].uid , responding ) == true ) {
146
- queueHasRespondingSlaves = true ;
147
- break ;
148
- } else {
149
- queueHasRespondingSlaves = false ;
150
- }
151
- }
160
+ // boolean queueHasRespondingSlaves; // true if queue holds at least one request to responding slaves
161
+ // for (byte i = 0; i < queueHeaders.size(); i++) {
162
+ // if (getSlaveStatus(queueHeaders[i].uid, statOk ) == true) {
163
+ // queueHasRespondingSlaves = true;
164
+ // break;
165
+ // } else {
166
+ // queueHasRespondingSlaves = false;
167
+ // }
168
+ // }
152
169
serialState = SENDING; // trigger sendSerial()
153
170
}
154
171
}
155
172
}
156
173
157
174
byte checkRequest (const byte inBuffer[], unsigned int msgLength, const IPAddress remoteIP, const unsigned int remotePort, const byte clientNum) {
158
- byte address;
159
- if (localConfig.enableRtuOverTcp ) address = inBuffer[0 ];
160
- else address = inBuffer[6 ];
161
175
if (localConfig.enableRtuOverTcp ) { // check CRC for Modbus RTU over TCP/UDP
162
176
if (checkCRC (inBuffer, msgLength) == false ) {
163
177
return 0 ; // reject: do nothing and return no error code
@@ -167,37 +181,49 @@ byte checkRequest(const byte inBuffer[], unsigned int msgLength, const IPAddress
167
181
return 0 ; // reject: do nothing and return no error code
168
182
}
169
183
}
170
- msgLength = msgLength - ADDRESS_POS - (2 * localConfig.enableRtuOverTcp ); // in Modbus RTU over TCP/UDP do not store CRC
184
+ msgLength = msgLength - ADDRESS_POS - (2 * localConfig.enableRtuOverTcp ); // in Modbus RTU over TCP/UDP do not store CRC
171
185
// check if we have space in request queue
172
186
if (queueHeaders.available () < 1 || queuePDUs.available () < msgLength) {
173
- return 0x06 ; // return modbus error 6 (Slave Device Busy) - try again later
187
+ setSlaveStatus (inBuffer[ADDRESS_POS], STAT_ERROR_0A, true );
188
+ return 0x0A ; // return modbus error 0x0A (Gateway Overloaded)
174
189
}
175
190
// all checkes passed OK, we can store the incoming data in request queue
176
- // Store in request queue: 2 bytes MBAP Transaction ID (ignored in Modbus RTU over TCP); MBAP Unit ID (address); message length; remote IP; remote port; TCP client Number (socket) - 0xFF for UDP
177
- queueHeaders.push (header{ { inBuffer[0 ], inBuffer[1 ] }, inBuffer[ADDRESS_POS], (byte)msgLength, (IPAddress)remoteIP, (unsigned int )remotePort, (byte)clientNum });
178
- queueRetries.push (0 );
179
- for (byte i = 0 ; i < msgLength; i++) {
191
+ // Store in request queue
192
+ queueHeaders.push (header{
193
+ { inBuffer[0 ], inBuffer[1 ] }, // tid[2] (ignored in Modbus RTU over TCP/UDP)
194
+ (byte)msgLength, // msgLen
195
+ (IPAddress)remoteIP, // remIP
196
+ (unsigned int )remotePort, // remPort
197
+ (byte)clientNum, // clientNum
198
+ 0 , // atts
199
+ });
200
+ for (byte i = 0 ; i < msgLength; i++) {
180
201
queuePDUs.push (inBuffer[i + ADDRESS_POS]);
181
202
}
182
203
return 0 ;
183
204
}
184
205
185
206
void deleteRequest () // delete request from queue
186
207
{
187
- for (byte i = 0 ; i < queueHeaders.first ().PDUlen ; i++) {
208
+ for (byte i = 0 ; i < queueHeaders.first ().msgLen ; i++) {
188
209
queuePDUs.shift ();
189
210
}
190
211
queueHeaders.shift ();
191
- queueRetries.shift ();
192
212
}
193
213
194
- bool getSlaveStatus (const uint8_t index , const uint8_t status[] ) {
195
- if (index >= maxSlaves) return false ; // error
196
- return (status[index / 8 ] & masks[index & 7 ]) > 0 ;
214
+ bool getSlaveStatus (const uint8_t slave , const byte status) {
215
+ if (slave >= maxSlaves) return false ; // error
216
+ return (stat[ status][slave / 8 ] & masks[slave & 7 ]) > 0 ;
197
217
}
198
218
199
- void setSlaveStatus (const uint8_t index, uint8_t status[], const bool value) {
200
- if (index >= maxSlaves) return ; // error
201
- if (value == 0 ) status[index / 8 ] &= ~masks[index & 7 ];
202
- else status[index / 8 ] |= masks[index & 7 ];
219
+ void setSlaveStatus (const uint8_t slave, byte status, const bool value) {
220
+ if (slave >= maxSlaves) return ; // error
221
+ if (value == 0 ) {
222
+ stat[status][slave / 8 ] &= ~masks[slave & 7 ];
223
+ } else {
224
+ for (byte i = 0 ; i < STAT_NUM; i++) {
225
+ stat[i][slave / 8 ] &= ~masks[slave & 7 ]; // set all other flags to false
226
+ }
227
+ stat[status][slave / 8 ] |= masks[slave & 7 ];
228
+ }
203
229
}
0 commit comments