Skip to content

Commit a5c2fc8

Browse files
committed
Update readme and desription of functions..
1 parent 0152d03 commit a5c2fc8

File tree

7 files changed

+176
-147
lines changed

7 files changed

+176
-147
lines changed

README.md

Lines changed: 96 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -9,102 +9,145 @@ Change settings of your Arduino-based Modbus RTU to Modbus TCP/UDP gateway via w
99

1010
## What are the technical specifications?
1111

12-
* slaves are connected via RS485 interface
13-
* master(s) are connected via ethernet interface
14-
* up to 247 Modbus RTU slaves
15-
* up to 7 Modbus TCP masters
16-
* unlimited number of Modbus UDP masters
12+
* slaves are connected via RS485 interface:
13+
- up to 247 Modbus RTU slaves
14+
* master(s) are connected via ethernet interface:
15+
- up to 6 Modbus TCP masters (depending on hardware)
16+
- unlimited number of Modbus UDP masters
1717
* RS485 interface protocols:
1818
- Modbus RTU
19-
* Ethernet interface protocols:
19+
* ethernet interface protocols:
2020
- Modbus TCP
2121
- Modbus UDP
2222
- Modbus RTU over TCP
2323
- Modbus RTU over UDP
24-
* supports broadcast (slave address 0x00) and error codes
24+
* supports broadcast (slave address 0x00)
2525
* supports all Modbus function codes
26-
* diagnostics and Modbus RTU scan via web interface
27-
* optimized queue for Modbus requests (queue will accept only one requests to non-responding slaves)
28-
* settings can be changed via web interface, they are stored in EEPROM
29-
* user settings are retained during firmware upgrade (only in case of major VERSION change, Arduino loads factory defaults).
26+
* supports error codes:
27+
- codes 1~8 are forwarded from slaves
28+
- codes 10, 11 are generated by the gateway
29+
* diagnostics via web interface:
30+
- send Modbus request and recieve Modbus response
31+
- scan Modbus slaves on RS485 interface
32+
- requests queue status
33+
- error counts
34+
- content of the Modbus Status page is updated in the background (fetch API), javascript alert is shown if connection is lost
35+
* optimized TCP socket management (web interface and Modbus TCP):
36+
- gateway always listens for new web and Modbus TCP connections
37+
- existing connections are kept alive (persistent), unless the gateway runs out of available sockets
38+
- if there are no available sockets, oldest connections are closed after they are idle for a certain time (Modbus TCP idle timeout is configured in web UI)
39+
* optimized queue for Modbus requests:
40+
- queue will accept only one requests to a non-responding slave
41+
- requests to responding slaves are prioritized over requests to non-responding slaves
42+
* user settings:
43+
- can be changed via web interface (see bellow)
44+
- stored in EEPROM
45+
- retained during firmware upgrade (only in case of major version change, Arduino loads factory defaults)
46+
- all web interface inputs have proper validation
47+
- settings marked \* are only available if ENABLE_DHCP is defined in the sketch
48+
- settings marked \*\* are only available if ENABLE_EXTRA_DIAG is defined in the sketch
49+
* advanced settings:
50+
- can be changed in sketch (initial section of arduino-modbus-rtu-tcp-gateway.ino)
51+
- stored in flash memory
3052

3153
<img src="/pics/modbus1.png" alt="01" style="zoom:100%;" />
3254

33-
### System Info:
34-
35-
**Load Default Settings**. Loads default settings (see DEFAULT_CONFIG in arduino-modbus-rtu-tcp-gateway.ino)
55+
**Load Default Settings**. Loads default settings (see DEFAULT_CONFIG in arduino-modbus-rtu-tcp-gateway.ino). MAC address is retained.
3656

3757
**Reboot**.
3858

39-
**Generate New MAC**. Generate new MAC address. Fisrt 3 bytes are fixed 90:A2:DA, remaining 3 bytes are true random.
59+
**Generate New MAC**. Generate new MAC address. First 3 bytes are fixed 90:A2:DA, remaining 3 bytes are true random.
4060

4161
<img src="/pics/modbus2.png" alt="02" style="zoom:100%;" />
4262

43-
### Modbus Status:
63+
**Modbus RTU Request**. Send a Modbus RTU request directly from web UI. First byte (slave address) and second byte (function code) are mandatory, no need to calculate CRC. Gateway remembers last request for your convenience.
4464

45-
**Run Time**.
65+
**Modbus RTU Response**. Shows response to the last Modbus request. Response is shown in Modbus RTU format (incl. CRC). Due to memory limitations, only few initial bytes are shown.
4666

47-
**Modbus Statistics**.
67+
**Run Time**.\*\* Days, hours, minutes and seconds since boot or stat reset.
4868

49-
**Requests Queue**.
69+
**RTU Data**.\*\* Counter for bytes sent and received via RS485.
5070

51-
**Modbus TCP/UDP Masters**.
71+
**Ethernet Data**.\*\* Counter for bytes sent and received via Modbus TCP/UDP.
5272

53-
**Modbus Slaves**.
73+
**Requests Queue**. Monitors the internal request queue (buffer). The limits for bytes and for the number of requests stored in the queue can be configured in advanced settings.
5474

55-
**Scan Slaves**.
75+
**Modbus Statistics**. Counters for various errors. Insigned longs are used, rollover of counters is synchronized:
76+
* **Slave Responded**. Slave responded with a valid Modbus RTU response within response timeout.
77+
* **Slave Responded with Error (Codes 1~8)**. Slave responded, but with an error. For the list of error codes see https://en.wikipedia.org/wiki/Modbus#Exception_responses.
78+
* **Gateway Overloaded (Code 10)**. Request queue is full (either the number of bytes stored or the number of requests stored). Request was dropped and the gateway responded with an error code 10.
79+
* **Slave Failed to Respond (Code 11)**. Slave is not responding. Response timeouts have passed, all attempts have failed. The gateway responded with an error code 11.
80+
* **Invalid TCP/UDP Request**. Invalid request was received via TCP or UDP. Request was dropped, no response was sent by the gateway. Validation criteria depends on the Modbus mode:
81+
- Modbus TCP/UDP: MBAP header (protocol identifier is 0x0000, length is < 255 and corresponds to the number of bytes in the remainder of the Modbus request)
82+
- Modbus RTU over TCP/UDP: CRC ckeck
83+
* **Invalid RTU Response**. Invalid data were recieved via RS485. Usually caused by wrong Modbus RTU settings or too short response timeout (any response arriving after timeout is invalid). Validation criteria:
84+
- silence between individual bytes is shorter than char timeout specified in Modbus RTU standards
85+
- CRC check
86+
- slave address in the Modbus RTU response corresponds to the slave address in the request
87+
- response arrived before response timeout
88+
* **Response Timeout**. Slave failed to respond within the specified response timeout. New attempt follows (or error code 11 if all attempts were spent).
5689

57-
<img src="/pics/modbus3.png" alt="03" style="zoom:100%;" />
90+
**Modbus Masters**. Shows IP addresses for Modbus TCP or UDP masters:
91+
* **UDP**. Only the last Modbus UDP master is shown, because all UDP masters connect to the same socket.
92+
* **TCP**. All connected Modbus TCP masters are shown. Each Modbus TCP connection occupies one socket.
5893

59-
### IP Settings:
94+
**Modbus Slaves**. Shows the slave address (in hex) and the last status (error) for all slaves who responded to a slave scan or who were recipients of a Modbus request.
6095

61-
**Auto IP**. Only if ENABLE_DHCP. Once enabled, Arduino will receive IP, gateway, subnet and DNS from the DHCP server.
96+
**Scan Slaves**. An attempt is made to find Modbus RTU slaves connected to the RS485 interface:
97+
- scan is launched automaticaly after boot or manualy later
98+
- scans all slave addresses 1 - 247
99+
- dummy requests are sent to each slave address for two different Modbus functions (configured in advanced settings)
100+
- fixed response timeout (very short, configured in advanced settings), only one attempt
101+
- gateway marks the slave as "Slave Responded" if any response is received (even error)
62102

63-
**Static IP**.
103+
104+
<img src="/pics/modbus3.png" alt="03" style="zoom:100%;" />
105+
106+
**Auto IP**.\* Once enabled, Arduino will receive IP, gateway, subnet and DNS from the DHCP server.
107+
108+
**Static IP**. Set new static IP address. Gateway automatically redirect the web interface to the new IP.
64109

65110
**Submask**.
66111

67112
**Gateway**.
68113

69-
**DNS**. Only if ENABLE_DHCP.
114+
**DNS**.\*
70115

71116
<img src="/pics/modbus4.png" alt="04" style="zoom:100%;" />
72117

73-
### TCP/UDP Settings:
74-
75118
**Modbus TCP Port**.
76119

77-
**Modbus UDP Port**.
120+
**Modbus UDP Port**. Can be the same as Modbus TCP Port.
78121

79-
**Web Port**.
122+
**Web Port**. Gateway automatically redirect the web interface to the new Web UI port.
80123

81-
**Modbus Mode**. Modbus TCP/UDP or Modbus RTU over TCP/UDP.
124+
**Modbus Mode**. Modbus TCP/UDP or Modbus RTU over TCP/UDP. Be aware that "Modbus RTU over TCP/UDP" is not a standard Modbus protocol. In this mode, the gateway expects to recieve Modbus RTU request (incl. CRC) via TCP or UDP. Responses from RS485 line are forwarded as they are in Modbus RTU format (incl. CRC).
125+
126+
**Modbus TCP Idle Timeout**. Amount of time that a connection is always held alive (open) with no incoming traffic from a Modbus TCP master. This timeout should be longer than polling period (scan rate) set on your Modbus TCP master device.
82127

83128
<img src="/pics/modbus5.png" alt="05" style="zoom:100%;" />
84129

85-
### RS485 Settings:
130+
**Baud Rate**. Choose baud rate from a pre-aranged list. The list can be adjusted in advanced settings.
86131

87-
**Baud Rate**.
132+
**Data Bits**. Data bits available on arduino HW serial line: 5, 6, 7, 8.
88133

89-
**Data Bits**.
134+
**Parity**. Parity options available on arduino HW serial line: None, Even, Odd.
90135

91-
**Parity**.
136+
**Stop Bits**. 1 or 2 stop bits.
92137

93-
**Stop Bits**.
138+
**Inter-frame Delay**. Delay (ms) between the end of reading Modbus RTU frame and writing new frame. Higher Frame Delay is needed for RS485 modules with automatic flow control. Increase Frame Delay if you have very short polling period and Response Timeouts in stats. The minimum Inter-frame Delay is calculated from baud rate according to Modbus standards.
94139

95-
**Frame Delay**. Delay (ms) between the end of reading Modbus RTU frame and writing new frame. Higher Frame Delay is needed for RS485 modules with automatic flow control. Increase Frame Delay if you see Response Timeouts in stats.
140+
**Response Timeout**. Timeout for Modbus RTU response. Increase Response Timeout if you see Response Timeouts in Modbus statistics.
96141

97-
**Response Timeout**.
142+
**Attempts**. Number of attempts before error (Code 11) is sent back to the Modbus TCP/UDP master.
98143

99-
**Attempts**.
100-
101144
## How can I build it myself?
102145
Get the hardware (cheap clones from China are sufficient) and connect together:
103146

104-
* Arduino Nano, Uno or Mega (and possibly other). On Mega you have to configure Serial in ADVANCED SETTINGS in the sketch.
105-
* W5100, W5200 or W5500 based Ethernet shield (for Nano, I recommend W5500 Ethernet Shield from RobotDyn)
106-
* TTL to RS485 module:
107-
- with hardware automatic flow control (recommended)<br>
147+
* **Arduino Nano, Uno or Mega** (and possibly other). On Mega you have to configure Serial in advanced settings in the sketch.
148+
* **W5100, W5200 or W5500 based Ethernet shield**. The ubiquitous W5100 shield for Uno/Mega is sufficient. If available, I recommend W5500 Ethernet Shield. !!! ENC28J60 will not work !!!
149+
* **TTL to RS485 module**:
150+
- with hardware automatic flow control (recommended, available on Aliexpress)<br>
108151
Arduino <-> Module<br>
109152
Tx1 <-> Tx<br>
110153
Rx0 <-> Rx
@@ -113,13 +156,12 @@ Get the hardware (cheap clones from China are sufficient) and connect together:
113156
Tx1 <-> DI<br>
114157
Rx0 <-> RO<br>
115158
Pin 6 <-> DE,RE
116-
117159

118160
Here is my setup:
119-
Terminal shield + Arduino Nano + W5500 eth shield (RobotDyn) + TTL to RS485 module (HW automatic flow control)
161+
Terminal shield + Arduino Nano + W5500 ethernet shield (RobotDyn) + TTL to RS485 module (HW automatic flow control)
120162
<img src="/pics/HW.jpg" alt="01" style="zoom:100%;" />
121163

122-
Download this repository (all *.ino files) and open arduino-modbus-rtu-tcp-gateway.ino in Arduino IDE. Download all required libraries (both are available in "library manager"). If you want, you can check the default factory settings (can be later changed via web interface) and advanced settings (can only be changed in sketch). Compile and upload your program to Arduino. Connect your Arduino to ethernet, connect your Modbus RTU slaves to MAX485 module. Use your web browser to access the web interface on default IP http://192.168.1.254 Enjoy :-)
164+
Download this repository (all *.ino files) and open arduino-modbus-rtu-tcp-gateway.ino in Arduino IDE. Download all required libraries (they are available in "library manager"). If you want, you can check the default factory settings (can be later changed via web interface) and advanced settings (can only be changed in the sketch). Compile and upload your program to Arduino. Connect your Arduino to ethernet, connect your Modbus RTU slaves to MAX485 module. Use your web browser to access the web interface on default IP http://192.168.1.254 Enjoy :-)
123165

124166
## Where can I learn more about Modbus protocols?
125167

@@ -136,7 +178,7 @@ The key to success is:
136178

137179
* use StreamLib https://github.com/jandrassy/StreamLib
138180
* use F macros for your HTML code
139-
* use for() loop for repetitive code
181+
* use for() loop or dedicated functions for repetitive code
140182
* use POST method (rather than GET) for your webforms, see this tutorial https://werner.rothschopf.net/202003_arduino_webserver_post_en.htm
141183

142184
Big thanks to the authors of these libraries and tutorials!
@@ -147,27 +189,19 @@ Big thanks to the authors of these libraries and tutorials!
147189

148190
The code was tested on Arduino Nano, Uno and Mega, ethernet chips W5100 and W5500. It may work on other platforms, but:
149191

150-
* The pseudorandom generator (for random MAC) is seeded through watch dog timer interrupt - this will work only on Arduino (credits to https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library/arduino-random-seed)
192+
* The random number generator (for random MAC) is seeded through watch dog timer interrupt - this will work only on Arduino (credits to https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library/arduino-random-seed)
151193
* The restart function will also work only on Arduino.
152194

153-
#### Ethernet socket
195+
#### Ethernet sockets
154196

155-
The default Ethernet.h library determines MAX_SOCK_NUM by microcontroller RAM (not by Ethernet chip type). So if you use W5500 (which has 8 sockets available) on Arduino Nano, only 4 sockets will be used. If you want to force the library to use 8 sockets, redefine MAX_SOCK_NUM in advanced settings in the sketch.
197+
The number of used sockets is determined (by the Ethernet.h library) based on microcontroller RAM. Therefore, even if you use W5500 (which has 8 sockets available) on Arduino Nano, only 4 sockets will be used due to limited RAM on Nano.
156198

157199
#### Memory
158200

159-
Not everything could fit into the limited flash memory of Arduino Nano / Uno. If you have a microcontroller with more memory (such as Mega), you can enable extra features in the main sketch by uncommenting:
160-
161-
* #define ENABLE_DHCP will allow you to set "Auto IP" via DHCP in the IP settings web interface. Leased IP is automatically renewed.
162-
163-
<img src="/pics/modbus6.png" alt="06" style="zoom:100%;" />
164-
165-
* #define ENABLE_EXTRA_DIAG shows extra info on "Current status" page: per socket diagnostics, run time counter, ethernet data counter.
166-
167-
<img src="/pics/modbus1x.png" alt="01x" style="zoom:100%;" />
201+
Not everything could fit into the limited flash memory of Arduino Nano / Uno. If you have a microcontroller with more memory (such as Mega), you can enable extra settings in the main sketch by defining ENABLE_DHCP and/or ENABLE_EXTRA_DIAG in the sketch.
168202

169203
## Version history
170204

171205
For version history see:
172-
206+
173207
https://github.com/budulinek/arduino-modbus-rtu-tcp-gateway/blob/master/arduino-modbus-rtu-tcp-gateway/arduino-modbus-rtu-tcp-gateway.ino#L27

arduino-modbus-rtu-tcp-gateway/01-interfaces.ino

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,46 @@
11
/* *******************************************************************
22
Ethernet and serial interface functions
33
4-
startSerial
4+
startSerial()
55
- starts HW serial interface which we use for RS485 line
6-
- calculates Modbus RTU character timeout and frame delay
76
8-
startEthernet
7+
charTime(), charTimeOut(), frameDelay()
8+
- calculate Modbus RTU character timeout and inter-frame delay
9+
10+
startEthernet()
911
- initiates ethernet interface
1012
- if enabled, gets IP from DHCP
1113
- starts all servers (Modbus TCP, UDP, web server)
1214
13-
resetFunc
15+
resetFunc()
1416
- well... resets Arduino
1517
1618
maintainDhcp()
1719
- maintain DHCP lease
1820
19-
maintainUptime
21+
maintainUptime()
2022
- maintains up time in case of millis() overflow
2123
22-
maintainCounters
24+
maintainCounters(), rollover()
2325
- synchronizes roll-over of data counters to zero
2426
25-
CreateTrulyRandomSeed
26-
- seed pseudorandom generator using watch dog timer interrupt (works only on AVR)
27-
- see https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library/arduino-random-seed
27+
resetStats()
28+
- resets Modbus stats
2829
2930
generateMac()
3031
- generate random MAC using pseudo random generator (faster and than build-in random())
3132
33+
manageSockets()
34+
- closes sockets which are waiting to be closed or which refuse to close
35+
- forwards sockets with data available (webserver or Modbus TCP) for further processing
36+
- disconnects (closes) sockets which are too old / idle for too long
37+
- opens new sockets if needed (and if available)
38+
39+
CreateTrulyRandomSeed()
40+
- seed pseudorandom generator using watch dog timer interrupt (works only on AVR)
41+
- see https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library/arduino-random-seed
42+
43+
3244
+ preprocessor code for identifying microcontroller board
3345
3446
***************************************************************** */
@@ -250,7 +262,7 @@ void manageSockets() {
250262
W5100.execCmdSn(s, Sock_DISCON); // send DISCON command...
251263
lastSocketUse[s] = millis(); // record time at which it was sent...
252264
// status becomes LAST_ACK for short time
253-
} else if (((W5100.readSnPORT(s) == localConfig.webPort && sockAge > TCP_WEB_DISCON_AGE)
265+
} else if (((W5100.readSnPORT(s) == localConfig.webPort && sockAge > WEB_IDLE_TIMEOUT)
254266
|| (W5100.readSnPORT(s) == localConfig.tcpPort && sockAge > (localConfig.tcpTimeout * 1000UL)))
255267
&& sockAge > maxAge) {
256268
oldest = s; // record the socket number...

arduino-modbus-rtu-tcp-gateway/02-modbus-tcp.ino

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
/* *******************************************************************
22
Modbus TCP/UDP functions
33
4-
recvUdp
4+
recvUdp()
55
- receives Modbus UDP (or Modbus RTU over UDP) messages
66
- calls checkRequest
77
8-
recvTcp
8+
recvTcp()
99
- receives Modbus TCP (or Modbus RTU over TCP) messages
1010
- calls checkRequest
1111
12-
scanRequest
13-
- inserts scan request into queue
14-
15-
checkRequest
12+
checkRequest()
1613
- checks Modbus TCP/UDP requests (correct MBAP header, CRC in case of Modbus RTU over TCP/UDP)
1714
- checks availability of queue
18-
- stores requests in queue or returns an error
15+
- stores requests into queue or returns an error
1916
20-
deleteRequest
17+
scanRequest()
18+
- inserts scan request into queue
19+
20+
deleteRequest()
2121
- deletes requests from queue
2222
23-
getSlaveStatus, setSlaveStatus
23+
clearQueue()
24+
- clears queue and corresponding counters
25+
26+
getSlaveStatus(), setSlaveStatus()
2427
- read from and write to bool array
2528
2629
***************************************************************** */
@@ -126,7 +129,7 @@ void scanRequest() {
126129
queueHeaders.push(header{
127130
{ 0x00, 0x00 }, // tid[2]
128131
sizeof(scanCommand) + 1, // msgLen
129-
{}, // remIP
132+
{ 0, 0, 0, 0 }, // remIP
130133
0, // remPort
131134
SCAN_REQUEST, // requestType
132135
0, // atts
@@ -167,7 +170,7 @@ byte checkRequest(byte inBuffer[], unsigned int msgLength, const uint32_t remote
167170
// allow only one request to non responding slaves
168171
if (getSlaveStatus(inBuffer[addressPos], SLAVE_ERROR_0B_QUEUE)) {
169172
errorCount[SLAVE_ERROR_0B]++;
170-
return 0x0B; // return modbus error 11 (Gateway Target Device Failed to Respond) - usually means that target device (address) is not present
173+
return 0x0B; // return modbus error 11 (Gateway Target Device Failed to Respond)
171174
} else if (getSlaveStatus(inBuffer[addressPos], SLAVE_ERROR_0B)) {
172175
setSlaveStatus(inBuffer[addressPos], SLAVE_ERROR_0B_QUEUE, true, false);
173176
} else {

0 commit comments

Comments
 (0)