35
35
36
36
37
37
void startSerial () {
38
- mySerial.flush ();
39
- mySerial.end ();
40
- queueHeaders.clear (); // <- eats memory!
41
- queueData.clear ();
42
- scanReqInQueue = false ;
43
- priorityReqInQueue= false ;
44
- memset (stat[STAT_ERROR_0B_QUEUE], 0 , sizeof (stat[STAT_ERROR_0B_QUEUE]));
45
- sendTimer.sleep (0 );
46
- mySerial.begin (localConfig.baud , localConfig.serialConfig );
38
+ mySerial.begin ((localConfig.baud * 100UL ), localConfig.serialConfig );
47
39
#ifdef RS485_CONTROL_PIN
48
40
pinMode (RS485_CONTROL_PIN, OUTPUT);
49
41
digitalWrite (RS485_CONTROL_PIN, RS485_RECEIVE); // Init Transceiver
@@ -57,12 +49,12 @@ unsigned long charTime() {
57
49
(((localConfig.serialConfig & 0x06 ) >> 1 ) + 5 ) + // data bits
58
50
(((localConfig.serialConfig & 0x08 ) >> 3 ) + 1 ); // stop bits
59
51
if (((localConfig.serialConfig & 0x30 ) >> 4 ) > 1 ) bits += 1 ; // parity bit (if present)
60
- return (bits * 1000000UL ) / (unsigned long )localConfig.baud ;
52
+ return (bits * 10000UL ) / (unsigned long )localConfig.baud ;
61
53
}
62
54
63
55
// character timeout
64
56
unsigned long charTimeOut () {
65
- if (localConfig.baud <= 19200UL ) {
57
+ if (localConfig.baud <= 192 ) {
66
58
return 1.5 * charTime (); // inter-character time-out should be 1,5T
67
59
} else {
68
60
return 750 ;
@@ -71,7 +63,7 @@ unsigned long charTimeOut() {
71
63
72
64
// minimum frame delay
73
65
unsigned long frameDelay () {
74
- if (localConfig.baud <= 19200UL ) {
66
+ if (localConfig.baud <= 192 ) {
75
67
return 3.5 * charTime (); // inter-frame delay should be 3,5T
76
68
} else {
77
69
return 1750 ; // 1750 μs
@@ -99,14 +91,16 @@ void startEthernet() {
99
91
#else /* ENABLE_DHCP */
100
92
Ethernet.begin (mac, localConfig.ip , {}, localConfig.gateway , localConfig.subnet ); // No DNS
101
93
#endif /* ENABLE_DHCP */
94
+ Ethernet.setRetransmissionTimeout (TCP_RETRANSMISSION_TIMEOUT);
95
+ Ethernet.setRetransmissionCount (TCP_RETRANSMISSION_COUNT);
102
96
modbusServer = EthernetServer (localConfig.tcpPort );
103
97
webServer = EthernetServer (localConfig.webPort );
104
98
Udp.begin (localConfig.udpPort );
105
99
modbusServer.begin ();
106
100
webServer.begin ();
107
- if (Ethernet. hardwareStatus () == EthernetW5100) {
108
- maxSockNum = 4 ; // W5100 chip never supports more than 4 sockets
109
- }
101
+ # if MAX_SOCK_NUM > 4
102
+ if (W5100. getChip () == 51 ) maxSockNum = 4 ; // W5100 chip never supports more than 4 sockets
103
+ # endif
110
104
}
111
105
112
106
void (*resetFunc)(void ) = 0 ; // declare reset function at address 0
@@ -123,6 +117,7 @@ void maintainDhcp() {
123
117
}
124
118
#endif /* ENABLE_DHCP */
125
119
120
+ #ifdef ENABLE_EXTRA_DIAG
126
121
void maintainUptime () {
127
122
unsigned long milliseconds = millis ();
128
123
if (last_milliseconds > milliseconds) {
@@ -136,19 +131,23 @@ void maintainUptime() {
136
131
// We add the "remaining_seconds", so that we can continue measuring the time passed from the last boot of the device.
137
132
seconds = (milliseconds / 1000 ) + remaining_seconds;
138
133
}
134
+ #endif /* ENABLE_EXTRA_DIAG */
139
135
140
136
bool rollover () {
141
137
// synchronize roll-over of run time, data counters and modbus stats to zero, at 0xFFFFFF00
142
138
const unsigned long ROLLOVER = 0xFFFFFF00 ;
143
- for (byte i = 0 ; i < STAT_ERROR_0B_QUEUE ; i++) { // there is no counter for STAT_ERROR_0B_QUEUE
139
+ for (byte i = 0 ; i < SLAVE_ERROR_0B_QUEUE ; i++) { // there is no counter for SLAVE_ERROR_0B_QUEUE
144
140
if (errorCount[i] > ROLLOVER) {
145
141
return true ;
146
142
}
147
143
}
148
- if (errorTcpCount > ROLLOVER || errorRtuCount > ROLLOVER || errorTimeoutCount > ROLLOVER || seconds > ROLLOVER ) {
144
+ if (errorTcpCount > ROLLOVER || errorRtuCount > ROLLOVER || errorTimeoutCount > ROLLOVER) {
149
145
return true ;
150
146
}
151
147
#ifdef ENABLE_EXTRA_DIAG
148
+ if (seconds > ROLLOVER) {
149
+ return true ;
150
+ }
152
151
if (serialTxCount > ROLLOVER || serialRxCount > ROLLOVER || ethTxCount > ROLLOVER || ethRxCount > ROLLOVER) {
153
152
return true ;
154
153
}
@@ -161,8 +160,8 @@ void resetStats() {
161
160
errorTcpCount = 0 ;
162
161
errorRtuCount = 0 ;
163
162
errorTimeoutCount = 0 ;
164
- remaining_seconds = -(millis () / 1000 );
165
163
#ifdef ENABLE_EXTRA_DIAG
164
+ remaining_seconds = -(millis () / 1000 );
166
165
ethRxCount = 0 ;
167
166
ethTxCount = 0 ;
168
167
serialRxCount = 0 ;
@@ -181,6 +180,123 @@ void generateMac() {
181
180
}
182
181
}
183
182
183
+
184
+
185
+ #if MAX_SOCK_NUM == 8
186
+ unsigned long lastSocketUse[MAX_SOCK_NUM] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }; // +rs 03Feb2019 - records last interaction involving each socket to enable detecting sockets unused for longest time period
187
+ byte socketInQueue[MAX_SOCK_NUM] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
188
+ #elif MAX_SOCK_NUM == 4
189
+ unsigned long lastSocketUse[MAX_SOCK_NUM] = { 0 , 0 , 0 , 0 }; // +rs 03Feb2019 - records last interaction involving each socket to enable detecting sockets unused for longest time period
190
+ byte socketInQueue[MAX_SOCK_NUM] = { 0 , 0 , 0 , 0 };
191
+ #endif
192
+
193
+ // from https://github.com/SapientHetero/Ethernet/blob/master/src/socket.cpp
194
+ void manageSockets () {
195
+ uint32_t maxAge = 0 ; // the 'age' of the socket in a 'disconnectable' state that was last used the longest time ago
196
+ byte oldest = MAX_SOCK_NUM; // the socket number of the 'oldest' disconnectable socket
197
+ byte modbusListening = MAX_SOCK_NUM;
198
+ byte webListening = MAX_SOCK_NUM;
199
+ byte dataAvailable = MAX_SOCK_NUM;
200
+ byte socketsAvailable = 0 ;
201
+ // SPI.beginTransaction(SPI_ETHERNET_SETTINGS); // begin SPI transaction
202
+ // look at all the hardware sockets, record and take action based on current states
203
+ for (byte s = 0 ; s < maxSockNum; s++) { // for each hardware socket ...
204
+ byte status = W5100.readSnSR (s); // get socket status...
205
+ uint32_t sockAge = millis () - lastSocketUse[s]; // age of the current socket
206
+ if (socketInQueue[s] > 0 ) {
207
+ lastSocketUse[s] = millis ();
208
+ continue ; // do not close Modbus TCP sockets currently processed (in queue)
209
+ }
210
+
211
+ switch (status) {
212
+ case SnSR::CLOSED:
213
+ {
214
+ socketsAvailable++;
215
+ }
216
+ break ;
217
+ case SnSR::LISTEN:
218
+ case SnSR::SYNRECV:
219
+ {
220
+ lastSocketUse[s] = millis ();
221
+ if (W5100.readSnPORT (s) == localConfig.webPort ) {
222
+ webListening = s;
223
+ } else {
224
+ modbusListening = s;
225
+ }
226
+ }
227
+ break ;
228
+ case SnSR::FIN_WAIT:
229
+ case SnSR::CLOSING:
230
+ case SnSR::TIME_WAIT:
231
+ case SnSR::LAST_ACK:
232
+ {
233
+ socketsAvailable++; // socket will be available soon
234
+ if (sockAge > TCP_DISCON_TIMEOUT) { // if it's been more than TCP_CLIENT_DISCON_TIMEOUT since disconnect command was sent...
235
+ W5100.execCmdSn (s, Sock_CLOSE); // send CLOSE command...
236
+ lastSocketUse[s] = millis (); // and record time at which it was sent so we don't do it repeatedly.
237
+ }
238
+ }
239
+ break ;
240
+ case SnSR::ESTABLISHED:
241
+ case SnSR::CLOSE_WAIT:
242
+ {
243
+ if (EthernetClient (s).available () > 0 ) {
244
+ dataAvailable = s;
245
+ lastSocketUse[s] = millis ();
246
+ } else {
247
+ // remote host closed connection, our end still open
248
+ if (status == SnSR::CLOSE_WAIT) {
249
+ socketsAvailable++; // socket will be available soon
250
+ W5100.execCmdSn (s, Sock_DISCON); // send DISCON command...
251
+ lastSocketUse[s] = millis (); // record time at which it was sent...
252
+ // status becomes LAST_ACK for short time
253
+ } else if (((W5100.readSnPORT (s) == localConfig.webPort && sockAge > TCP_WEB_DISCON_AGE)
254
+ || (W5100.readSnPORT (s) == localConfig.tcpPort && sockAge > (localConfig.tcpTimeout * 1000UL )))
255
+ && sockAge > maxAge) {
256
+ oldest = s; // record the socket number...
257
+ maxAge = sockAge; // and make its age the new max age.
258
+ }
259
+ }
260
+ }
261
+ break ;
262
+ default :
263
+ break ;
264
+ }
265
+ }
266
+
267
+ if (dataAvailable != MAX_SOCK_NUM) {
268
+ EthernetClient client = EthernetClient (dataAvailable);
269
+ if (W5100.readSnPORT (dataAvailable) == localConfig.webPort ) {
270
+ recvWeb (client);
271
+ } else {
272
+ recvTcp (client);
273
+ }
274
+ }
275
+
276
+ if (modbusListening == MAX_SOCK_NUM) {
277
+ modbusServer.begin ();
278
+ } else if (webListening == MAX_SOCK_NUM) {
279
+ webServer.begin ();
280
+ }
281
+
282
+ // If needed, disconnect socket that's been idle (ESTABLISHED without data recieved) the longest
283
+ if (oldest != MAX_SOCK_NUM && socketsAvailable == 0 && (webListening == MAX_SOCK_NUM || modbusListening == MAX_SOCK_NUM)) {
284
+ disconSocket (oldest);
285
+ }
286
+
287
+ // SPI.endTransaction(); // Serves to o release the bus for other devices to access it. Since the ethernet chip is the only device
288
+ // we do not need SPI.beginTransaction(SPI_ETHERNET_SETTINGS) or SPI.endTransaction()
289
+ }
290
+
291
+ void disconSocket (byte s) {
292
+ if (W5100.readSnSR (s) == SnSR::ESTABLISHED) {
293
+ W5100.execCmdSn (s, Sock_DISCON); // Sock_DISCON does not close LISTEN sockets
294
+ lastSocketUse[s] = millis (); // record time at which it was sent...
295
+ } else {
296
+ W5100.execCmdSn (s, Sock_CLOSE); // send DISCON command...
297
+ }
298
+ }
299
+
184
300
// https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library/arduino-random-seed
185
301
void CreateTrulyRandomSeed () {
186
302
seed1 = 0 ;
0 commit comments