1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-22 23:56:13 +01:00

STM32 Ethernet support

This commit is contained in:
pmantoine 2024-09-28 19:48:11 +08:00
parent dc481a2f0c
commit 07ab7286ba
6 changed files with 133 additions and 79 deletions

View File

@ -1,8 +1,10 @@
/* /*
* © 2024 Morten "Doc" Nielsen
* © 2023-2024 Paul M. Antoine
* © 2022 Bruno Sanches * © 2022 Bruno Sanches
* © 2021 Fred Decker * © 2021 Fred Decker
* © 2020-2022 Harald Barth * © 2020-2022 Harald Barth
* © 2020-2021 Chris Harlow * © 2020-2024 Chris Harlow
* © 2020 Gregor Baues * © 2020 Gregor Baues
* All rights reserved. * All rights reserved.
* *
@ -36,9 +38,14 @@
MDNS mdns(udp); MDNS mdns(udp);
#endif #endif
//extern void looptimer(unsigned long timeout, const FSH* message);
#define looptimer(a,b)
bool EthernetInterface::connected=false; bool EthernetInterface::connected=false;
EthernetServer * EthernetInterface::server= nullptr; 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 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
bool EthernetInterface::inUse[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 uint8_t EthernetInterface::buffer[MAX_ETH_BUFFER+1]; // buffer used by TCP for the recv
RingStream * EthernetInterface::outboundRing = nullptr; RingStream * EthernetInterface::outboundRing = nullptr;
@ -47,12 +54,13 @@ RingStream * EthernetInterface::outboundRing = nullptr;
* *
*/ */
void EthernetInterface::setup() // STM32 VERSION void EthernetInterface::setup()
{ {
DIAG(F("Ethernet begin" DIAG(F("Ethernet starting"
#ifdef DO_MDNS #ifdef DO_MDNS
" with mDNS" " (with mDNS)"
#endif #endif
" Please be patient, especially if no cable is connected!"
)); ));
#ifdef STM32_ETHERNET #ifdef STM32_ETHERNET
@ -116,6 +124,47 @@ void EthernetInterface::setup() // STM32 VERSION
connected=true; connected=true;
} }
#if defined (STM32_ETHERNET)
void EthernetInterface::acceptClient() { // STM32 version
auto client=server->available();
if (!client) return;
// check for existing client
for (byte socket = 0; socket < MAX_SOCK_NUM; socket++)
if (inUse[socket] && client == clients[socket]) return;
// new client
for (byte socket = 0; socket < MAX_SOCK_NUM; socket++)
{
if (!inUse[socket])
{
clients[socket] = client;
inUse[socket]=true;
if (Diag::ETHERNET)
DIAG(F("Ethernet: New client socket %d"), socket);
return;
}
}
DIAG(F("Ethernet OVERFLOW"));
}
#else
void EthernetInterface::acceptClient() { // non-STM32 version
auto client=server->accept();
if (!client) return;
auto socket=client.getSocketNumber();
clients[socket]=client;
inUse[socket]=true;
if (Diag::ETHERNET)
DIAG(F("Ethernet: New client socket %d"), socket);
}
#endif
void EthernetInterface::dropClient(byte socket)
{
clients[socket].stop();
inUse[socket]=false;
CommandDistributor::forget(socket);
if (Diag::ETHERNET) DIAG(F("Ethernet: Disconnect %d "), socket);
}
/** /**
* @brief Main loop for the EthernetInterface * @brief Main loop for the EthernetInterface
@ -124,7 +173,8 @@ void EthernetInterface::setup() // STM32 VERSION
void EthernetInterface::loop() void EthernetInterface::loop()
{ {
if (!connected) return; if (!connected) return;
looptimer(5000, F("E.loop"));
static bool warnedAboutLink=false; static bool warnedAboutLink=false;
if (Ethernet.linkStatus() == LinkOFF){ if (Ethernet.linkStatus() == LinkOFF){
if (warnedAboutLink) return; if (warnedAboutLink) return;
@ -132,7 +182,8 @@ void EthernetInterface::loop()
warnedAboutLink=true; warnedAboutLink=true;
return; return;
} }
looptimer(5000, F("E.loop warn"));
// link status must be ok here // link status must be ok here
if (warnedAboutLink) { if (warnedAboutLink) {
DIAG(F("Ethernet link RESTORED")); DIAG(F("Ethernet link RESTORED"));
@ -142,6 +193,8 @@ void EthernetInterface::loop()
#ifdef DO_MDNS #ifdef DO_MDNS
// Always do this because we don't want traffic to intefere with being found! // Always do this because we don't want traffic to intefere with being found!
mdns.run(); mdns.run();
looptimer(5000, F("E.mdns"));
#endif #endif
// //
@ -161,50 +214,22 @@ void EthernetInterface::loop()
//DIAG(F("maintained")); //DIAG(F("maintained"));
break; break;
} }
looptimer(5000, F("E.maintain"));
// get client from the server
acceptClient();
// get client from the server // handle disconnected sockets because STM32 library doesnt
#if defined (STM32_ETHERNET) // do the read==0 response.
// STM32Ethernet doesn't use accept(), just available() for (byte socket = 0; socket < MAX_SOCK_NUM; socket++)
auto client = server->available(); {
if (client) { if (inUse[socket] && !clients[socket].connected()) dropClient(socket);
// 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])
{
clients[socket] = client;
sockfound=true;
if (Diag::ETHERNET)
DIAG(F("Ethernet: New client socket %d"), socket);
break;
}
}
}
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 // check for incoming data from all possible clients
for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) for (byte socket = 0; socket < MAX_SOCK_NUM; socket++)
{ {
if (!clients[socket]) continue; // socket is not in use if (!inUse[socket]) continue; // socket is not in use
// read any bytes from this client // read any bytes from this client
auto count = clients[socket].read(buffer, MAX_ETH_BUFFER); auto count = clients[socket].read(buffer, MAX_ETH_BUFFER);
@ -216,14 +241,13 @@ void EthernetInterface::loop()
if (Diag::ETHERNET) DIAG(F("Ethernet s=%d, c=%d b=:%e"), socket, count, buffer); if (Diag::ETHERNET) DIAG(F("Ethernet s=%d, c=%d b=:%e"), socket, count, buffer);
// execute with data going directly back // execute with data going directly back
CommandDistributor::parse(socket,buffer,outboundRing); CommandDistributor::parse(socket,buffer,outboundRing);
//looptimer(5000, F("Ethloop2 parse"));
return; // limit the amount of processing that takes place within 1 loop() cycle. return; // limit the amount of processing that takes place within 1 loop() cycle.
} }
// count=0 The client has disconnected // count=0 The client has disconnected
clients[socket].stop(); dropClient(socket);
CommandDistributor::forget(socket); }
if (Diag::ETHERNET) DIAG(F("Ethernet: disconnect %d "), socket);
}
WiThrottle::loop(outboundRing); WiThrottle::loop(outboundRing);
@ -245,9 +269,11 @@ void EthernetInterface::loop()
tmpbuf[i] = outboundRing->read(); tmpbuf[i] = outboundRing->read();
} }
tmpbuf[count]=0; tmpbuf[count]=0;
if (Diag::ETHERNET) DIAG(F("Ethernet reply s=%d, c=%d, b:%e"), if (inUse[socketOut]) {
if (Diag::ETHERNET) DIAG(F("Ethernet reply s=%d, c=%d, b:%e"),
socketOut,count,tmpbuf); socketOut,count,tmpbuf);
clients[socketOut].write(tmpbuf,count); clients[socketOut].write(tmpbuf,count);
}
} }
} }

View File

@ -1,8 +1,10 @@
/* /*
* © 2023-2024 Paul M. Antoine
* © 2021 Neil McKechnie * © 2021 Neil McKechnie
* © 2021 Mike S * © 2021 Mike S
* © 2021 Fred Decker * © 2021 Fred Decker
* © 2020-2021 Chris Harlow * © 2020-2022 Harald Barth
* © 2020-2024 Chris Harlow
* © 2020 Gregor Baues * © 2020 Gregor Baues
* All rights reserved. * All rights reserved.
* *
@ -35,6 +37,7 @@
#if defined (ARDUINO_TEENSY41) #if defined (ARDUINO_TEENSY41)
#include <NativeEthernet.h> //TEENSY Ethernet Treiber #include <NativeEthernet.h> //TEENSY Ethernet Treiber
#include <NativeEthernetUdp.h> #include <NativeEthernetUdp.h>
#define MAX_SOCK_NUM 4
#elif defined (ARDUINO_NUCLEO_F429ZI) || defined (ARDUINO_NUCLEO_F439ZI) || defined (ARDUINO_NUCLEO_F4X9ZI) #elif defined (ARDUINO_NUCLEO_F429ZI) || defined (ARDUINO_NUCLEO_F439ZI) || defined (ARDUINO_NUCLEO_F4X9ZI)
#include <LwIP.h> #include <LwIP.h>
// #include "STM32lwipopts.h" // #include "STM32lwipopts.h"
@ -67,8 +70,12 @@ class EthernetInterface {
static bool connected; static bool connected;
static EthernetServer * server; 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 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 bool inUse[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 uint8_t buffer[MAX_ETH_BUFFER+1]; // buffer used by TCP for the recv
static RingStream * outboundRing; static RingStream * outboundRing;
static void acceptClient();
static void dropClient(byte socketnum);
}; };
#endif #endif

View File

@ -38,8 +38,9 @@
*****************************************************************************/ *****************************************************************************/
#if defined(I2C_USE_INTERRUPTS) && defined(ARDUINO_ARCH_STM32) #if defined(I2C_USE_INTERRUPTS) && defined(ARDUINO_ARCH_STM32)
#if defined(ARDUINO_NUCLEO_F401RE) || defined(ARDUINO_NUCLEO_F411RE) || defined(ARDUINO_NUCLEO_F446RE) \ #if defined(ARDUINO_NUCLEO_F401RE) || defined(ARDUINO_NUCLEO_F411RE) || defined(ARDUINO_NUCLEO_F446RE) \
|| defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F413ZH) \ || defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F413ZH) || defined(ARDUINO_NUCLEO_F446ZE) \
|| defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F446ZE) || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F4X9ZI)
// Assume I2C1 for now - default I2C bus on Nucleo-F411RE and likely all Nucleo-64 // Assume I2C1 for now - default I2C bus on Nucleo-F411RE and likely all Nucleo-64
// and Nucleo-144 variants // and Nucleo-144 variants
I2C_TypeDef *s = I2C1; I2C_TypeDef *s = I2C1;

View File

@ -75,11 +75,19 @@
#define SAMD_STANDARD_MOTOR_SHIELD STANDARD_MOTOR_SHIELD #define SAMD_STANDARD_MOTOR_SHIELD STANDARD_MOTOR_SHIELD
#define STM32_STANDARD_MOTOR_SHIELD STANDARD_MOTOR_SHIELD #define STM32_STANDARD_MOTOR_SHIELD STANDARD_MOTOR_SHIELD
#if defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F4X9ZI)
// EX 8874 based shield connected to a 3V3 system with 12-bit (4096) ADC
// The Ethernet capable STM32 models cannot use Channel B BRAKE on D8, and must use the ALT pin of D6,
// AND cannot use Channel B PWN on D11, but must use the ALT pin of D5
#define EX8874_SHIELD F("EX8874"), \
new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 1.27, 5000, A4), \
new MotorDriver( 5, 13, UNUSED_PIN, 6, A1, 1.27, 5000, A5)
#else
// EX 8874 based shield connected to a 3V3 system with 12-bit (4096) ADC // EX 8874 based shield connected to a 3V3 system with 12-bit (4096) ADC
#define EX8874_SHIELD F("EX8874"), \ #define EX8874_SHIELD F("EX8874"), \
new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 1.27, 5000, A4), \ new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 1.27, 5000, A4), \
new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 1.27, 5000, A5) new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 1.27, 5000, A5)
#endif
#elif defined(ARDUINO_ARCH_ESP32) #elif defined(ARDUINO_ARCH_ESP32)
// STANDARD shield on an ESPDUINO-32 (ESP32 in Uno form factor). The shield must be eiter the // STANDARD shield on an ESPDUINO-32 (ESP32 in Uno form factor). The shield must be eiter the

View File

@ -202,7 +202,7 @@ monitor_speed = 115200
monitor_echo = yes monitor_echo = yes
[env:Nucleo-F411RE] [env:Nucleo-F411RE]
platform = ststm32 platform = ststm32 @ 17.6.0
board = nucleo_f411re board = nucleo_f411re
framework = arduino framework = arduino
lib_deps = ${env.lib_deps} lib_deps = ${env.lib_deps}
@ -211,7 +211,7 @@ monitor_speed = 115200
monitor_echo = yes monitor_echo = yes
[env:Nucleo-F446RE] [env:Nucleo-F446RE]
platform = ststm32 platform = ststm32 @ 17.6.0
board = nucleo_f446re board = nucleo_f446re
framework = arduino framework = arduino
lib_deps = ${env.lib_deps} lib_deps = ${env.lib_deps}
@ -223,7 +223,7 @@ monitor_echo = yes
; tested as yet ; tested as yet
; ;
[env:Nucleo-F401RE] [env:Nucleo-F401RE]
platform = ststm32 platform = ststm32 @ 17.6.0
board = nucleo_f401re board = nucleo_f401re
framework = arduino framework = arduino
lib_deps = ${env.lib_deps} lib_deps = ${env.lib_deps}
@ -236,7 +236,7 @@ monitor_echo = yes
; installed before you can let PlatformIO see this ; installed before you can let PlatformIO see this
; ;
; [env:Nucleo-F413ZH] ; [env:Nucleo-F413ZH]
; platform = ststm32 ; platform = ststm32 @ 17.6.0
; board = nucleo_f413zh ; board = nucleo_f413zh
; framework = arduino ; framework = arduino
; lib_deps = ${env.lib_deps} ; lib_deps = ${env.lib_deps}
@ -248,7 +248,7 @@ monitor_echo = yes
; installed before you can let PlatformIO see this ; installed before you can let PlatformIO see this
; ;
[env:Nucleo-F446ZE] [env:Nucleo-F446ZE]
platform = ststm32 platform = ststm32 @ 17.6.0
board = nucleo_f446ze board = nucleo_f446ze
framework = arduino framework = arduino
lib_deps = ${env.lib_deps} lib_deps = ${env.lib_deps}
@ -260,8 +260,8 @@ monitor_echo = yes
; installed before you can let PlatformIO see this ; installed before you can let PlatformIO see this
; ;
; [env:Nucleo-F412ZG] ; [env:Nucleo-F412ZG]
; platform = ststm32 ; platform = ststm32 @ 17.6.0
; board = blah_f412zg ; board = nucleo_f412zg
; framework = arduino ; framework = arduino
; lib_deps = ${env.lib_deps} ; lib_deps = ${env.lib_deps}
; build_flags = -std=c++17 -Os -g2 -Wunused-variable ; build_flags = -std=c++17 -Os -g2 -Wunused-variable
@ -272,12 +272,12 @@ monitor_echo = yes
; Experimental - Ethernet work still in progress ; Experimental - Ethernet work still in progress
; ;
[env:Nucleo-F429ZI] [env:Nucleo-F429ZI]
platform = ststm32 platform = ststm32 @ 17.6.0
board = nucleo_f429zi board = nucleo_f429zi
framework = arduino framework = arduino
lib_deps = ${env.lib_deps} lib_deps = ${env.lib_deps}
stm32duino/STM32Ethernet @ ^1.3.0 stm32duino/STM32Ethernet @ ^1.4.0
stm32duino/STM32duino LwIP @ ^2.1.2 stm32duino/STM32duino LwIP @ ^2.1.3
MDNS_Generic MDNS_Generic
lib_ignore = WiFi101 lib_ignore = WiFi101
WiFi101_Generic WiFi101_Generic
@ -289,18 +289,29 @@ monitor_speed = 115200
monitor_echo = yes monitor_echo = yes
upload_protocol = stlink upload_protocol = stlink
; [env:Nucleo-F429ZI] ; Experimental - Ethernet work still in progress
; platform = ststm32 ;
; board = nucleo_f429zi [env:Nucleo-F439ZI]
; framework = arduino platform = ststm32 @ 17.6.0
; lib_deps = ${env.lib_deps} ; board = nucleo_f439zi
; arduino-libraries/Ethernet @ ^2.0.1 ; Temporarily treat it as an F429ZI (they are code compatible) until
; stm32duino/STM32Ethernet @ ^1.3.0 ; the PR to PlatformIO to update the F439ZI JSON file is available
; stm32duino/STM32duino LwIP @ ^2.1.2 ; PMA - 28-Sep-2024
; build_flags = -std=c++17 -Os -g2 -Wunused-variable board = nucleo_f429zi
; monitor_speed = 115200 framework = arduino
; monitor_echo = yes lib_deps = ${env.lib_deps}
; upload_protocol = stlink stm32duino/STM32Ethernet @ ^1.4.0
stm32duino/STM32duino LwIP @ ^2.1.3
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:Teensy3_2] [env:Teensy3_2]
platform = teensy platform = teensy

View File

@ -3,8 +3,9 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "5.2.80" #define VERSION "5.2.81"
// 5.2.80 - EthernetInterface upgrade // 5.2.81 - STM32 Ethernet boards support, also now have specific EX8874 motor driver definition
// 5.2.80 - EthernetInterface upgrade, including STM32 Ethernet support
// 5.2.79 - serial manager loop that handles quoted strings // 5.2.79 - serial manager loop that handles quoted strings
// - WiFiESP32 reconfig // - WiFiESP32 reconfig
// 5.2.78 - NeoPixel support. // 5.2.78 - NeoPixel support.