Skip to content

Commit 93f2740

Browse files
committed
HTML code (page scrolling)
1 parent ac50117 commit 93f2740

File tree

4 files changed

+65
-63
lines changed

4 files changed

+65
-63
lines changed

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,31 @@ void startSerial() {
4242
#endif /* RS485_CONTROL_PIN */
4343
}
4444

45-
// time to send 1 character over serial in microseconds
46-
unsigned long charTime() {
45+
// time to send 1 character over serial in microseconds (never above 40 000 so we can use unsigned int)
46+
unsigned long charTime() {
4747
byte bits = // number of bits per character (11 in default Modbus RTU settings)
4848
1 + // start bit
4949
(((localConfig.serialConfig & 0x06) >> 1) + 5) + // data bits
5050
(((localConfig.serialConfig & 0x08) >> 3) + 1); // stop bits
5151
if (((localConfig.serialConfig & 0x30) >> 4) > 1) bits += 1; // parity bit (if present)
52-
return ((unsigned long)bits * 1000000UL) / localConfig.baud;
52+
return (bits * 1000000UL) / (unsigned long)localConfig.baud;
53+
}
54+
55+
unsigned long charTimeOut() {
56+
if (localConfig.baud <= 19200) {
57+
return 1.5 * charTime(); // inter-character time-out should be 1,5T
58+
} else {
59+
return 750;
60+
}
61+
}
62+
63+
unsigned long frameDelay() {
64+
if (FRAME_DELAY) return FRAME_DELAY * 1000UL;
65+
if (localConfig.baud <= 19200) {
66+
return 3.5 * charTime(); // inter-frame delay should be 3,5T
67+
} else {
68+
return 1750;
69+
}
5370
}
5471

5572
void startEthernet() {
@@ -71,8 +88,8 @@ void startEthernet() {
7188
Ethernet.begin(mac, localConfig.ip, localConfig.dns, localConfig.gateway, localConfig.subnet);
7289
}
7390
#else /* ENABLE_DHCP */
74-
Ethernet.begin(mac, localConfig.ip, localConfig.dns, localConfig.gateway, localConfig.subnet);
75-
localConfig.enableDhcp = false; // Make sure Dhcp is disabled in config
91+
// Ethernet.begin(mac, localConfig.ip, localConfig.dns, localConfig.gateway, localConfig.subnet);
92+
Ethernet.begin(mac, localConfig.ip, {}, localConfig.gateway, localConfig.subnet);
7693
#endif /* ENABLE_DHCP */
7794
modbusServer = EthernetServer(localConfig.tcpPort);
7895
webServer = EthernetServer(localConfig.webPort);
@@ -246,6 +263,3 @@ ISR(WDT_vect) {
246263
#endif
247264

248265
#endif
249-
250-
251-

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

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
int rxNdx = 0;
2020
int txNdx = 0;
21-
bool rxErr = false;
2221

2322
MicroTimer recvTimer;
2423
MicroTimer sendTimer;
@@ -65,11 +64,9 @@ void sendSerial() {
6564
// this if statement is not very reliable (too fast)
6665
// Serial.isFlushed() method is needed....see https://github.com/arduino/Arduino/pull/3737
6766
txNdx = 0;
68-
unsigned long delay = 0;
6967
#ifdef RS485_CONTROL_PIN
70-
delay = 3.5 * charTime(); // inter-frame delay should be 3,5T
71-
#endif /* RS485_CONTROL_PIN */
72-
sendTimer.sleep(delay);
68+
sendTimer.sleep(charTimeOut()); // very short delay before we toggle the RS485_CONTROL_PIN and disable RS485 transmit
69+
#endif /* RS485_CONTROL_PIN */
7370
serialState++;
7471
}
7572
}
@@ -86,9 +83,9 @@ void sendSerial() {
8683
myHeader.atts++;
8784
queueHeaders.shift();
8885
queueHeaders.unshift(myHeader);
89-
unsigned long delay = (unsigned long)localConfig.serialTimeout * 1000;
90-
// if (myHeader.requestType & SCAN_REQUEST) delay = SCAN_TIMEOUT * 1000; // fixed timeout for scan requests
91-
sendTimer.sleep(delay);
86+
unsigned long delay = localConfig.serialTimeout;
87+
if (myHeader.requestType & SCAN_REQUEST) delay = SCAN_TIMEOUT; // fixed timeout for scan requests
88+
sendTimer.sleep(delay * 1000UL);
9289
serialState++;
9390
}
9491
break;
@@ -134,7 +131,7 @@ void sendSerial() {
134131
}
135132
}
136133
deleteRequest();
137-
errorTimeoutCount++;
134+
errorTimeoutCount++;
138135
} else {
139136
setSlaveStatus(queueData[0], STAT_ERROR_0B_QUEUE, true);
140137
errorTimeoutCount++;
@@ -153,21 +150,18 @@ void recvSerial() {
153150
if (rxNdx < MODBUS_SIZE) {
154151
serialIn[rxNdx] = mySerial.read();
155152
rxNdx++;
156-
} else {
157-
mySerial.read();
158-
rxErr = true; // frame longer than maximum allowed
159-
}
160-
unsigned long delay = 750;
161-
if (localConfig.baud <= 19200) {
162-
delay = 1.5 * charTime(); // inter-character time-out should be 1,5T
153+
} else { // frame longer than maximum allowed
154+
mySerial.read(); // CRC will fail and errorRtuCount will be recorded down the road
163155
}
164-
recvTimer.sleep(delay);
156+
recvTimer.sleep(charTimeOut());
157+
sendTimer.sleep(frameDelay()); // delay next serial write
158+
// sendTimer.sleep(localConfig.serialTimeout * 1000UL); // delay next serial write
165159
}
166160
if (recvTimer.isOver() && rxNdx != 0) {
167161
// Process Serial data
168162
// Checks: 1) RTU frame is without errors; 2) CRC; 3) address of incoming packet against first request in queue; 4) only expected responses are forwarded to TCP/UDP
169163
header myHeader = queueHeaders.first();
170-
if (!rxErr && checkCRC(serialIn, rxNdx) == true && serialIn[0] == queueData[0] && serialState == WAITING) {
164+
if (checkCRC(serialIn, rxNdx) == true && serialIn[0] == queueData[0] && serialState == WAITING) {
171165
if (serialIn[1] > 0x80 && (myHeader.requestType & SCAN_REQUEST) == false) {
172166
setSlaveStatus(serialIn[0], STAT_ERROR_0X, true);
173167
} else {
@@ -209,15 +203,6 @@ void recvSerial() {
209203
serialRxCount += rxNdx;
210204
#endif /* ENABLE_EXTRA_DIAG */
211205
rxNdx = 0;
212-
rxErr = false;
213-
unsigned long delay = 1750;
214-
if (localConfig.baud <= 19200) {
215-
delay = 3.5 * charTime(); // inter-frame delay should be 3,5T
216-
}
217-
if (FRAME_DELAY) {
218-
delay = FRAME_DELAY * 1000;
219-
}
220-
sendTimer.sleep(delay); // delay next serial write
221206
}
222207
}
223208

arduino-modbus-rtu-tcp-gateway/04-webserver.ino

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
***************************************************************** */
1818

1919
const byte WEB_IN_BUFFER_SIZE = 128; // size of web server read buffer (reads a complete line), 128 bytes necessary for POST data
20-
const byte SMALL_BUFFER_SIZE = 32; // a smaller buffer for uri
20+
const byte SMALL_BUFFER_SIZE = 32; // a smaller buffer for uri
2121

2222
// Actions that need to be taken after saving configuration.
2323
// These actions are also used by buttons on the Tools page.
@@ -67,18 +67,18 @@ enum post_key : byte {
6767
POST_DNS,
6868
POST_DNS_1,
6969
POST_DNS_2,
70-
POST_DNS_3, // DNS || all these 16 enum elements must be listed in succession!! ||
71-
POST_TCP, // TCP port || Because HTML code for these 3 ports ||
72-
POST_UDP, // UDP port || is generated through one for-loop, ||
73-
POST_WEB, // web UI port || these 3 elements must be listed in succession!! ||
74-
POST_RTU_OVER, // RTU over TCP/UDP
75-
POST_BAUD, // baud rate
76-
POST_DATA, // data bits
77-
POST_PARITY, // parity
78-
POST_STOP, // stop bits
79-
POST_TIMEOUT, // response timeout
80-
POST_ATTEMPTS, // number of request attempts
81-
POST_ACTION // actions on Tools page
70+
POST_DNS_3, // DNS || all these 16 enum elements must be listed in succession!! ||
71+
POST_TCP, // TCP port || Because HTML code for these 3 ports ||
72+
POST_UDP, // UDP port || is generated through one for-loop, ||
73+
POST_WEB, // web UI port || these 3 elements must be listed in succession!! ||
74+
POST_RTU_OVER, // RTU over TCP/UDP
75+
POST_BAUD, // baud rate
76+
POST_DATA, // data bits
77+
POST_PARITY, // parity
78+
POST_STOP, // stop bits
79+
POST_TIMEOUT, // response timeout
80+
POST_ATTEMPTS, // number of request attempts
81+
POST_ACTION // actions on Tools page
8282
};
8383

8484
void recvWeb() {
@@ -89,7 +89,7 @@ void recvWeb() {
8989
// char postParameter[SMALL_BUFFER_SIZE] {'\0'}; // parameter transmitted in the body / by POST
9090
if (client.available()) {
9191
char webInBuffer[WEB_IN_BUFFER_SIZE]{ '\0' }; // buffer for incoming data
92-
unsigned int i = 0; // index / current read position
92+
unsigned int i = 0; // index / current read position
9393
enum status_type : byte {
9494
REQUEST,
9595
CONTENT_LENGTH,
@@ -107,7 +107,7 @@ void recvWeb() {
107107
char *ptr;
108108
ptr = strtok(webInBuffer, " "); // strtok willdestroy the newRequest
109109
ptr = strtok(NULL, " ");
110-
strlcpy(uri, ptr, sizeof(uri)); // enthält noch evtl. parameter
110+
strlcpy(uri, ptr, sizeof(uri)); // enthält noch evtl. parameter
111111
status = EMPTY_LINE; // jump to next status
112112
} else if (status > REQUEST && i < 2) // check if we have an empty line
113113
{
@@ -116,8 +116,7 @@ void recvWeb() {
116116
i = 0;
117117
memset(webInBuffer, 0, sizeof(webInBuffer));
118118
} else {
119-
if (i < (WEB_IN_BUFFER_SIZE - 1))
120-
{
119+
if (i < (WEB_IN_BUFFER_SIZE - 1)) {
121120
webInBuffer[i] = c;
122121
i++;
123122
webInBuffer[i] = '\0';
@@ -142,8 +141,6 @@ void recvWeb() {
142141
// Actions that require "please wait" page
143142
if (action == WEB || action == REBOOT || action == ETH_SOFT || action == FACTORY || action == MAC) {
144143
reqPage = PAGE_WAIT;
145-
// } else if (action == RESET_COUNTERS) {
146-
// reqPage = PAGE_STATUS;
147144
}
148145

149146
// Send page
@@ -205,12 +202,14 @@ void processPost(char postParameter[]) {
205202
switch (paramKeyByte) {
206203
case POST_NONE: // reserved, because atoi / atol returns NULL in case of error
207204
break;
205+
#ifdef ENABLE_DHCP
208206
case POST_DHCP:
209207
if ((byte)paramValueUlong != localConfig.enableDhcp) {
210208
action = ETH_SOFT;
211209
localConfig.enableDhcp = (byte)paramValueUlong;
212210
}
213211
break;
212+
#endif /* ENABLE_DHCP */
214213
case POST_IP ... POST_IP_3:
215214
if ((byte)paramValueUlong != localConfig.ip[paramKeyByte - POST_IP]) {
216215
action = ETH_SOFT;
@@ -332,7 +331,7 @@ void processPost(char postParameter[]) {
332331
}
333332
// new parameter values received, save them to EEPROM
334333
EEPROM.put(CONFIG_START + 1, localConfig); // it is safe to call, only changed values are updated
335-
if (action == SERIAL_SOFT) { // can do it without "please wait" page
334+
if (action == SERIAL_SOFT) { // can do it without "please wait" page
336335
Serial.flush();
337336
Serial.end();
338337
startSerial();

arduino-modbus-rtu-tcp-gateway/05-pages.ino

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ void sendPage(EthernetClient &client, byte reqPage) {
5151
"<style>"
5252
"html,body{margin:0;height:100%;font-family:sans-serif}"
5353
"a{text-decoration:none;color:white}"
54+
"table{width:100%;height:100%}"
55+
"th{height:0;text-align:left;background-color:#0067AC;color:white;padding:10px}"
5456
"td:first-child {text-align:right;width:30%}"
55-
"th{text-align:left;background-color:#0067AC;color:white;padding:10px;height:0}"
56-
"table{width:100%}"
5757
"h1{margin:0}"
58+
"#x{padding:0;display:block;height:calc(100vh - 70px);overflow-y:auto}"
5859
"</style>"
5960
"</head>"
6061
"<body"));
@@ -63,10 +64,10 @@ void sendPage(EthernetClient &client, byte reqPage) {
6364
"<script>function dis(st) {var x = document.getElementsByClassName('ip');for (var i = 0; i < x.length; i++) {x[i].disabled = st}}</script"));
6465
#endif /* ENABLE_DHCP */
6566
chunked.print(F(">"
66-
"<table height=100%>"
67+
"<table>"
6768
"<tr><th colspan=2>"
6869
"<h1>Modbus RTU &rArr; Modbus TCP/UDP Gateway</h1>" // first row is header
69-
"<tr valign=top>" // second row is left menu (first cell) and main page (second cell)
70+
"<tr>" // second row is left menu (first cell) and main page (second cell)
7071
"<th style=width:20%;padding:0>"
7172

7273
// Left Menu
@@ -82,7 +83,7 @@ void sendPage(EthernetClient &client, byte reqPage) {
8283
menuItem(chunked, i);
8384
chunked.print(F("</a>"));
8485
}
85-
chunked.print(F("</table><td style=padding:0>"));
86+
chunked.print(F("<tr></table><td id=x>"));
8687

8788
// Main Page
8889
chunked.print(F("<form action=/"));
@@ -176,7 +177,7 @@ void contentStatus(ChunkedPrint &chunked) {
176177
chunked.print(F("W5500"));
177178
break;
178179
default: // TODO: add W6100 once it is included in Ethernet library
179-
chunked.print(F("unknown"));
180+
chunked.print(F("Unknown"));
180181
break;
181182
}
182183
chunked.print(F("<tr><td>Ethernet Sockets:<td>"));
@@ -568,12 +569,15 @@ void contentRtu(ChunkedPrint &chunked) {
568569
chunked.print(F("</option>"));
569570
}
570571
chunked.print(F("</select> bit"
572+
// "<tr><td>Frame Delay:"));
573+
// chunked.print(frameDelay());
574+
// chunked.print(F(" μs"
571575
"<tr><td>Response Timeout:"));
572576
helperInput(chunked);
573577
chunked.print(POST_TIMEOUT);
574-
chunked.print(F(" min=100 max=2000 value="));
578+
chunked.print(F(" min=50 max=2000 value="));
575579
chunked.print(localConfig.serialTimeout);
576-
chunked.print(F("> (100~2000) ms"
580+
chunked.print(F("> (50~2000) ms"
577581
"<tr><td>Attempts:"));
578582
helperInput(chunked);
579583
chunked.print(POST_ATTEMPTS);

0 commit comments

Comments
 (0)