16
16
17
17
***************************************************************** */
18
18
19
-
20
- const byte pagesCnt = 5 ; // number of consecutive pages ("1.htm", "2.htm"....) served by the server, maximum is 9
21
19
const byte webInBufferSize = 128 ; // size of web server read buffer (reads a complete line), 128 bytes necessary for POST data
22
20
const byte smallbuffersize = 32 ; // a smaller buffer for uri
23
21
24
22
// Actions that need to be taken after saving configuration.
25
- // Order of these actions must correspond to POST param values of buttons on the " Tools" web page (e.g. "value=1" for Restore factory defaults, etc.)
23
+ // These actions are also used by buttons on the Tools page.
26
24
enum action_type : byte
27
25
{
28
- NONE, FACTORY, MAC, REBOOT, ETH_SOFT, SERIAL_SOFT, SCAN, WEB
26
+ NONE,
27
+ FACTORY, // Restore factory settings (but keep MAC address)
28
+ MAC, // Generate new random MAC
29
+ REBOOT, // Reboot the microcontroller
30
+ ETH_SOFT, // Ethernet software reset
31
+ SERIAL_SOFT, // Serial software reset
32
+ SCAN, // Initialize RS485 scan
33
+ WEB // Restart webserver
29
34
};
30
35
enum action_type action;
31
36
37
+ // Pages served by the webserver. Order of elements defines the order in the left menu of the web UI.
38
+ // URL of the page (*.htm) contains number corresponding to its position in this array.
39
+ // The following enum array can have a maximum of 10 elements (incl. PAGE_NONE and PAGE_WAIT)
40
+ enum page : byte
41
+ {
42
+ PAGE_NONE, // reserved for NULL
43
+ PAGE_STATUS,
44
+ PAGE_IP,
45
+ PAGE_TCP,
46
+ PAGE_RTU,
47
+ PAGE_TOOLS,
48
+ PAGE_WAIT // page with "Reloading. Please wait..." message. Must be the last element within this enum!!
49
+ };
50
+
51
+ // Keys for POST parameters, used in web forms and processed by processPost() function.
52
+ // Using enum ensures unique identification of each POST parameter key and consistence across functions.
53
+ // In HTML code, each element will apear as number corresponding to its position in this array.
54
+ enum post_key : byte
55
+ {
56
+ POST_NONE, // reserved for NULL
57
+ POST_DHCP, // enable DHCP
58
+ POST_IP, POST_IP_1, POST_IP_2, POST_IP_3, // IP address || Each part of an IP address has its own POST parameter. ||
59
+ POST_SUBNET, POST_SUBNET_1, POST_SUBNET_2, POST_SUBNET_3, // subnet || Because HTML code for IP, subnet, gateway and DNS ||
60
+ POST_GATEWAY, POST_GATEWAY_1, POST_GATEWAY_2, POST_GATEWAY_3, // gateway || is generated through one (nested) for-loop, ||
61
+ POST_DNS, POST_DNS_1, POST_DNS_2, POST_DNS_3, // DNS || all these 16 enum elements must be listed in succession!! ||
62
+ POST_TCP, // TCP port || Because HTML code for these 3 ports ||
63
+ POST_UDP, // UDP port || is generated through one for-loop, ||
64
+ POST_WEB, // web UI port || these 3 elements must be listed in succession!! ||
65
+ POST_RTU_OVER, // RTU over TCP/UDP
66
+ POST_BAUD, // baud rate
67
+ POST_DATA, // data bits
68
+ POST_PARITY, // parity
69
+ POST_STOP, // stop bits
70
+ POST_TIMEOUT, // response timeout
71
+ POST_RETRY, // retry attempts
72
+ POST_ACTION // actions on Tools page
73
+ };
74
+
32
75
void recvWeb ()
33
76
{
34
77
EthernetClient client = webServer.available ();
35
78
if (client) {
36
- dbg (F (" [web] Data from client " ));
79
+ dbg (F (" [web in ] Data from client " ));
37
80
38
81
char uri[smallbuffersize]; // the requested page
39
82
// char requestParameter[smallbuffersize]; // parameter appended to the URI after a ?
@@ -54,13 +97,13 @@ void recvWeb()
54
97
{
55
98
if (status == REQUEST) // read the first line
56
99
{
57
- dbg (F (" [web] webInBuffer=" )); dbgln (webInBuffer);
100
+ dbg (F (" [web in ] webInBuffer=" )); dbgln (webInBuffer);
58
101
// now split the input
59
102
char *ptr;
60
103
ptr = strtok (webInBuffer, " " ); // strtok willdestroy the newRequest
61
104
ptr = strtok (NULL , " " );
62
105
strlcpy (uri, ptr, sizeof (uri)); // enthält noch evtl. parameter
63
- dbg (F (" [web] uri=" )); dbgln (uri);
106
+ dbg (F (" [web in ] uri=" )); dbgln (uri);
64
107
status = EMPTY_LINE; // jump to next status
65
108
}
66
109
else if (status > REQUEST && i < 2 ) // check if we have an empty line
@@ -92,24 +135,35 @@ void recvWeb()
92
135
}
93
136
if (status == BODY) // status 3 could end without linefeed, therefore we takeover here also
94
137
{
95
- dbg (F (" [web] POST data=" )); dbgln (webInBuffer);
138
+ dbg (F (" [web in ] POST data=" )); dbgln (webInBuffer);
96
139
if (webInBuffer[0 ] != ' \0 ' ) {
97
140
processPost (webInBuffer);
98
141
}
99
142
}
100
143
}
101
144
102
- // send back a response
103
- // Get number of the requested page
145
+ // Get number of the requested page from URI
104
146
byte reqPage = 0 ; // requested page
105
- if ((uri[0 ] == ' /' ) && !strcmp (uri + 2 , " .htm" )) {
106
- reqPage = uri[1 ] - 48 ; // Convert ASCII to byte
147
+ if (!strcmp (uri, " /" )) // the homepage Current Status
148
+ reqPage = PAGE_STATUS;
149
+ else if ((uri[0 ] == ' /' ) && !strcmp (uri + 2 , " .htm" )) {
150
+ reqPage = (byte)(uri[1 ] - 48 ); // Convert single ASCII char to byte
107
151
}
108
-
109
152
// Actions that require "please wait" page
110
153
if (action == WEB || action == REBOOT || action == ETH_SOFT || action == FACTORY || action == MAC) {
111
- sendPage (client, 0xFF ); // Send "please wait" page
112
- // Do all actions before the "please wait" redirects (5s delay at the moment)
154
+ reqPage = PAGE_WAIT;
155
+ }
156
+
157
+ // Send page
158
+ if ((reqPage > 0 ) && (reqPage <= PAGE_WAIT))
159
+ sendPage (client, reqPage);
160
+ else if (!strcmp (uri, " /favicon.ico" )) // a favicon
161
+ send204 (client); // if you don't have a favicon, send 204
162
+ else // if the page is unknown, HTTP response code 404
163
+ send404 (client); // defaults to 404 error
164
+
165
+ // Do all actions before the "please wait" redirects (5s delay at the moment)
166
+ if (reqPage == PAGE_WAIT) {
113
167
for (byte n = 0 ; n < maxSockNum; n++) {
114
168
// in case of webserver restart, stop only clients from old webserver (clients with port different from current settings)
115
169
EthernetClient clientTemp = EthernetClient (n);
@@ -119,7 +173,6 @@ void recvWeb()
119
173
clientTemp.stop ();
120
174
}
121
175
}
122
-
123
176
switch (action) {
124
177
case WEB:
125
178
webServer = EthernetServer (localConfig.webPort );
@@ -136,20 +189,10 @@ void recvWeb()
136
189
break ;
137
190
}
138
191
}
139
- else if (!strcmp (uri, " /" ) || !strcmp (uri, " /index.htm" )) // the homepage Current Status
140
- sendPage (client, 1 );
141
- else if ((reqPage > 0 ) && (reqPage <= pagesCnt))
142
- sendPage (client, reqPage);
143
- else if (!strcmp (uri, " /favicon.ico" )) // a favicon
144
- send204 (client); // if you don't have a favicon, send 204
145
- else // if the page is unknown, HTTP response code 404
146
- send404 (client);
147
192
action = NONE;
148
- dbg (F (" [web] Stop client " ));
149
193
}
150
194
}
151
195
152
-
153
196
// This function stores POST parameter values in localConfig.
154
197
// Most changes are saved and applied immediatelly, some changes (IP settings, web server port, actions in "Tools" page) are saved but applied later after "please wait" page is sent.
155
198
void processPost (char postParameter[]) {
@@ -161,134 +204,108 @@ void processPost(char postParameter[]) {
161
204
char *paramValue;
162
205
char *sav2 = NULL ; // for inner strtok_r
163
206
paramKey = strtok_r (point, " =" , &sav2); // inner strtok_r, use sav2
207
+ paramValue = strtok_r (NULL , " =" , &sav2);
208
+ if (!paramValue) continue ;
209
+ byte paramKeyByte = atoi (paramKey);
210
+ unsigned long paramValueUlong = atol (paramValue);
164
211
165
- switch (paramKey[0 ]) {
166
- case ' i' : // processing IP Settings
167
- {
168
- paramValue = strtok_r (NULL , " =" , &sav2);
169
- int paramValueInt = atoi (paramValue);
170
- if (paramValue && (paramValueInt >= 0 && paramValueInt <= 255 )) {
171
- byte j = atoi (paramKey + 1 );
172
- if (j <= 0 ); // do nothing
173
- else if (j == 1 ) { // Enable DHCP
174
- if ((byte)paramValueInt != localConfig.enableDhcp ) {
175
- action = ETH_SOFT;
176
- localConfig.enableDhcp = (byte)paramValueInt;
177
- }
178
- } else if (j <= 5 ) { // IP
179
- if ((byte)paramValueInt != localConfig.ip [j - 2 ]) {
180
- action = ETH_SOFT;
181
- localConfig.ip [j - 2 ] = (byte)paramValueInt;
182
- }
183
- } else if (j <= 9 ) { // Subnet
184
- if ((byte)paramValueInt != localConfig.subnet [j - 6 ]) {
185
- action = ETH_SOFT;
186
- localConfig.subnet [j - 6 ] = (byte)paramValueInt;
187
- }
188
- } else if (j <= 13 ) { // Gateway
189
- if ((byte)paramValueInt != localConfig.gateway [j - 10 ]) {
190
- action = ETH_SOFT;
191
- localConfig.gateway [j - 10 ] = (byte)paramValueInt;
192
- }
193
- } else if (j <= 17 ) { // DNS
194
- if ((byte)paramValueInt != localConfig.dns [j - 14 ]) {
195
- action = ETH_SOFT;
196
- localConfig.dns [j - 14 ] = (byte)paramValueInt;
197
- }
198
- }
199
- }
200
- break ;
212
+ switch (paramKeyByte) {
213
+ case POST_NONE: // reserved, because atoi / atol returns NULL in case of error
214
+ break ;
215
+ case POST_DHCP:
216
+ if ((byte)paramValueUlong != localConfig.enableDhcp ) {
217
+ action = ETH_SOFT;
218
+ localConfig.enableDhcp = (byte)paramValueUlong;
201
219
}
202
- case ' t' : // processing TCP/UDP Settings
203
- {
204
- paramValue = strtok_r (NULL , " =" , &sav2);
205
- unsigned int paramValueUint = atoi (paramValue);
206
- if (paramValue) {
207
- switch (atoi (paramKey + 1 )) {
208
- case 1 : // TCP port
209
- if (localConfig.tcpPort != paramValueUint) {
210
- for (byte i = 0 ; i < maxSockNum; i++) {
211
- EthernetClient clientTemp = EthernetClient (i);
212
- if (clientTemp.status () != SnSR::UDP && clientTemp.localPort () == localConfig.tcpPort ) {
213
- clientTemp.flush ();
214
- clientTemp.stop ();
215
- }
216
- }
217
- localConfig.tcpPort = paramValueUint;
218
- modbusServer = EthernetServer (localConfig.tcpPort );
219
- }
220
- break ;
221
- case 2 : // UDP Port
222
- if (localConfig.udpPort != paramValueUint) {
223
- localConfig.udpPort = paramValueUint;
224
- Udp.stop ();
225
- Udp.begin (localConfig.udpPort );
226
- }
227
- break ;
228
- case 3 : // Web Port
229
- if (localConfig.webPort != paramValueUint) {
230
- localConfig.webPort = paramValueUint;
231
- action = WEB;
232
- }
233
- break ;
234
- case 4 : // Enable Modbus RTU over TCP/UDP
235
- localConfig.enableRtuOverTcp = (byte)paramValueUint;
236
- break ;
237
- default :
238
- break ;
239
- }
240
- }
241
- break ;
220
+ break ;
221
+ case POST_IP ... POST_IP_3:
222
+ if ((byte)paramValueUlong != localConfig.ip [paramKeyByte - POST_IP]) {
223
+ action = ETH_SOFT;
224
+ localConfig.ip [paramKeyByte - POST_IP] = (byte)paramValueUlong;
242
225
}
243
- case ' r' : // processing RS485 Settings
244
- {
245
- paramValue = strtok_r (NULL , " =" , &sav2);
246
- unsigned long paramValueUlong = atol (paramValue);
247
- if (paramValue) {
248
- switch (atoi (paramKey + 1 )) {
249
- case 1 : // Baud
250
- if (localConfig.baud != paramValueUlong) {
251
- action = SERIAL_SOFT;
252
- localConfig.baud = paramValueUlong;
253
- }
254
- break ;
255
- case 2 : // Data Size
256
- if ((((localConfig.serialConfig & 0x06 ) >> 1 ) + 5 ) != atoi (paramValue)) {
257
- action = SERIAL_SOFT;
258
- localConfig.serialConfig = (localConfig.serialConfig & 0xF9 ) | ((atoi (paramValue) - 5 ) << 1 );
259
- }
260
- break ;
261
- case 3 : // Parity
262
- if (((localConfig.serialConfig & 0x30 ) >> 4 ) != atoi (paramValue)) {
263
- action = SERIAL_SOFT;
264
- localConfig.serialConfig = (localConfig.serialConfig & 0xCF ) | (atoi (paramValue) << 4 );
265
- }
266
- break ;
267
- case 4 : // Stop Bits
268
- if ((((localConfig.serialConfig & 0x08 ) >> 3 ) + 1 ) != atoi (paramValue)) {
269
- action = SERIAL_SOFT;
270
- localConfig.serialConfig = (localConfig.serialConfig & 0xF7 ) | ((atoi (paramValue) - 1 ) << 3 );
271
- }
272
- break ;
273
- case 5 : // Modbus timeout
274
- localConfig.serialTimeout = paramValueUlong;
275
- break ;
276
- case 6 : // Modbus retry
277
- localConfig.serialRetry = (byte)paramValueUlong;
278
- break ;
279
- default :
280
- break ;
226
+ break ;
227
+ case POST_SUBNET ... POST_SUBNET_3:
228
+ if ((byte)paramValueUlong != localConfig.subnet [paramKeyByte - POST_SUBNET]) {
229
+ action = ETH_SOFT;
230
+ localConfig.subnet [paramKeyByte - POST_SUBNET] = (byte)paramValueUlong;
231
+ }
232
+ break ;
233
+ case POST_GATEWAY ... POST_GATEWAY_3:
234
+ if ((byte)paramValueUlong != localConfig.gateway [paramKeyByte - POST_GATEWAY]) {
235
+ action = ETH_SOFT;
236
+ localConfig.gateway [paramKeyByte - POST_GATEWAY] = (byte)paramValueUlong;
237
+ }
238
+ break ;
239
+ case POST_DNS ... POST_DNS_3:
240
+ if ((byte)paramValueUlong != localConfig.dns [paramKeyByte - POST_DNS]) {
241
+ action = ETH_SOFT;
242
+ localConfig.dns [paramKeyByte - POST_DNS] = (byte)paramValueUlong;
243
+ }
244
+ break ;
245
+ case POST_TCP:
246
+ if (localConfig.tcpPort != (unsigned int )paramValueUlong) {
247
+ for (byte i = 0 ; i < maxSockNum; i++) {
248
+ EthernetClient clientTemp = EthernetClient (i);
249
+ if (clientTemp.status () != SnSR::UDP && clientTemp.localPort () == localConfig.tcpPort ) {
250
+ clientTemp.flush ();
251
+ clientTemp.stop ();
281
252
}
282
253
}
283
- break ;
254
+ localConfig.tcpPort = (unsigned int )paramValueUlong;
255
+ modbusServer = EthernetServer (localConfig.tcpPort );
284
256
}
285
- case ' a' : // processing Tools buttons
286
- {
287
- action = (action_type)atoi (strtok_r (NULL , " =" , &sav2));
288
- break ;
289
- default :
290
- break ;
257
+ break ;
258
+ case POST_UDP:
259
+ if (localConfig.udpPort != (unsigned int )paramValueUlong) {
260
+ localConfig.udpPort = (unsigned int )paramValueUlong;
261
+ Udp.stop ();
262
+ Udp.begin (localConfig.udpPort );
263
+ }
264
+ break ;
265
+ case POST_WEB:
266
+ if (localConfig.webPort != (unsigned int )paramValueUlong) {
267
+ localConfig.webPort = (unsigned int )paramValueUlong;
268
+ action = WEB;
269
+ }
270
+ break ;
271
+ case POST_RTU_OVER:
272
+ localConfig.enableRtuOverTcp = (byte)paramValueUlong;
273
+ break ;
274
+ case POST_BAUD:
275
+ if (localConfig.baud != paramValueUlong) {
276
+ action = SERIAL_SOFT;
277
+ localConfig.baud = paramValueUlong;
278
+ }
279
+ break ;
280
+ case POST_DATA:
281
+ if ((((localConfig.serialConfig & 0x06 ) >> 1 ) + 5 ) != (byte)paramValueUlong) {
282
+ action = SERIAL_SOFT;
283
+ localConfig.serialConfig = (localConfig.serialConfig & 0xF9 ) | (((byte)paramValueUlong - 5 ) << 1 );
284
+ }
285
+ break ;
286
+ case POST_PARITY:
287
+ if (((localConfig.serialConfig & 0x30 ) >> 4 ) != (byte)paramValueUlong) {
288
+ action = SERIAL_SOFT;
289
+ localConfig.serialConfig = (localConfig.serialConfig & 0xCF ) | ((byte)paramValueUlong << 4 );
291
290
}
291
+ break ;
292
+ case POST_STOP:
293
+ if ((((localConfig.serialConfig & 0x08 ) >> 3 ) + 1 ) != (byte)paramValueUlong) {
294
+ action = SERIAL_SOFT;
295
+ localConfig.serialConfig = (localConfig.serialConfig & 0xF7 ) | (((byte)paramValueUlong - 1 ) << 3 );
296
+ }
297
+ break ;
298
+ case POST_TIMEOUT:
299
+ localConfig.serialTimeout = paramValueUlong;
300
+ break ;
301
+ case POST_RETRY:
302
+ localConfig.serialRetry = (byte)paramValueUlong;
303
+ break ;
304
+ case POST_ACTION:
305
+ action = (action_type)paramValueUlong;
306
+ break ;
307
+ default :
308
+ break ;
292
309
}
293
310
point = strtok_r (NULL , " &" , &sav1);
294
311
} // while (point != NULL)
0 commit comments