4
4
recvUdp
5
5
- receives Modbus UDP (or Modbus RTU over UDP) messages
6
6
- calls checkRequest
7
- - stores requests in queue or replies with error
8
7
9
8
recvTcp
10
9
- receives Modbus TCP (or Modbus RTU over TCP) messages
11
10
- calls checkRequest
12
- - stores requests in queue or replies with error
13
11
14
12
processRequests
15
13
- inserts scan request into queue
18
16
checkRequest
19
17
- checks Modbus TCP/UDP requests (correct MBAP header, CRC in case of Modbus RTU over TCP/UDP)
20
18
- checks availability of queue
19
+ - stores requests in queue or returns an error
21
20
22
21
deleteRequest
23
22
- deletes requests from queue
@@ -44,44 +43,37 @@ typedef struct {
44
43
CircularBuffer<header, reqQueueCount> queueHeaders; // queue of requests' headers and metadata (MBAP transaction ID, MBAP unit ID, PDU length, remIP, remPort, TCP client)
45
44
CircularBuffer<byte, reqQueueSize> queuePDUs; // queue of PDU data (function code, data)
46
45
CircularBuffer<byte, reqQueueCount> queueRetries; // queue of retry counters
46
+ byte pduStart; // first byte of Protocol Data Unit (i.e. Function code)
47
47
48
48
void recvUdp () {
49
49
unsigned int packetSize = Udp.parsePacket ();
50
50
if (packetSize) {
51
51
#ifdef ENABLE_EXTRA_DIAG
52
52
ethRxCount += packetSize;
53
53
#endif /* ENABLE_EXTRA_DIAG */
54
- byte udpInBuffer [modbusSize + 4 ]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
55
- // Modbus TCP/UDP frame: [0][1] transaction ID, [2][3] protocol ID, [4][5] length and [6] unit ID (address).....
56
- // Modbus RTU frame: [0] address.....
57
- Udp.read (udpInBuffer , sizeof (udpInBuffer ));
54
+ byte inBuffer [modbusSize + 4 ]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
55
+ // Modbus TCP/UDP frame: [0][1] transaction ID, [2][3] protocol ID, [4][5] length and [6] unit ID (address)..... no CRC
56
+ // Modbus RTU frame: [0] address.....[n-1][n] CRC
57
+ Udp.read (inBuffer , sizeof (inBuffer ));
58
58
Udp.flush ();
59
-
60
- byte errorCode = checkRequest (udpInBuffer, packetSize);
61
- byte pduStart; // first byte of Protocol Data Unit (i.e. Function code)
62
59
if (localConfig.enableRtuOverTcp ) pduStart = 1 ; // In Modbus RTU, Function code is second byte (after address)
63
60
else pduStart = 7 ; // In Modbus TCP/UDP, Function code is 8th byte (after address)
64
- if (errorCode == 0 ) {
65
- // 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 });
67
- queueRetries.push (0 );
68
- for (byte i = 0 ; i < (byte)(packetSize - pduStart); i++) {
69
- queuePDUs.push (udpInBuffer[i + pduStart]);
70
- }
71
- } else if (errorCode != 0xFF ) {
61
+
62
+ byte errorCode = checkRequest (inBuffer, packetSize, (IPAddress)Udp.remoteIP (), Udp.remotePort (), UDP_REQUEST);
63
+ if (errorCode) {
72
64
// send back message with error code
73
65
Udp.beginPacket (Udp.remoteIP (), Udp.remotePort ());
74
66
if (!localConfig.enableRtuOverTcp ) {
75
- Udp.write (udpInBuffer , 5 );
67
+ Udp.write (inBuffer , 5 );
76
68
Udp.write (0x03 );
77
69
}
78
- Udp.write (udpInBuffer [pduStart - 1 ]); // address
79
- Udp.write (udpInBuffer [pduStart] + 0x80 ); // function + 0x80
70
+ Udp.write (inBuffer [pduStart - 1 ]); // address
71
+ Udp.write (inBuffer [pduStart] + 0x80 ); // function + 0x80
80
72
Udp.write (errorCode);
81
73
if (localConfig.enableRtuOverTcp ) {
82
74
crc = 0xFFFF ;
83
- calculateCRC (udpInBuffer [pduStart - 1 ]);
84
- calculateCRC (udpInBuffer [pduStart] + 0x80 );
75
+ calculateCRC (inBuffer [pduStart - 1 ]);
76
+ calculateCRC (inBuffer [pduStart] + 0x80 );
85
77
calculateCRC (errorCode);
86
78
Udp.write (lowByte (crc)); // send CRC, low byte first
87
79
Udp.write (highByte (crc));
@@ -95,43 +87,36 @@ void recvUdp() {
95
87
}
96
88
}
97
89
98
-
99
90
void recvTcp () {
100
91
EthernetClient client = modbusServer.available ();
101
92
if (client) {
102
93
unsigned int packetSize = client.available ();
103
94
#ifdef ENABLE_EXTRA_DIAG
104
95
ethRxCount += packetSize;
105
96
#endif /* ENABLE_EXTRA_DIAG */
106
- byte tcpInBuffer [modbusSize + 4 ]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
97
+ byte inBuffer [modbusSize + 4 ]; // Modbus TCP frame is 4 bytes longer than Modbus RTU frame
107
98
// Modbus TCP/UDP frame: [0][1] transaction ID, [2][3] protocol ID, [4][5] length and [6] unit ID (address).....
108
99
// Modbus RTU frame: [0] address.....
109
- client.read (tcpInBuffer , sizeof (tcpInBuffer ));
100
+ client.read (inBuffer , sizeof (inBuffer ));
110
101
client.flush ();
111
- byte errorCode = checkRequest (tcpInBuffer, packetSize);
112
- byte pduStart; // first byte of Protocol Data Unit (i.e. Function code)
102
+
113
103
if (localConfig.enableRtuOverTcp ) pduStart = 1 ; // In Modbus RTU, Function code is second byte (after address)
114
104
else pduStart = 7 ; // In Modbus TCP/UDP, Function code is 8th byte (after address)
115
- if (errorCode == 0 ) {
116
- // 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
117
- queueHeaders.push (header{ { tcpInBuffer[0 ], tcpInBuffer[1 ] }, tcpInBuffer[pduStart - 1 ], (byte)(packetSize - pduStart), {}, 0 , client.getSocketNumber () });
118
- queueRetries.push (0 );
119
- for (byte i = 0 ; i < packetSize - pduStart; i++) {
120
- queuePDUs.push (tcpInBuffer[i + pduStart]);
121
- }
122
- } else if (errorCode != 0xFF ) {
105
+
106
+ byte errorCode = checkRequest (inBuffer, packetSize, (IPAddress){}, 0 , client.getSocketNumber ());
107
+ if (errorCode) {
123
108
// send back message with error code
124
109
if (!localConfig.enableRtuOverTcp ) {
125
- client.write (tcpInBuffer , 5 );
110
+ client.write (inBuffer , 5 );
126
111
client.write (0x03 );
127
112
}
128
- client.write (tcpInBuffer [pduStart - 1 ]); // address
129
- client.write (tcpInBuffer [pduStart] + 0x80 ); // function + 0x80
113
+ client.write (inBuffer [pduStart - 1 ]); // address
114
+ client.write (inBuffer [pduStart] + 0x80 ); // function + 0x80
130
115
client.write (errorCode);
131
116
if (localConfig.enableRtuOverTcp ) {
132
117
crc = 0xFFFF ;
133
- calculateCRC (tcpInBuffer [pduStart - 1 ]);
134
- calculateCRC (tcpInBuffer [pduStart] + 0x80 );
118
+ calculateCRC (inBuffer [pduStart - 1 ]);
119
+ calculateCRC (inBuffer [pduStart] + 0x80 );
135
120
calculateCRC (errorCode);
136
121
client.write (lowByte (crc)); // send CRC, low byte first
137
122
client.write (highByte (crc));
@@ -156,7 +141,6 @@ void processRequests() {
156
141
scanCounter++;
157
142
if (scanCounter == maxSlaves + 1 ) scanCounter = 0 ;
158
143
}
159
-
160
144
// Optimize queue (prioritize requests from responding slaves) and trigger sending via serial
161
145
if (serialState == IDLE) { // send new data over serial only if we are not waiting for response
162
146
if (!queueHeaders.isEmpty ()) {
@@ -174,25 +158,30 @@ void processRequests() {
174
158
}
175
159
}
176
160
177
- byte checkRequest (byte buffer [], unsigned int bufferSize ) {
161
+ byte checkRequest (byte inBuffer [], unsigned int packetSize, IPAddress remoteIP, unsigned int remotePort, byte clientNum ) {
178
162
byte address;
179
- if (localConfig.enableRtuOverTcp ) address = buffer[0 ];
180
- else address = buffer[6 ];
181
-
163
+ if (localConfig.enableRtuOverTcp ) address = inBuffer[0 ];
164
+ else address = inBuffer[6 ];
182
165
if (localConfig.enableRtuOverTcp ) { // check CRC for Modbus RTU over TCP/UDP
183
- if (checkCRC (buffer, bufferSize ) == false ) {
184
- return 0xFF ; // reject: do nothing and return no error code
166
+ if (checkCRC (inBuffer, packetSize ) == false ) {
167
+ return 0 ; // reject: do nothing and return no error code
185
168
}
186
169
} else { // check MBAP header structure for Modbus TCP/UDP
187
- if (buffer [2 ] != 0x00 || buffer [3 ] != 0x00 || buffer [4 ] != 0x00 || buffer [5 ] != bufferSize - 6 ) {
188
- return 0xFF ; // reject: do nothing and return no error code
170
+ if (inBuffer [2 ] != 0x00 || inBuffer [3 ] != 0x00 || inBuffer [4 ] != 0x00 || inBuffer [5 ] != packetSize - 6 ) {
171
+ return 0 ; // reject: do nothing and return no error code
189
172
}
190
173
}
191
174
// check if we have space in request queue
192
- if (queueHeaders.available () < 1 || (localConfig.enableRtuOverTcp && queuePDUs.available () < bufferSize - 1 ) || (!localConfig.enableRtuOverTcp && queuePDUs.available () < bufferSize - 7 )) {
175
+ if (queueHeaders.available () < 1 || (localConfig.enableRtuOverTcp && queuePDUs.available () < packetSize - 1 ) || (!localConfig.enableRtuOverTcp && queuePDUs.available () < packetSize - 7 )) {
193
176
return 0x06 ; // return modbus error 6 (Slave Device Busy) - try again later
194
177
}
195
178
// al checkes passed OK, we can store the incoming data in request queue
179
+ // 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
180
+ queueHeaders.push (header{ { inBuffer[0 ], inBuffer[1 ] }, inBuffer[pduStart - 1 ], (byte)(packetSize - pduStart), (IPAddress)remoteIP, (unsigned int )remotePort, (byte)clientNum });
181
+ queueRetries.push (0 );
182
+ for (byte i = 0 ; i < packetSize - pduStart; i++) {
183
+ queuePDUs.push (inBuffer[i + pduStart]);
184
+ }
196
185
return 0 ;
197
186
}
198
187
0 commit comments