From 14cc1e463cc550033125c72477d45f6d7a4bd006 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Mon, 22 Jul 2024 08:34:05 +0800 Subject: [PATCH] STM32 ethernet client handling fix --- EthernetInterface.cpp | 121 ++++++++++++++++++++++++------------------ EthernetInterface.h | 9 +++- I2CManager_STM32.h | 3 +- 3 files changed, 79 insertions(+), 54 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 814cc4f..8e34db8 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -215,16 +215,23 @@ bool EthernetInterface::checkLink() { // gets disconnected and connected again if(!outboundRing) outboundRing=new RingStream(OUTBOUND_RING_SIZE); + // Clear out the clients + for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) { + clients[socket].inUse = false; + } } return true; } else { // LinkOFF if (connected) { // Were connected, but no longer without a LINK! DIAG(F("Ethernet cable disconnected")); connected=false; - //clean up any client + //clean up any clients for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) { - if(clients[socket].connected()) - clients[socket].stop(); + if (clients[socket].inUse && clients[socket].client.connected()) + { + clients[socket].client.flush(); + clients[socket].client.stop(); + } } mdns.removeServiceRecord(IP_PORT, MDNSServiceTCP); // tear down server @@ -251,57 +258,68 @@ void EthernetInterface::loop2() { // check for new client if (client) { - byte socket; - bool sockfound = false; - for (socket = 0; socket < MAX_SOCK_NUM; socket++) { - if (clients[socket] && (clients[socket] == client)) { - sockfound = true; - if (Diag::ETHERNET) DIAG(F("Ethernet: Old client socket %d"),socket); - break; - } - } - if (!sockfound) { // new client - for (socket = 0; socket < MAX_SOCK_NUM; socket++) { - if (!clients[socket]) { - // On accept() the EthernetServer doesn't track the client anymore - // so we store it in our client array - clients[socket] = client; - if (Diag::ETHERNET) DIAG(F("Ethernet: New client socket %d"),socket); - break; - } - } + byte socket; + bool sockfound = false; + for (socket = 0; socket < MAX_SOCK_NUM; socket++) + { + if (clients[socket].inUse && (client == clients[socket].client)) + { + sockfound = true; + if (Diag::ETHERNET) + DIAG(F("Ethernet: Old client socket %d"), socket); + break; } - if (socket==MAX_SOCK_NUM) DIAG(F("new Ethernet OVERFLOW")); + } + if (!sockfound) + { // new client + for (socket = 0; socket < MAX_SOCK_NUM; socket++) + { + if (!clients[socket].inUse) + { + // On accept() the EthernetServer doesn't track the client anymore + // so we store it in our client array + clients[socket].client = client; + clients[socket].inUse = true; + if (Diag::ETHERNET) + DIAG(F("Ethernet: New client socket %d"), socket); + break; + } + } + } + if (socket == MAX_SOCK_NUM) + DIAG(F("new Ethernet OVERFLOW")); } // check for incoming data from all possible clients for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) { - if (clients[socket]) { - if (!clients[socket].connected()) { // stop any clients which disconnect - CommandDistributor::forget(socket); - clients[socket].stop(); - #if defined(ARDUINO_ARCH_AVR) - clients[socket]=NULL; - #else - clients[socket]=(EthernetClient)nullptr; - #endif - //if (Diag::ETHERNET) - DIAG(F("Ethernet: disconnect %d "), socket); - return; // Trick: So that we do not continue in this loop with client that is NULL - } - - int available=clients[socket].available(); - if (available > 0) { - if (Diag::ETHERNET) DIAG(F("Ethernet: available socket=%d,avail=%d"), socket, available); - // read bytes from a client - int count = clients[socket].read(buffer, MAX_ETH_BUFFER); - buffer[count] = '\0'; // terminate the string properly - if (Diag::ETHERNET) DIAG(F(",count=%d:%e"), socket,buffer); - // execute with data going directly back - CommandDistributor::parse(socket,buffer,outboundRing); - return; // limit the amount of processing that takes place within 1 loop() cycle. - } + if (clients[socket].inUse) + { + if (!clients[socket].client.connected()) + { // stop any clients which disconnect + CommandDistributor::forget(socket); + clients[socket].client.flush(); + clients[socket].client.stop(); + clients[socket].inUse = false; + if (Diag::ETHERNET) + DIAG(F("Ethernet: disconnect %d "), socket); + return; // Trick: So that we do not continue in this loop with client that is NULL + } + + int available = clients[socket].client.available(); + if (available > 0) + { + if (Diag::ETHERNET) + DIAG(F("Ethernet: available socket=%d,avail=%d"), socket, available); + // read bytes from a client + int count = clients[socket].client.read(buffer, MAX_ETH_BUFFER); + buffer[count] = '\0'; // terminate the string properly + if (Diag::ETHERNET) + DIAG(F(",count=%d:%e"), socket, buffer); + // execute with data going directly back + CommandDistributor::parse(socket, buffer, outboundRing); + return; // limit the amount of processing that takes place within 1 loop() cycle. + } } } @@ -315,9 +333,10 @@ void EthernetInterface::loop2() { DIAG(F("Ethernet outboundRing socket=%d error"), socketOut); } else if (socketOut >= 0) { int count=outboundRing->count(); - if (Diag::ETHERNET) DIAG(F("Ethernet reply socket=%d, count=:%d"), socketOut,count); - for(;count>0;count--) clients[socketOut].write(outboundRing->read()); - clients[socketOut].flush(); //maybe + if (Diag::ETHERNET) + DIAG(F("Ethernet reply socket=%d, count=:%d"), socketOut,count); + for(;count>0;count--) clients[socketOut].client.write(outboundRing->read()); + clients[socketOut].client.flush(); //maybe } } #endif diff --git a/EthernetInterface.h b/EthernetInterface.h index 31780f4..2be42f1 100644 --- a/EthernetInterface.h +++ b/EthernetInterface.h @@ -36,7 +36,7 @@ #include //TEENSY Ethernet Treiber #include #define MAX_SOCK_NUM 4 -#elif defined (ARDUINO_NUCLEO_F429ZI) || defined (ARDUINO_NUCLEO_F439ZI) +#elif defined (ARDUINO_NUCLEO_F429ZI) || defined (ARDUINO_NUCLEO_F439ZI) || defined (ARDUINO_NUCLEO_F4X9ZI) #include // #include "STM32lwipopts.h" #include @@ -73,7 +73,12 @@ class EthernetInterface { void loop2(); bool checkLink(); EthernetServer * server = NULL; - EthernetClient clients[MAX_SOCK_NUM]; // accept up to MAX_SOCK_NUM client connections at the same time; This depends on the chipset used on the Shield + struct { + EthernetClient client; + bool inUse; + } clients[MAX_CLIENT]; + // accept up to MAX_SOCK_NUM client connections at the same time; This depends on the chipset used on the Shield + uint8_t buffer[MAX_ETH_BUFFER+1]; // buffer used by TCP for the recv RingStream * outboundRing = NULL; }; diff --git a/I2CManager_STM32.h b/I2CManager_STM32.h index 9e4582f..ca1593e 100644 --- a/I2CManager_STM32.h +++ b/I2CManager_STM32.h @@ -39,7 +39,8 @@ #if defined(I2C_USE_INTERRUPTS) && defined(ARDUINO_ARCH_STM32) #if defined(ARDUINO_NUCLEO_F401RE) || defined(ARDUINO_NUCLEO_F411RE) || defined(ARDUINO_NUCLEO_F446RE) \ || defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F413ZH) \ - || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F446ZE) + || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F4X9ZI) \ + || defined(ARDUINO_NUCLEO_F446ZE) // Assume I2C1 for now - default I2C bus on Nucleo-F411RE and likely all Nucleo-64 // and Nucleo-144 variants I2C_TypeDef *s = I2C1;