3535
3636
3737void 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 );
4739#ifdef RS485_CONTROL_PIN
4840 pinMode (RS485_CONTROL_PIN, OUTPUT);
4941 digitalWrite (RS485_CONTROL_PIN, RS485_RECEIVE); // Init Transceiver
@@ -57,12 +49,12 @@ unsigned long charTime() {
5749 (((localConfig.serialConfig & 0x06 ) >> 1 ) + 5 ) + // data bits
5850 (((localConfig.serialConfig & 0x08 ) >> 3 ) + 1 ); // stop bits
5951 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 ;
6153}
6254
6355// character timeout
6456unsigned long charTimeOut () {
65- if (localConfig.baud <= 19200UL ) {
57+ if (localConfig.baud <= 192 ) {
6658 return 1.5 * charTime (); // inter-character time-out should be 1,5T
6759 } else {
6860 return 750 ;
@@ -71,7 +63,7 @@ unsigned long charTimeOut() {
7163
7264// minimum frame delay
7365unsigned long frameDelay () {
74- if (localConfig.baud <= 19200UL ) {
66+ if (localConfig.baud <= 192 ) {
7567 return 3.5 * charTime (); // inter-frame delay should be 3,5T
7668 } else {
7769 return 1750 ; // 1750 μs
@@ -99,14 +91,16 @@ void startEthernet() {
9991#else /* ENABLE_DHCP */
10092 Ethernet.begin (mac, localConfig.ip , {}, localConfig.gateway , localConfig.subnet ); // No DNS
10193#endif /* ENABLE_DHCP */
94+ Ethernet.setRetransmissionTimeout (TCP_RETRANSMISSION_TIMEOUT);
95+ Ethernet.setRetransmissionCount (TCP_RETRANSMISSION_COUNT);
10296 modbusServer = EthernetServer (localConfig.tcpPort );
10397 webServer = EthernetServer (localConfig.webPort );
10498 Udp.begin (localConfig.udpPort );
10599 modbusServer.begin ();
106100 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
110104}
111105
112106void (*resetFunc)(void ) = 0 ; // declare reset function at address 0
@@ -123,6 +117,7 @@ void maintainDhcp() {
123117}
124118#endif /* ENABLE_DHCP */
125119
120+ #ifdef ENABLE_EXTRA_DIAG
126121void maintainUptime () {
127122 unsigned long milliseconds = millis ();
128123 if (last_milliseconds > milliseconds) {
@@ -136,19 +131,23 @@ void maintainUptime() {
136131 // We add the "remaining_seconds", so that we can continue measuring the time passed from the last boot of the device.
137132 seconds = (milliseconds / 1000 ) + remaining_seconds;
138133}
134+ #endif /* ENABLE_EXTRA_DIAG */
139135
140136bool rollover () {
141137 // synchronize roll-over of run time, data counters and modbus stats to zero, at 0xFFFFFF00
142138 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
144140 if (errorCount[i] > ROLLOVER) {
145141 return true ;
146142 }
147143 }
148- if (errorTcpCount > ROLLOVER || errorRtuCount > ROLLOVER || errorTimeoutCount > ROLLOVER || seconds > ROLLOVER ) {
144+ if (errorTcpCount > ROLLOVER || errorRtuCount > ROLLOVER || errorTimeoutCount > ROLLOVER) {
149145 return true ;
150146 }
151147#ifdef ENABLE_EXTRA_DIAG
148+ if (seconds > ROLLOVER) {
149+ return true ;
150+ }
152151 if (serialTxCount > ROLLOVER || serialRxCount > ROLLOVER || ethTxCount > ROLLOVER || ethRxCount > ROLLOVER) {
153152 return true ;
154153 }
@@ -161,8 +160,8 @@ void resetStats() {
161160 errorTcpCount = 0 ;
162161 errorRtuCount = 0 ;
163162 errorTimeoutCount = 0 ;
164- remaining_seconds = -(millis () / 1000 );
165163#ifdef ENABLE_EXTRA_DIAG
164+ remaining_seconds = -(millis () / 1000 );
166165 ethRxCount = 0 ;
167166 ethTxCount = 0 ;
168167 serialRxCount = 0 ;
@@ -181,6 +180,123 @@ void generateMac() {
181180 }
182181}
183182
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+
184300// https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library/arduino-random-seed
185301void CreateTrulyRandomSeed () {
186302 seed1 = 0 ;
0 commit comments