29
29
30
30
// bool array for storing Modbus RTU status (responging or not responding). Array index corresponds to slave address.
31
31
uint8_t slavesResponding[(maxSlaves + 1 + 7 ) / 8 ];
32
- uint8_t masks[8 ] = {1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 };
32
+ uint8_t masks[8 ] = { 1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 };
33
33
34
34
typedef struct {
35
- byte tid[2 ]; // MBAP Transaction ID
36
- byte uid; // MBAP Unit ID (address)
37
- byte PDUlen; // lenght of PDU (func + data) stored in queuePDUs
38
- IPAddress remIP; // remote IP for UDP client (UDP response is sent back to remote IP)
39
- unsigned int remPort; // remote port for UDP client (UDP response is sent back to remote port)
40
- byte clientNum; // TCP client who sent the request, UDP_REQUEST (0xFF) designates UDP client
35
+ byte tid[2 ]; // MBAP Transaction ID
36
+ byte uid; // MBAP Unit ID (address)
37
+ byte PDUlen; // lenght of PDU (func + data) stored in queuePDUs
38
+ IPAddress remIP; // remote IP for UDP client (UDP response is sent back to remote IP)
39
+ unsigned int remPort; // remote port for UDP client (UDP response is sent back to remote port)
40
+ byte clientNum; // TCP client who sent the request, UDP_REQUEST (0xFF) designates UDP client
41
41
} header;
42
42
43
43
// each request is stored in 3 queues (all queues are written to, read and deleted in sync)
44
- CircularBuffer<header, reqQueueCount> queueHeaders; // queue of requests' headers and metadata (MBAP transaction ID, MBAP unit ID, PDU length, remIP, remPort, TCP client)
45
- CircularBuffer<byte, reqQueueSize> queuePDUs; // queue of PDU data (function code, data)
46
- CircularBuffer<byte, reqQueueCount> queueRetries; // queue of retry counters
44
+ CircularBuffer<header, reqQueueCount> queueHeaders; // queue of requests' headers and metadata (MBAP transaction ID, MBAP unit ID, PDU length, remIP, remPort, TCP client)
45
+ CircularBuffer<byte, reqQueueSize> queuePDUs; // queue of PDU data (function code, data)
46
+ CircularBuffer<byte, reqQueueCount> queueRetries; // queue of retry counters
47
47
48
- void recvUdp ()
49
- {
48
+ void recvUdp () {
50
49
unsigned int packetSize = Udp.parsePacket ();
51
- if (packetSize)
52
- {
50
+ if (packetSize) {
53
51
ethRxCount += packetSize;
54
- byte udpInBuffer[modbusSize + 4 ]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
52
+ byte udpInBuffer[modbusSize + 4 ]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
55
53
// Modbus TCP/UDP frame: [0][1] transaction ID, [2][3] protocol ID, [4][5] length and [6] unit ID (address).....
56
54
// Modbus RTU frame: [0] address.....
57
55
Udp.read (udpInBuffer, sizeof (udpInBuffer));
58
56
Udp.flush ();
59
57
60
58
byte errorCode = checkRequest (udpInBuffer, packetSize);
61
- byte pduStart; // first byte of Protocol Data Unit (i.e. Function code)
62
- if (localConfig.enableRtuOverTcp ) pduStart = 1 ; // In Modbus RTU, Function code is second byte (after address)
63
- else pduStart = 7 ; // In Modbus TCP/UDP, Function code is 8th byte (after address)
59
+ byte pduStart; // first byte of Protocol Data Unit (i.e. Function code)
60
+ if (localConfig.enableRtuOverTcp ) pduStart = 1 ; // In Modbus RTU, Function code is second byte (after address)
61
+ else pduStart = 7 ; // In Modbus TCP/UDP, Function code is 8th byte (after address)
64
62
if (errorCode == 0 ) {
65
63
// Store in request queue: 2 bytes MBAP Transaction ID (ignored in Modbus RTU over TCP); MBAP Unit ID (address); PDUlen (func + data);remote IP; remote port; TCP client Number (socket) - 0xFF for UDP
66
- queueHeaders.push (header {{ udpInBuffer[0 ], udpInBuffer[1 ]}, udpInBuffer[pduStart - 1 ], (byte)(packetSize - pduStart), Udp.remoteIP (), Udp.remotePort (), UDP_REQUEST});
64
+ queueHeaders.push (header{ { udpInBuffer[0 ], udpInBuffer[1 ] }, udpInBuffer[pduStart - 1 ], (byte)(packetSize - pduStart), Udp.remoteIP (), Udp.remotePort (), UDP_REQUEST });
67
65
queueRetries.push (0 );
68
66
for (byte i = 0 ; i < (byte)(packetSize - pduStart); i++) {
69
67
queuePDUs.push (udpInBuffer[i + pduStart]);
@@ -75,15 +73,15 @@ void recvUdp()
75
73
Udp.write (udpInBuffer, 5 );
76
74
Udp.write (0x03 );
77
75
}
78
- Udp.write (udpInBuffer[pduStart - 1 ]); // address
79
- Udp.write (udpInBuffer[pduStart] + 0x80 ); // function + 0x80
76
+ Udp.write (udpInBuffer[pduStart - 1 ]); // address
77
+ Udp.write (udpInBuffer[pduStart] + 0x80 ); // function + 0x80
80
78
Udp.write (errorCode);
81
79
if (localConfig.enableRtuOverTcp ) {
82
80
crc = 0xFFFF ;
83
81
calculateCRC (udpInBuffer[pduStart - 1 ]);
84
82
calculateCRC (udpInBuffer[pduStart] + 0x80 );
85
83
calculateCRC (errorCode);
86
- Udp.write (lowByte (crc)); // send CRC, low byte first
84
+ Udp.write (lowByte (crc)); // send CRC, low byte first
87
85
Udp.write (highByte (crc));
88
86
}
89
87
Udp.endPacket ();
@@ -96,24 +94,23 @@ void recvUdp()
96
94
}
97
95
98
96
99
- void recvTcp ()
100
- {
97
+ void recvTcp () {
101
98
EthernetClient client = modbusServer.available ();
102
99
if (client) {
103
100
unsigned int packetSize = client.available ();
104
101
ethRxCount += packetSize;
105
- byte tcpInBuffer[modbusSize + 4 ]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
102
+ byte tcpInBuffer[modbusSize + 4 ]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
106
103
// Modbus TCP/UDP frame: [0][1] transaction ID, [2][3] protocol ID, [4][5] length and [6] unit ID (address).....
107
104
// Modbus RTU frame: [0] address.....
108
105
client.read (tcpInBuffer, sizeof (tcpInBuffer));
109
106
client.flush ();
110
107
byte errorCode = checkRequest (tcpInBuffer, packetSize);
111
- byte pduStart; // first byte of Protocol Data Unit (i.e. Function code)
112
- if (localConfig.enableRtuOverTcp ) pduStart = 1 ; // In Modbus RTU, Function code is second byte (after address)
113
- else pduStart = 7 ; // In Modbus TCP/UDP, Function code is 8th byte (after address)
108
+ byte pduStart; // first byte of Protocol Data Unit (i.e. Function code)
109
+ if (localConfig.enableRtuOverTcp ) pduStart = 1 ; // In Modbus RTU, Function code is second byte (after address)
110
+ else pduStart = 7 ; // In Modbus TCP/UDP, Function code is 8th byte (after address)
114
111
if (errorCode == 0 ) {
115
112
// Store in request queue: 2 bytes MBAP Transaction ID (ignored in Modbus RTU over TCP); MBAP Unit ID (address); PDUlen (func + data);remote IP; remote port; TCP client Number (socket) - 0xFF for UDP
116
- queueHeaders.push (header {{ tcpInBuffer[0 ], tcpInBuffer[1 ]}, tcpInBuffer[pduStart - 1 ], (byte)(packetSize - pduStart), {}, 0 , client.getSocketNumber ()});
113
+ queueHeaders.push (header{ { tcpInBuffer[0 ], tcpInBuffer[1 ] }, tcpInBuffer[pduStart - 1 ], (byte)(packetSize - pduStart), {}, 0 , client.getSocketNumber () });
117
114
queueRetries.push (0 );
118
115
for (byte i = 0 ; i < packetSize - pduStart; i++) {
119
116
queuePDUs.push (tcpInBuffer[i + pduStart]);
@@ -124,15 +121,15 @@ void recvTcp()
124
121
client.write (tcpInBuffer, 5 );
125
122
client.write (0x03 );
126
123
}
127
- client.write (tcpInBuffer[pduStart - 1 ]); // address
128
- client.write (tcpInBuffer[pduStart] + 0x80 ); // function + 0x80
124
+ client.write (tcpInBuffer[pduStart - 1 ]); // address
125
+ client.write (tcpInBuffer[pduStart] + 0x80 ); // function + 0x80
129
126
client.write (errorCode);
130
127
if (localConfig.enableRtuOverTcp ) {
131
128
crc = 0xFFFF ;
132
129
calculateCRC (tcpInBuffer[pduStart - 1 ]);
133
130
calculateCRC (tcpInBuffer[pduStart] + 0x80 );
134
131
calculateCRC (errorCode);
135
- client.write (lowByte (crc)); // send CRC, low byte first
132
+ client.write (lowByte (crc)); // send CRC, low byte first
136
133
client.write (highByte (crc));
137
134
}
138
135
#ifdef ENABLE_EXTRA_DIAG
@@ -143,13 +140,12 @@ void recvTcp()
143
140
}
144
141
}
145
142
146
- void processRequests ()
147
- {
143
+ void processRequests () {
148
144
// Insert scan request into queue
149
145
if (scanCounter != 0 && queueHeaders.available () > 1 && queuePDUs.available () > 1 ) {
150
146
// Store scan request in request queue
151
- queueHeaders.push (header {{ 0x00 , 0x00 }, scanCounter, sizeof (scanCommand), {}, 0 , SCAN_REQUEST});
152
- queueRetries.push (localConfig.serialRetry - 1 ); // scan requests are only sent once, so set "queueRetries" to one attempt below limit
147
+ queueHeaders.push (header{ { 0x00 , 0x00 }, scanCounter, sizeof (scanCommand), {}, 0 , SCAN_REQUEST });
148
+ queueRetries.push (localConfig.serialRetry - 1 ); // scan requests are only sent once, so set "queueRetries" to one attempt below limit
153
149
for (byte i = 0 ; i < sizeof (scanCommand); i++) {
154
150
queuePDUs.push (scanCommand[i]);
155
151
}
@@ -158,9 +154,9 @@ void processRequests()
158
154
}
159
155
160
156
// Optimize queue (prioritize requests from responding slaves) and trigger sending via serial
161
- if (serialState == IDLE) { // send new data over serial only if we are not waiting for response
157
+ if (serialState == IDLE) { // send new data over serial only if we are not waiting for response
162
158
if (!queueHeaders.isEmpty ()) {
163
- boolean queueHasRespondingSlaves; // true if queue holds at least one request to responding slaves
159
+ boolean queueHasRespondingSlaves; // true if queue holds at least one request to responding slaves
164
160
for (byte i = 0 ; i < queueHeaders.size (); i++) {
165
161
if (getSlaveResponding (queueHeaders[i].uid ) == true ) {
166
162
queueHasRespondingSlaves = true ;
@@ -177,7 +173,7 @@ void processRequests()
177
173
queueRetries.push (queueRetries.shift ());
178
174
queueHeaders.push (queueHeaders.shift ());
179
175
}
180
- serialState = SENDING; // trigger sendSerial()
176
+ serialState = SENDING; // trigger sendSerial()
181
177
}
182
178
}
183
179
}
@@ -187,31 +183,31 @@ byte checkRequest(byte buffer[], unsigned int bufferSize) {
187
183
if (localConfig.enableRtuOverTcp ) address = buffer[0 ];
188
184
else address = buffer[6 ];
189
185
190
- if (localConfig.enableRtuOverTcp ) { // check CRC for Modbus RTU over TCP/UDP
186
+ if (localConfig.enableRtuOverTcp ) { // check CRC for Modbus RTU over TCP/UDP
191
187
if (checkCRC (buffer, bufferSize) == false ) {
192
- return 0xFF ; // reject: do nothing and return no error code
188
+ return 0xFF ; // reject: do nothing and return no error code
193
189
}
194
- } else { // check MBAP header structure for Modbus TCP/UDP
190
+ } else { // check MBAP header structure for Modbus TCP/UDP
195
191
if (buffer[2 ] != 0x00 || buffer[3 ] != 0x00 || buffer[4 ] != 0x00 || buffer[5 ] != bufferSize - 6 ) {
196
- return 0xFF ; // reject: do nothing and return no error code
192
+ return 0xFF ; // reject: do nothing and return no error code
197
193
}
198
194
}
199
- if (queueHeaders.isEmpty () == false && getSlaveResponding (address) == false ) { // allow only one request to non responding slaves
200
- for (byte j = queueHeaders.size (); j > 0 ; j--) { // start searching from tail because requests to non-responsive slaves are usually towards the tail of the queue
195
+ if (queueHeaders.isEmpty () == false && getSlaveResponding (address) == false ) { // allow only one request to non responding slaves
196
+ for (byte j = queueHeaders.size (); j > 0 ; j--) { // start searching from tail because requests to non-responsive slaves are usually towards the tail of the queue
201
197
if (queueHeaders[j - 1 ].uid == address) {
202
- return 0x0B ; // return modbus error 11 (Gateway Target Device Failed to Respond) - usually means that target device (address) is not present
198
+ return 0x0B ; // return modbus error 11 (Gateway Target Device Failed to Respond) - usually means that target device (address) is not present
203
199
}
204
200
}
205
201
}
206
202
// check if we have space in request queue
207
203
if (queueHeaders.available () < 1 || (localConfig.enableRtuOverTcp && queuePDUs.available () < bufferSize - 1 ) || (!localConfig.enableRtuOverTcp && queuePDUs.available () < bufferSize - 7 )) {
208
- return 0x06 ; // return modbus error 6 (Slave Device Busy) - try again later
204
+ return 0x06 ; // return modbus error 6 (Slave Device Busy) - try again later
209
205
}
210
206
// al checkes passed OK, we can store the incoming data in request queue
211
207
return 0 ;
212
208
}
213
209
214
- void deleteRequest () // delete request from queue
210
+ void deleteRequest () // delete request from queue
215
211
{
216
212
for (byte i = 0 ; i < queueHeaders.first ().PDUlen ; i++) {
217
213
queuePDUs.shift ();
@@ -221,16 +217,14 @@ void deleteRequest() // delete request from queue
221
217
}
222
218
223
219
224
- bool getSlaveResponding (const uint8_t index)
225
- {
226
- if (index >= maxSlaves) return false ; // error
220
+ bool getSlaveResponding (const uint8_t index) {
221
+ if (index >= maxSlaves) return false ; // error
227
222
return (slavesResponding[index / 8 ] & masks[index & 7 ]) > 0 ;
228
223
}
229
224
230
225
231
- void setSlaveResponding (const uint8_t index, const bool value)
232
- {
233
- if (index >= maxSlaves) return ; // error
226
+ void setSlaveResponding (const uint8_t index, const bool value) {
227
+ if (index >= maxSlaves) return ; // error
234
228
if (value == 0 ) slavesResponding[index / 8 ] &= ~masks[index & 7 ];
235
229
else slavesResponding[index / 8 ] |= masks[index & 7 ];
236
230
}
0 commit comments