From 7e29011d638ed4ed91ad10a5d59c916d57f1b9fe Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Wed, 7 Aug 2024 21:13:44 +0200 Subject: [PATCH 01/18] looptimer test 1 --- CommandStation-EX.ino | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index 3a0e5ca..31b3b21 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -141,44 +141,73 @@ void setup() CommandDistributor::broadcastPower(); } +void looptimer(unsigned long timeout, const FSH* message) +{ + static unsigned long lasttimestamp = 0; + unsigned long now = micros(); + if (timeout != 0) { + unsigned long diff = now - lasttimestamp; + if (diff > timeout) { + DIAG(message); + DIAG(F("DeltaT=%L"), diff); + lasttimestamp = micros(); + return; + } + } + lasttimestamp = now; +} + void loop() { // The main sketch has responsibilities during loop() // Responsibility 1: Handle DCC background processes // (loco reminders and power checks) + looptimer(0, F("")); DCC::loop(); + looptimer(5000, F("DCC")); // got warnings up to 3884 during prog track read // Responsibility 2: handle any incoming commands on USB connection SerialManager::loop(); + looptimer(2000, F("Serial")); // got warnings up to 1900 during start // Responsibility 3: Optionally handle any incoming WiFi traffic #ifndef ARDUINO_ARCH_ESP32 #if WIFI_ON WifiInterface::loop(); + looptimer(9000, F("Wifi")); // got warnings up to 8000 + #endif //WIFI_ON #else //ARDUINO_ARCH_ESP32 #ifndef WIFI_TASK_ON_CORE0 WifiESP::loop(); + looptimer(1000, F("WifiESP")); + #endif #endif //ARDUINO_ARCH_ESP32 #if ETHERNET_ON EthernetInterface::loop(); + looptimer(10000, F("Ethernet")); #endif RMFT::loop(); // ignored if no automation + looptimer(1000, F("RMFT")); #if defined(LCN_SERIAL) LCN::loop(); + looptimer(1000, F("LCN")); #endif // Display refresh DisplayInterface::loop(); + looptimer(2000, F("Display")); // got warnings around 1150 // Handle/update IO devices. IODevice::loop(); + looptimer(1000, F("IODevice")); Sensor::checkAll(); // Update and print changes + looptimer(1000, F("Sensor")); // Report any decrease in memory (will automatically trigger on first call) static int ramLowWatermark = __INT_MAX__; // replaced on first loop From 923b031d06442d578607d7462de39897f58bd58b Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Wed, 7 Aug 2024 21:14:07 +0200 Subject: [PATCH 02/18] Gittag --- GITHUB_SHA.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 48e2fdf..b09405c 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-202406182019Z" +#define GITHUB_SHA "devel-fozzie-202408071912Z" From 690c629e6dce280b6f870b0d42c39491c28b0ca4 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 9 Aug 2024 09:16:56 +0200 Subject: [PATCH 03/18] looptimer more diag in EthernetInterface --- EthernetInterface.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 34e209a..ef08a1b 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -30,6 +30,8 @@ #include "WiThrottle.h" #include "DCCTimer.h" +extern void looptimer(unsigned long timeout, const FSH* message); + EthernetInterface * EthernetInterface::singleton=NULL; /** * @brief Setup Ethernet Connection @@ -125,6 +127,7 @@ void EthernetInterface::loop() //nothing happened break; } + looptimer(8000, F("Ethloop after maintain")); singleton->loop2(); } @@ -207,13 +210,14 @@ void EthernetInterface::loop2() { // 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); + if (Diag::ETHERNET) DIAG(F(",count=%d:%e"), count, 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. } } } + looptimer(8000, F("Ethloop2 after incoming")); // stop any clients which disconnect for (int socket = 0; socketread(); if (socketOut >= MAX_SOCK_NUM) { @@ -236,5 +242,7 @@ void EthernetInterface::loop2() { for(;count>0;count--) clients[socketOut].write(outboundRing->read()); clients[socketOut].flush(); //maybe } + looptimer(8000, F("Ethloop after outbound")); + } #endif From 127f3acce53254130077b1e726d41aad0097a37a Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 9 Aug 2024 11:46:33 +0200 Subject: [PATCH 04/18] send whole outbuffer --- EthernetInterface.cpp | 10 +++++++++- GITHUB_SHA.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index ef08a1b..a7ca0be 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -209,6 +209,7 @@ void EthernetInterface::loop2() { 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); + looptimer(8000, F("Ethloop2 read")); buffer[count] = '\0'; // terminate the string properly if (Diag::ETHERNET) DIAG(F(",count=%d:%e"), count, buffer); // execute with data going directly back @@ -239,7 +240,14 @@ void EthernetInterface::loop2() { } 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()); + { + char buffer[count+1]; // one extra for '\0' + for(int i=0;iread(); + } + buffer[count]=0; + clients[socketOut].write(buffer,count); + } clients[socketOut].flush(); //maybe } looptimer(8000, F("Ethloop after outbound")); diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index febb419..eca7c82 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-fozzie-202408080852Z" +#define GITHUB_SHA "devel-fozzie-202408090945Z" From 80c8b3ef62ec936bd21a8420369a247bf4113dea Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 9 Aug 2024 11:57:54 +0200 Subject: [PATCH 05/18] better name --- EthernetInterface.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index a7ca0be..a5bcb08 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -241,12 +241,12 @@ void EthernetInterface::loop2() { int count=outboundRing->count(); if (Diag::ETHERNET) DIAG(F("Ethernet reply socket=%d, count=:%d"), socketOut,count); { - char buffer[count+1]; // one extra for '\0' + char tmpbuf[count+1]; // one extra for '\0' for(int i=0;iread(); + tmpbuf[i] = outboundRing->read(); } - buffer[count]=0; - clients[socketOut].write(buffer,count); + tmpbuf[count]=0; + clients[socketOut].write(tmpbuf,count); } clients[socketOut].flush(); //maybe } From 92288603bfefa75561180dc39151e4bbbc6ce054 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 9 Aug 2024 12:01:53 +0200 Subject: [PATCH 06/18] do not available, just try to read --- EthernetInterface.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index a5bcb08..584ad2e 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -202,18 +202,18 @@ void EthernetInterface::loop2() { // check for incoming data from all possible clients for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) { - if (clients[socket]) { - - 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); - looptimer(8000, F("Ethloop2 read")); + if (clients[socket]) { + + // read bytes from a client + int count = clients[socket].read(buffer, MAX_ETH_BUFFER); + looptimer(8000, F("Ethloop2 read")); + if (count > 0) { + if (Diag::ETHERNET) DIAG(F("Ethernet: available socket=%d,count=%d"), socket, count); buffer[count] = '\0'; // terminate the string properly - if (Diag::ETHERNET) DIAG(F(",count=%d:%e"), count, buffer); + if (Diag::ETHERNET) DIAG(F("buffer:%e"), buffer); // execute with data going directly back CommandDistributor::parse(socket,buffer,outboundRing); + looptimer(2000, F("Ethloop2 parse")); return; // limit the amount of processing that takes place within 1 loop() cycle. } } From 8c3c5dfe3304c65b1bbe54b3e4edd72d75d25c19 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 9 Aug 2024 14:34:30 +0200 Subject: [PATCH 07/18] do not flush --- EthernetInterface.cpp | 3 ++- GITHUB_SHA.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 584ad2e..423d60e 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -248,7 +248,8 @@ void EthernetInterface::loop2() { tmpbuf[count]=0; clients[socketOut].write(tmpbuf,count); } - clients[socketOut].flush(); //maybe + // do trust write does its thing and not flush + // clients[socketOut].flush(); //maybe } looptimer(8000, F("Ethloop after outbound")); diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index eca7c82..f8c7e12 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-fozzie-202408090945Z" +#define GITHUB_SHA "devel-fozzie-202408091233Z" From c8c3697fa00fd468b0e19b89b46ae3f01ea9779e Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 9 Aug 2024 15:02:11 +0200 Subject: [PATCH 08/18] write buffer --- EthernetInterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 423d60e..3e1a51a 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -239,13 +239,14 @@ 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); { char tmpbuf[count+1]; // one extra for '\0' for(int i=0;iread(); } tmpbuf[count]=0; + if (Diag::ETHERNET) + DIAG(F("Ethernet reply socket=%d, count=%d, buf:%e"), socketOut,count,tmpbuf); clients[socketOut].write(tmpbuf,count); } // do trust write does its thing and not flush From 048ba3fd1e9891768b596333da8b4d9278e78a2a Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sat, 17 Aug 2024 20:18:59 +0200 Subject: [PATCH 09/18] replace socket.connected() with check for return value of socket.read() --- EthernetInterface.cpp | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 3e1a51a..e87316c 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -208,28 +208,24 @@ void EthernetInterface::loop2() { int count = clients[socket].read(buffer, MAX_ETH_BUFFER); looptimer(8000, F("Ethloop2 read")); if (count > 0) { - if (Diag::ETHERNET) DIAG(F("Ethernet: available socket=%d,count=%d"), socket, count); - buffer[count] = '\0'; // terminate the string properly - if (Diag::ETHERNET) DIAG(F("buffer:%e"), buffer); - // execute with data going directly back - CommandDistributor::parse(socket,buffer,outboundRing); - looptimer(2000, F("Ethloop2 parse")); - return; // limit the amount of processing that takes place within 1 loop() cycle. - } - } + if (Diag::ETHERNET) DIAG(F("Ethernet: available socket=%d,count=%d"), socket, count); + buffer[count] = '\0'; // terminate the string properly + if (Diag::ETHERNET) DIAG(F("buffer:%e"), buffer); + // execute with data going directly back + CommandDistributor::parse(socket,buffer,outboundRing); + looptimer(2000, F("Ethloop2 parse")); + return; // limit the amount of processing that takes place within 1 loop() cycle. + } else if (count == 0) { + // The client has disconnected + clients[socket].stop(); + CommandDistributor::forget(socket); + if (Diag::ETHERNET) DIAG(F("Ethernet: disconnect %d "), socket); + } + // fall through if count = -1 (no bytes available) + } } looptimer(8000, F("Ethloop2 after incoming")); - // stop any clients which disconnect - for (int socket = 0; socket Date: Sat, 17 Aug 2024 23:09:09 +0200 Subject: [PATCH 10/18] tag --- GITHUB_SHA.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index f8c7e12..6c85e61 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-fozzie-202408091233Z" +#define GITHUB_SHA "devel-fozzie-202408172108Z" From 5db19a0fb8ea6e68bf313ae5d60f23b8df16ad81 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 18 Aug 2024 20:32:05 +0100 Subject: [PATCH 11/18] Ethgernet simplification --- EthernetInterface.cpp | 218 +++++++++++++----------------------------- EthernetInterface.h | 15 +-- 2 files changed, 72 insertions(+), 161 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index e87316c..bf3c0a0 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -32,76 +32,37 @@ extern void looptimer(unsigned long timeout, const FSH* message); -EthernetInterface * EthernetInterface::singleton=NULL; +bool EthernetInterface::connected=false; +EthernetServer * EthernetInterface::server= nullptr; +EthernetClient EthernetInterface::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 +uint8_t EthernetInterface::buffer[MAX_ETH_BUFFER+1]; // buffer used by TCP for the recv +RingStream * EthernetInterface::outboundRing = nullptr; + /** * @brief Setup Ethernet Connection * */ void EthernetInterface::setup() { - if (singleton!=NULL) { - DIAG(F("Prog Error!")); - return; - } - if ((singleton=new EthernetInterface())) - return; - DIAG(F("Ethernet not initialized")); -}; + connected=false; - -#ifdef IP_ADDRESS -static IPAddress myIP(IP_ADDRESS); -#endif - -/** - * @brief Aquire IP Address from DHCP and start server - * - * @return true - * @return false - */ -EthernetInterface::EthernetInterface() -{ byte mac[6]; DCCTimer::getSimulatedMacAddress(mac); - connected=false; - -#ifdef IP_ADDRESS - Ethernet.begin(mac, myIP); -#else + DIAG(F("Ethernet begin")); if (Ethernet.begin(mac) == 0) { DIAG(F("Ethernet.begin FAILED")); return; } -#endif - if (Ethernet.hardwareStatus() == EthernetNoHardware) { - DIAG(F("Ethernet shield not found or W5100")); - } - - unsigned long startmilli = millis(); - while ((millis() - startmilli) < 5500) { // Loop to give time to check for cable connection - if (Ethernet.linkStatus() == LinkON) - break; - DIAG(F("Ethernet waiting for link (1sec) ")); - delay(1000); - } - // now we either do have link of we have a W5100 - // where we do not know if we have link. That's - // the reason to now run checkLink. - // CheckLinks sets up outboundRing if it does - // not exist yet as well. - checkLink(); + auto ip = Ethernet.localIP(); // look what IP was obtained (dynamic or static) + server = new EthernetServer(IP_PORT); // Ethernet Server listening on default port IP_PORT + server->begin(); + LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + LCD(5,F("Port:%d"), IP_PORT); + outboundRing=new RingStream(OUTBOUND_RING_SIZE); + connected=true; } -/** - * @brief Cleanup any resources - * - * @return none - */ -EthernetInterface::~EthernetInterface() { - delete server; - delete outboundRing; -} /** * @brief Main loop for the EthernetInterface @@ -109,76 +70,28 @@ EthernetInterface::~EthernetInterface() { */ void EthernetInterface::loop() { - if (!singleton || (!singleton->checkLink())) - return; - + if (!connected) return; + //DIAG(F("maintain")); switch (Ethernet.maintain()) { case 1: //renewed fail DIAG(F("Ethernet Error: renewed fail")); - singleton=NULL; + connected=false; return; case 3: //rebind fail DIAG(F("Ethernet Error: rebind fail")); - singleton=NULL; + connected=false; return; default: //nothing happened + //DIAG(F("maintained")); break; } - looptimer(8000, F("Ethloop after maintain")); - singleton->loop2(); -} + // looptimer(8000, F("Ethloop after maintain")); -/** - * @brief Checks ethernet link cable status and detects when it connects / disconnects - * - * @return true when cable is connected, false otherwise - */ -bool EthernetInterface::checkLink() { - if (Ethernet.linkStatus() != LinkOFF) { // check for not linkOFF instead of linkON as the W5100 does return LinkUnknown - //if we are not connected yet, setup a new server - if(!connected) { - DIAG(F("Ethernet cable connected")); - connected=true; - #ifdef IP_ADDRESS - Ethernet.setLocalIP(myIP); // for static IP, set it again - #endif - IPAddress ip = Ethernet.localIP(); // look what IP was obtained (dynamic or static) - server = new EthernetServer(IP_PORT); // Ethernet Server listening on default port IP_PORT - server->begin(); - LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); - LCD(5,F("Port:%d"), IP_PORT); - // only create a outboundRing it none exists, this may happen if the cable - // gets disconnected and connected again - if(!outboundRing) - outboundRing=new RingStream(OUTBOUND_RING_SIZE); - } - return true; - } else { // connected - DIAG(F("Ethernet cable disconnected")); - connected=false; - //clean up any client - for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) { - if(clients[socket].connected()) - clients[socket].stop(); - } - // tear down server - delete server; - server = nullptr; - LCD(4,F("IP: None")); - } - return false; -} - -void EthernetInterface::loop2() { - if (!outboundRing) { // no idea to call loop2() if we can't handle outgoing data in it - if (Diag::ETHERNET) DIAG(F("No outboundRing")); - return; - } // get client from the server - EthernetClient client = server->accept(); + auto client = server->accept(); // check for new client if (client) @@ -202,53 +115,56 @@ void EthernetInterface::loop2() { // check for incoming data from all possible clients for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) { - if (clients[socket]) { + if (!clients[socket]) continue; // socket is not in use - // read bytes from a client - int count = clients[socket].read(buffer, MAX_ETH_BUFFER); - looptimer(8000, F("Ethloop2 read")); - if (count > 0) { - if (Diag::ETHERNET) DIAG(F("Ethernet: available socket=%d,count=%d"), socket, count); - buffer[count] = '\0'; // terminate the string properly - if (Diag::ETHERNET) DIAG(F("buffer:%e"), buffer); - // execute with data going directly back - CommandDistributor::parse(socket,buffer,outboundRing); - looptimer(2000, F("Ethloop2 parse")); - return; // limit the amount of processing that takes place within 1 loop() cycle. - } else if (count == 0) { - // The client has disconnected - clients[socket].stop(); - CommandDistributor::forget(socket); - if (Diag::ETHERNET) DIAG(F("Ethernet: disconnect %d "), socket); - } - // fall through if count = -1 (no bytes available) - } - } - looptimer(8000, F("Ethloop2 after incoming")); + // read any bytes from this client + auto count = clients[socket].read(buffer, MAX_ETH_BUFFER); + + if (count<0) continue; // -1 indicates nothing to read + + if (count > 0) { // we have incoming data + buffer[count] = '\0'; // terminate the string properly + if (Diag::ETHERNET) DIAG(F("Ethernet s=%d, c=%d b=:%e"), socket, count, buffer); + // execute with data going directly back + CommandDistributor::parse(socket,buffer,outboundRing); + //looptimer(5000, F("Ethloop2 parse")); + return; // limit the amount of processing that takes place within 1 loop() cycle. + } + + // count=0 The client has disconnected + clients[socket].stop(); + CommandDistributor::forget(socket); + if (Diag::ETHERNET) DIAG(F("Ethernet: disconnect %d "), socket); + } + + //looptimer(8000, F("Ethloop2 after incoming")); WiThrottle::loop(outboundRing); - looptimer(8000, F("Ethloop after Withrottleloop")); + //looptimer(8000, F("Ethloop after Withrottleloop")); // handle at most 1 outbound transmission - int socketOut=outboundRing->read(); - if (socketOut >= MAX_SOCK_NUM) { - DIAG(F("Ethernet outboundRing socket=%d error"), socketOut); - } else if (socketOut >= 0) { - int count=outboundRing->count(); - { - char tmpbuf[count+1]; // one extra for '\0' - for(int i=0;iread(); - } - tmpbuf[count]=0; - if (Diag::ETHERNET) - DIAG(F("Ethernet reply socket=%d, count=%d, buf:%e"), socketOut,count,tmpbuf); - clients[socketOut].write(tmpbuf,count); - } - // do trust write does its thing and not flush - // clients[socketOut].flush(); //maybe - } - looptimer(8000, F("Ethloop after outbound")); + auto socketOut=outboundRing->read(); + if (socketOut<0) return; // no outbound pending + if (socketOut >= MAX_SOCK_NUM) { + // This is a catastrophic code failure and unrecoverable. + DIAG(F("Ethernet outboundRing s=%d error"), socketOut); + connected=false; + return; + } + + auto count=outboundRing->count(); + { + char tmpbuf[count+1]; // one extra for '\0' + for(int i=0;iread(); + } + tmpbuf[count]=0; + if (Diag::ETHERNET) DIAG(F("Ethernet reply s=%d, c=%d, b:%e"), + socketOut,count,tmpbuf); + clients[socketOut].write(tmpbuf,count); + } + + //looptimer(8000, F("Ethloop after outbound")); } #endif diff --git a/EthernetInterface.h b/EthernetInterface.h index 8078c3f..e03d79b 100644 --- a/EthernetInterface.h +++ b/EthernetInterface.h @@ -56,16 +56,11 @@ class EthernetInterface { static void loop(); private: - static EthernetInterface * singleton; - bool connected; - EthernetInterface(); - ~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 - uint8_t buffer[MAX_ETH_BUFFER+1]; // buffer used by TCP for the recv - RingStream * outboundRing = NULL; + static bool connected; + static EthernetServer * server; + static 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 + static uint8_t buffer[MAX_ETH_BUFFER+1]; // buffer used by TCP for the recv + static RingStream * outboundRing; }; #endif From edb02a00ceaa8608e402e5c74d2c5352e4e8500f Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 19 Aug 2024 08:59:32 +0200 Subject: [PATCH 12/18] allow static IP (again) --- EthernetInterface.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index bf3c0a0..27f6557 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -49,12 +49,21 @@ void EthernetInterface::setup() byte mac[6]; DCCTimer::getSimulatedMacAddress(mac); DIAG(F("Ethernet begin")); +#ifdef IP_ADDRESS + static IPAddress myIP(IP_ADDRESS); + Ethernet.begin(mac, myIP); +#else if (Ethernet.begin(mac) == 0) { - DIAG(F("Ethernet.begin FAILED")); - return; - } + LCD(4,F("IP: No DHCP")); + return; + } +#endif auto ip = Ethernet.localIP(); // look what IP was obtained (dynamic or static) + if (!ip) { + LCD(4,F("IP: None")); + return; + } server = new EthernetServer(IP_PORT); // Ethernet Server listening on default port IP_PORT server->begin(); LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); From 4d84eccac3dc79070c1999d48439aa145d9d92fc Mon Sep 17 00:00:00 2001 From: Asbelos Date: Tue, 20 Aug 2024 19:51:45 +0100 Subject: [PATCH 13/18] LCD and link warning --- EthernetInterface.cpp | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 27f6557..6b201c1 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -49,6 +49,7 @@ void EthernetInterface::setup() byte mac[6]; DCCTimer::getSimulatedMacAddress(mac); DIAG(F("Ethernet begin")); + #ifdef IP_ADDRESS static IPAddress myIP(IP_ADDRESS); Ethernet.begin(mac, myIP); @@ -66,8 +67,21 @@ void EthernetInterface::setup() } server = new EthernetServer(IP_PORT); // Ethernet Server listening on default port IP_PORT server->begin(); - LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); - LCD(5,F("Port:%d"), IP_PORT); + #ifdef LCD_DRIVER + const byte lcdData[]={LCD_DRIVER}; + const bool wideDisplay=lcdData[1]>=24; // data[1] is cols. + #else + const bool wideDisplay=true; + #endif + if (wideDisplay) { + // OLEDS or just usb diag is ok on one line. + LCD(4,F("IP %d.%d.%d.%d:%d"), ip[0], ip[1], ip[2], ip[3], IP_PORT); + } + else { // LCDs generally too narrow, so take 2 lines + LCD(4,F("IP %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + LCD(5,F("Port %d"), IP_PORT); + } + outboundRing=new RingStream(OUTBOUND_RING_SIZE); connected=true; } @@ -80,7 +94,22 @@ void EthernetInterface::setup() void EthernetInterface::loop() { if (!connected) return; - //DIAG(F("maintain")); + + static bool warnedAboutLink=false; + if (Ethernet.linkStatus() == LinkOFF){ + if (warnedAboutLink) return; + DIAG(F("Ethernet link OFF")); + warnedAboutLink=true; + return; + } + + // link status must be ok here + if (warnedAboutLink) { + DIAG(F("Ethernet link RESTORED")); + warnedAboutLink=false; + } + + // switch (Ethernet.maintain()) { case 1: //renewed fail @@ -97,8 +126,7 @@ void EthernetInterface::loop() //DIAG(F("maintained")); break; } - // looptimer(8000, F("Ethloop after maintain")); - + // get client from the server auto client = server->accept(); @@ -146,10 +174,7 @@ void EthernetInterface::loop() if (Diag::ETHERNET) DIAG(F("Ethernet: disconnect %d "), socket); } - //looptimer(8000, F("Ethloop2 after incoming")); - WiThrottle::loop(outboundRing); - //looptimer(8000, F("Ethloop after Withrottleloop")); // handle at most 1 outbound transmission auto socketOut=outboundRing->read(); @@ -174,6 +199,5 @@ void EthernetInterface::loop() clients[socketOut].write(tmpbuf,count); } - //looptimer(8000, F("Ethloop after outbound")); } #endif From dfe9e6b69f2a2c6c6322f6c0f0a889f09ffc78b8 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sun, 25 Aug 2024 17:01:58 +0200 Subject: [PATCH 14/18] platformio eth debug target --- platformio.ini | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/platformio.ini b/platformio.ini index b39b136..dc2e00c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -108,6 +108,23 @@ monitor_speed = 115200 monitor_echo = yes build_flags = +[env:mega2560-eth] +platform = atmelavr +board = megaatmega2560 +framework = arduino +lib_deps = + ${env.lib_deps} + arduino-libraries/Ethernet + MDNS_Generic + SPI +lib_ignore = WiFi101 + WiFi101_Generic + WiFiEspAT + WiFiMulti_Generic + WiFiNINA_Generic +monitor_speed = 115200 +monitor_echo = yes + [env:mega328] platform = atmelavr board = uno From 06a353cfa09e0e9b6c5c566dbf508e53309595e9 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 25 Aug 2024 16:29:59 +0100 Subject: [PATCH 15/18] stm32 merge (mdns disabled} --- EthernetInterface.cpp | 164 ++++++++++++++++++++++++++++-------------- EthernetInterface.h | 2 +- platformio.ini | 26 +++++++ 3 files changed, 136 insertions(+), 56 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 6b201c1..6943f03 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -29,8 +29,15 @@ #include "CommandDistributor.h" #include "WiThrottle.h" #include "DCCTimer.h" +#if __has_include ( "MDNS_Generic.h") + #include "MDNS_Generic.h" + // #define DO_MDNS !!!!!!!!!!!!! breaks mega + EthernetUDP udp; + MDNS mdns(udp); +#endif -extern void looptimer(unsigned long timeout, const FSH* message); + +//extern void looptimer(unsigned long timeout, const FSH* message); bool EthernetInterface::connected=false; EthernetServer * EthernetInterface::server= nullptr; @@ -42,48 +49,73 @@ RingStream * EthernetInterface::outboundRing = nullptr; * @brief Setup Ethernet Connection * */ -void EthernetInterface::setup() -{ - connected=false; +void EthernetInterface::setup() // STM32 VERSION +{ + DIAG(F("Ethernet begin")); + + #ifdef STM32_ETHERNET + // Set a HOSTNAME for the DHCP request - a nice to have, but hard it seems on LWIP for STM32 + // The default is "lwip", which is **always** set in STM32Ethernet/src/utility/ethernetif.cpp + // for some reason. One can edit it to instead read: + // #if LWIP_NETIF_HOSTNAME + // /* Initialize interface hostname */ + // if (netif->hostname == NULL) + // netif->hostname = "lwip"; + // #endif /* LWIP_NETIF_HOSTNAME */ + // Which seems more useful! We should propose the patch... so the following line actually works! + netif_set_hostname(&gnetif, WIFI_HOSTNAME); // Should probably be passed in the contructor... + #define _MAC_ MacAddressDefault() + #else byte mac[6]; DCCTimer::getSimulatedMacAddress(mac); - DIAG(F("Ethernet begin")); - -#ifdef IP_ADDRESS + #define _MAC_ mac + #endif + + #ifdef IP_ADDRESS static IPAddress myIP(IP_ADDRESS); - Ethernet.begin(mac, myIP); -#else - if (Ethernet.begin(mac) == 0) - { - LCD(4,F("IP: No DHCP")); - return; - } -#endif - auto ip = Ethernet.localIP(); // look what IP was obtained (dynamic or static) - if (!ip) { - LCD(4,F("IP: None")); - return; - } - server = new EthernetServer(IP_PORT); // Ethernet Server listening on default port IP_PORT - server->begin(); - #ifdef LCD_DRIVER - const byte lcdData[]={LCD_DRIVER}; - const bool wideDisplay=lcdData[1]>=24; // data[1] is cols. - #else - const bool wideDisplay=true; - #endif - if (wideDisplay) { - // OLEDS or just usb diag is ok on one line. - LCD(4,F("IP %d.%d.%d.%d:%d"), ip[0], ip[1], ip[2], ip[3], IP_PORT); - } - else { // LCDs generally too narrow, so take 2 lines - LCD(4,F("IP %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); - LCD(5,F("Port %d"), IP_PORT); - } + Ethernet.begin(_MAC_,myIP); + setup(false); + #else + if (Ethernet.begin(_MAC_)==0) + { + LCD(4,F("IP: No DHCP")); + return; + } + #endif + + auto ip = Ethernet.localIP(); // look what IP was obtained (dynamic or static) + if (!ip) { + LCD(4,F("IP: None")); + return; + } + server = new EthernetServer(IP_PORT); // Ethernet Server listening on default port IP_PORT + server->begin(); + + // Arrange display of IP address and port + #ifdef LCD_DRIVER + const byte lcdData[]={LCD_DRIVER}; + const bool wideDisplay=lcdData[1]>=24; // data[1] is cols. + #else + const bool wideDisplay=true; + #endif + if (wideDisplay) { + // OLEDS or just usb diag is ok on one line. + LCD(4,F("IP %d.%d.%d.%d:%d"), ip[0], ip[1], ip[2], ip[3], IP_PORT); + } + else { // LCDs generally too narrow, so take 2 lines + LCD(4,F("IP %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + LCD(5,F("Port %d"), IP_PORT); + } - outboundRing=new RingStream(OUTBOUND_RING_SIZE); - connected=true; + outboundRing=new RingStream(OUTBOUND_RING_SIZE); + #ifdef DO_MDNS + mdns.begin(Ethernet.localIP(), WIFI_HOSTNAME); // hostname + mdns.addServiceRecord(WIFI_HOSTNAME "._withrottle", IP_PORT, MDNSServiceTCP); + // Not sure if we need to run it once, but just in case! + mdns.run(); + #endif + connected=true; } @@ -109,6 +141,11 @@ void EthernetInterface::loop() warnedAboutLink=false; } + #ifdef DO_MDNS + // Always do this because we don't want traffic to intefere with being found! + mdns.run(); + #endif + // switch (Ethernet.maintain()) { case 1: @@ -127,27 +164,44 @@ void EthernetInterface::loop() break; } - // get client from the server - auto client = server->accept(); - - // check for new client - if (client) - { - if (Diag::ETHERNET) DIAG(F("Ethernet: New client ")); - byte socket; + // get client from the server + #if defined (STM32_ETHERNET) + // STM32Ethernet doesn't use accept(), just available() + auto client = server->available(); + if (client) { + // check for new client + byte socket; + bool sockfound = false; + for (socket = 0; socket < MAX_SOCK_NUM; socket++) + { + if (client == clients[socket]) + { + sockfound = true; + 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 - if (Diag::ETHERNET) DIAG(F("Socket %d"),socket); - clients[socket] = client; - break; - } + if (!clients[socket]) + { + clients[socket] = client; + sockFound=true; + if (Diag::ETHERNET) + DIAG(F("Ethernet: New client socket %d"), socket); + break; + } } - if (socket==MAX_SOCK_NUM) DIAG(F("new Ethernet OVERFLOW")); + } + if (!sockFound) DIAG(F("new Ethernet OVERFLOW")); } + + #else + auto client = server->accept(); + if (client) clients[client.getSocketNumber()]=client; + #endif + // check for incoming data from all possible clients for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) diff --git a/EthernetInterface.h b/EthernetInterface.h index e03d79b..8440dde 100644 --- a/EthernetInterface.h +++ b/EthernetInterface.h @@ -45,7 +45,7 @@ * */ -#define MAX_ETH_BUFFER 512 +#define MAX_ETH_BUFFER 128 #define OUTBOUND_RING_SIZE 2048 class EthernetInterface { diff --git a/platformio.ini b/platformio.ini index b39b136..6985327 100644 --- a/platformio.ini +++ b/platformio.ini @@ -104,6 +104,14 @@ lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI + MDNS_Generic + +lib_ignore = WiFi101 + WiFi101_Generic + WiFiEspAT + WiFiMulti_Generic + WiFiNINA_Generic + monitor_speed = 115200 monitor_echo = yes build_flags = @@ -246,6 +254,24 @@ monitor_echo = yes ; Experimental - Ethernet work still in progress ; +[env:Nucleo-F429ZI] +platform = ststm32 +board = nucleo_f429zi +framework = arduino +lib_deps = ${env.lib_deps} + stm32duino/STM32Ethernet @ ^1.3.0 + stm32duino/STM32duino LwIP @ ^2.1.2 + MDNS_Generic +lib_ignore = WiFi101 + WiFi101_Generic + WiFiEspAT + WiFiMulti_Generic + WiFiNINA_Generic +build_flags = -std=c++17 -Os -g2 -Wunused-variable +monitor_speed = 115200 +monitor_echo = yes +upload_protocol = stlink + ; [env:Nucleo-F429ZI] ; platform = ststm32 ; board = nucleo_f429zi From 4ed2ee9adc9e9921e6ea883a45293ba2159a4bbc Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 25 Aug 2024 16:50:49 +0100 Subject: [PATCH 16/18] mDNS restored on mega --- EthernetInterface.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 6943f03..bea4162 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -31,13 +31,13 @@ #include "DCCTimer.h" #if __has_include ( "MDNS_Generic.h") #include "MDNS_Generic.h" - // #define DO_MDNS !!!!!!!!!!!!! breaks mega + #define DO_MDNS EthernetUDP udp; MDNS mdns(udp); #endif -//extern void looptimer(unsigned long timeout, const FSH* message); +extern void looptimer(unsigned long timeout, const FSH* message); bool EthernetInterface::connected=false; EthernetServer * EthernetInterface::server= nullptr; @@ -52,7 +52,11 @@ RingStream * EthernetInterface::outboundRing = nullptr; void EthernetInterface::setup() // STM32 VERSION { - DIAG(F("Ethernet begin")); + DIAG(F("Ethernet begin" + #ifdef DO_MDNS + " with mDNS" + #endif + )); #ifdef STM32_ETHERNET // Set a HOSTNAME for the DHCP request - a nice to have, but hard it seems on LWIP for STM32 @@ -126,7 +130,8 @@ void EthernetInterface::setup() // STM32 VERSION void EthernetInterface::loop() { if (!connected) return; - + looptimer(5000, F("E.loop")); + static bool warnedAboutLink=false; if (Ethernet.linkStatus() == LinkOFF){ if (warnedAboutLink) return; @@ -134,7 +139,8 @@ void EthernetInterface::loop() warnedAboutLink=true; return; } - + looptimer(5000, F("E.loop warn")); + // link status must be ok here if (warnedAboutLink) { DIAG(F("Ethernet link RESTORED")); @@ -144,6 +150,8 @@ void EthernetInterface::loop() #ifdef DO_MDNS // Always do this because we don't want traffic to intefere with being found! mdns.run(); + looptimer(5000, F("E.mdns")); + #endif // @@ -163,7 +171,8 @@ void EthernetInterface::loop() //DIAG(F("maintained")); break; } - + looptimer(5000, F("E.maintain")); + // get client from the server #if defined (STM32_ETHERNET) // STM32Ethernet doesn't use accept(), just available() From 8245208b2be908064202bf1239c4baaf605792f6 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 25 Aug 2024 17:26:33 +0100 Subject: [PATCH 17/18] stm32 compiles --- EthernetInterface.cpp | 15 ++++++--------- EthernetInterface.h | 8 ++++++++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index bea4162..4b83f6d 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -69,19 +69,16 @@ void EthernetInterface::setup() // STM32 VERSION // #endif /* LWIP_NETIF_HOSTNAME */ // Which seems more useful! We should propose the patch... so the following line actually works! netif_set_hostname(&gnetif, WIFI_HOSTNAME); // Should probably be passed in the contructor... - #define _MAC_ MacAddressDefault() - #else + #endif + byte mac[6]; DCCTimer::getSimulatedMacAddress(mac); - #define _MAC_ mac - #endif #ifdef IP_ADDRESS static IPAddress myIP(IP_ADDRESS); - Ethernet.begin(_MAC_,myIP); - setup(false); + Ethernet.begin(mac,myIP); #else - if (Ethernet.begin(_MAC_)==0) + if (Ethernet.begin(mac)==0) { LCD(4,F("IP: No DHCP")); return; @@ -196,14 +193,14 @@ void EthernetInterface::loop() if (!clients[socket]) { clients[socket] = client; - sockFound=true; + sockfound=true; if (Diag::ETHERNET) DIAG(F("Ethernet: New client socket %d"), socket); break; } } } - if (!sockFound) DIAG(F("new Ethernet OVERFLOW")); + if (!sockfound) DIAG(F("new Ethernet OVERFLOW")); } #else diff --git a/EthernetInterface.h b/EthernetInterface.h index 8440dde..9ea2718 100644 --- a/EthernetInterface.h +++ b/EthernetInterface.h @@ -35,6 +35,14 @@ #if defined (ARDUINO_TEENSY41) #include //TEENSY Ethernet Treiber #include +#elif defined (ARDUINO_NUCLEO_F429ZI) || defined (ARDUINO_NUCLEO_F439ZI) || defined (ARDUINO_NUCLEO_F4X9ZI) + #include +// #include "STM32lwipopts.h" + #include + #include + extern "C" struct netif gnetif; + #define STM32_ETHERNET + #define MAX_SOCK_NUM 8 #else #include "Ethernet.h" #endif From 30236f9b36629544febe02ef9723075b2d6d7046 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Fri, 30 Aug 2024 11:52:27 +0800 Subject: [PATCH 18/18] STM32 Ethernet fixed --- EthernetInterface.cpp | 11 +++++------ EthernetInterface.h | 8 ++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index bea4162..8e84569 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -69,12 +69,11 @@ void EthernetInterface::setup() // STM32 VERSION // #endif /* LWIP_NETIF_HOSTNAME */ // Which seems more useful! We should propose the patch... so the following line actually works! netif_set_hostname(&gnetif, WIFI_HOSTNAME); // Should probably be passed in the contructor... - #define _MAC_ MacAddressDefault() - #else +#endif + byte mac[6]; DCCTimer::getSimulatedMacAddress(mac); #define _MAC_ mac - #endif #ifdef IP_ADDRESS static IPAddress myIP(IP_ADDRESS); @@ -180,16 +179,16 @@ void EthernetInterface::loop() if (client) { // check for new client byte socket; - bool sockfound = false; + bool sockFound = false; for (socket = 0; socket < MAX_SOCK_NUM; socket++) { if (client == clients[socket]) { - sockfound = true; + sockFound = true; break; } } - if (!sockfound) + if (!sockFound) { // new client for (socket = 0; socket < MAX_SOCK_NUM; socket++) { diff --git a/EthernetInterface.h b/EthernetInterface.h index 8440dde..9ea2718 100644 --- a/EthernetInterface.h +++ b/EthernetInterface.h @@ -35,6 +35,14 @@ #if defined (ARDUINO_TEENSY41) #include //TEENSY Ethernet Treiber #include +#elif defined (ARDUINO_NUCLEO_F429ZI) || defined (ARDUINO_NUCLEO_F439ZI) || defined (ARDUINO_NUCLEO_F4X9ZI) + #include +// #include "STM32lwipopts.h" + #include + #include + extern "C" struct netif gnetif; + #define STM32_ETHERNET + #define MAX_SOCK_NUM 8 #else #include "Ethernet.h" #endif