From ee7ac2f79d4bbf5460bf1c60c58469ab5e3022b9 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Thu, 28 Jul 2022 00:00:56 +0200 Subject: [PATCH] make WiFi/Ethernet interface compatible with Arduino Ethernet API (#8645) * make WiFi/Ethernet interface compatible with Arduino Ethernet API provide some minimaly adapted examples from legacy * move ethernet compat globals to EthernetCompat.h * LegacyEthernet: add UDP example * adjust comments Co-authored-by: Max Prokhorov --- cores/esp8266/LwipIntf.h | 2 +- cores/esp8266/LwipIntfDev.h | 1 - .../LegacyAdvancedChatServer.ino | 126 ++++++++++++++ .../LegacyChatServer/LegacyChatServer.ino | 105 ++++++++++++ .../LegacyDhcpAddressPrinter.ino | 101 ++++++++++++ .../LegacyUDPSendReceiveString.ino | 156 ++++++++++++++++++ libraries/lwIP_Ethernet/src/EthernetCompat.h | 101 ++++++++++++ 7 files changed, 590 insertions(+), 2 deletions(-) create mode 100644 libraries/lwIP_Ethernet/examples/LegacyAdvancedChatServer/LegacyAdvancedChatServer.ino create mode 100644 libraries/lwIP_Ethernet/examples/LegacyChatServer/LegacyChatServer.ino create mode 100644 libraries/lwIP_Ethernet/examples/LegacyDhcpAddressPrinter/LegacyDhcpAddressPrinter.ino create mode 100644 libraries/lwIP_Ethernet/examples/LegacyUDPSendReceiveString/LegacyUDPSendReceiveString.ino create mode 100644 libraries/lwIP_Ethernet/src/EthernetCompat.h diff --git a/cores/esp8266/LwipIntf.h b/cores/esp8266/LwipIntf.h index 43941c4f2..8d0bb1dce 100644 --- a/cores/esp8266/LwipIntf.h +++ b/cores/esp8266/LwipIntf.h @@ -41,7 +41,7 @@ public: // ---- + --------- ------------- // local_ip | local_ip local_ip // arg1 | gateway dns1 - // arg2 | netmask [Agateway + // arg2 | netmask gateway // arg3 | dns1 netmask // // result stored into gateway/netmask/dns1 diff --git a/cores/esp8266/LwipIntfDev.h b/cores/esp8266/LwipIntfDev.h index 15f3f033b..00f29e9df 100644 --- a/cores/esp8266/LwipIntfDev.h +++ b/cores/esp8266/LwipIntfDev.h @@ -104,7 +104,6 @@ public: } // ESP8266WiFi API compatibility - wl_status_t status(); protected: diff --git a/libraries/lwIP_Ethernet/examples/LegacyAdvancedChatServer/LegacyAdvancedChatServer.ino b/libraries/lwIP_Ethernet/examples/LegacyAdvancedChatServer/LegacyAdvancedChatServer.ino new file mode 100644 index 000000000..74b580308 --- /dev/null +++ b/libraries/lwIP_Ethernet/examples/LegacyAdvancedChatServer/LegacyAdvancedChatServer.ino @@ -0,0 +1,126 @@ +/* + Advanced Chat Server + + A more advanced server that distributes any incoming messages + to all connected clients but the client the message comes from. + To use, telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet Wiznet5500/Wiznet5100/ENC28J60 on esp8266 + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + redesigned to make use of operator== 25 Nov 2013 + by Norbert Truchsess + + */ + +// specific to esp8266 w/lwIP +#include +ArduinoWiznet5500lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware +// ArduinoWiznet5100lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware +// ArduinoENC28J60lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware + + + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +byte notNeededButAllowed_mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +byte* mac = nullptr; // automatic mac +IPAddress ip(192, 168, 1, 177); +IPAddress myDns(192, 168, 1, 1); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 0, 0); + + +// telnet defaults to port 23 +EthernetServer server(23); + +EthernetClient clients[8]; + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + // Ethernet.init(10); // Most Arduino shields + // Ethernet.init(5); // MKR ETH shield + // Ethernet.init(0); // Teensy 2.0 + // Ethernet.init(20); // Teensy++ 2.0 + // Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet + // Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet + // // esp8266 w/lwIP: SS set in Ethernet constructor + + // initialize the Ethernet device + Ethernet.begin(mac, ip, myDns, gateway, subnet); + + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + + // start listening for clients + server.begin(); + + Serial.print("Chat server address:"); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // check for any new client connecting, and say hello (before any incoming data) + EthernetClient newClient = server.accept(); + if (newClient) { + for (byte i = 0; i < 8; i++) { + if (!clients[i]) { + Serial.print("We have a new client #"); + Serial.println(i); + newClient.print("Hello, client number: "); + newClient.println(i); + // Once we "accept", the client is no longer tracked by EthernetServer + // so we must store it into our list of clients + clients[i] = newClient; + break; + } + } + } + + // check for incoming data from all clients + for (byte i = 0; i < 8; i++) { + if (clients[i] && clients[i].available() > 0) { + // read bytes from a client + byte buffer[80]; + int count = clients[i].read(buffer, 80); + // write the bytes to all other connected clients + for (byte j = 0; j < 8; j++) { + if (j != i && clients[j].connected()) { + clients[j].write(buffer, count); + } + } + } + } + + // stop any clients which disconnect + for (byte i = 0; i < 8; i++) { + if (clients[i] && !clients[i].connected()) { + Serial.print("disconnect client #"); + Serial.println(i); + clients[i].stop(); + } + } +} diff --git a/libraries/lwIP_Ethernet/examples/LegacyChatServer/LegacyChatServer.ino b/libraries/lwIP_Ethernet/examples/LegacyChatServer/LegacyChatServer.ino new file mode 100644 index 000000000..1c6ee9e2a --- /dev/null +++ b/libraries/lwIP_Ethernet/examples/LegacyChatServer/LegacyChatServer.ino @@ -0,0 +1,105 @@ +/* + Chat Server + + A simple server that distributes any incoming messages to all + connected clients. To use, telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet Wiznet5500/Wiznet5100/ENC28J60 on esp8266 + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + + */ + + +// specific to esp8266 w/lwIP +#include +ArduinoWiznet5500lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware +// ArduinoWiznet5100lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware +// ArduinoENC28J60lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware + + + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +byte notNeededButAllowed_mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +byte* mac = nullptr; // automatic mac +IPAddress ip(192, 168, 1, 177); +IPAddress myDns(192, 168, 1, 1); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 0, 0); + + +// telnet defaults to port 23 +EthernetServer server(23); +bool alreadyConnected = false; // whether or not the client was connected previously + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + // Ethernet.init(10); // Most Arduino shields + // Ethernet.init(5); // MKR ETH shield + // Ethernet.init(0); // Teensy 2.0 + // Ethernet.init(20); // Teensy++ 2.0 + // Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet + // Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet + // // esp8266 w/lwIP: SS set in Ethernet constructor + + // initialize the ethernet device + Ethernet.begin(mac, ip, myDns, gateway, subnet); + + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + + // start listening for clients + server.begin(); + + Serial.print("Chat server address:"); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // wait for a new client: + EthernetClient client = server.available(); + + // when the client sends the first byte, say hello: + if (client) { + if (!alreadyConnected) { + // clear out the input buffer: + client.flush(); + Serial.println("We have a new client"); + client.println("Hello, client!"); + alreadyConnected = true; + } + + if (client.available() > 0) { + // read the bytes incoming from the client: + char thisChar = client.read(); + // echo the bytes back to the client: + server.write(thisChar); + // echo the bytes to the server as well: + Serial.write(thisChar); + } + } +} diff --git a/libraries/lwIP_Ethernet/examples/LegacyDhcpAddressPrinter/LegacyDhcpAddressPrinter.ino b/libraries/lwIP_Ethernet/examples/LegacyDhcpAddressPrinter/LegacyDhcpAddressPrinter.ino new file mode 100644 index 000000000..e7ab75075 --- /dev/null +++ b/libraries/lwIP_Ethernet/examples/LegacyDhcpAddressPrinter/LegacyDhcpAddressPrinter.ino @@ -0,0 +1,101 @@ +/* + DHCP-based IP printer + + This sketch uses the DHCP extensions to the Ethernet library + to get an IP address via DHCP and print the address obtained. + using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet Wiznet5500/Wiznet5100/ENC28J60 on esp8266 + + created 12 April 2011 + modified 9 Apr 2012 + by Tom Igoe + modified 02 Sept 2015 + by Arturo Guadalupi + + */ + +// specific to esp8266 w/lwIP +#include +ArduinoWiznet5500lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware +// ArduinoWiznet5100lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware +// ArduinoENC28J60lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware + + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte notNeededButAllowed_mac[] = { + 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 +}; +byte* mac = nullptr; // automatic mac + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + // Ethernet.init(10); // Most Arduino shields + // Ethernet.init(5); // MKR ETH shield + // Ethernet.init(0); // Teensy 2.0 + // Ethernet.init(20); // Teensy++ 2.0 + // Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet + // Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet + // // esp8266 w/lwIP: SS set in Ethernet constructor + + + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + } else if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + // no point in carrying on, so do nothing forevermore: + while (true) { + delay(1); + } + } + // print your local IP address: + Serial.print("My IP address: "); + Serial.println(Ethernet.localIP()); +} + +void loop() { + switch (Ethernet.maintain()) { + case 1: + // renewed fail + Serial.println("Error: renewed fail"); + break; + + case 2: + // renewed success + Serial.println("Renewed success"); + // print your local IP address: + Serial.print("My IP address: "); + Serial.println(Ethernet.localIP()); + break; + + case 3: + // rebind fail + Serial.println("Error: rebind fail"); + break; + + case 4: + // rebind success + Serial.println("Rebind success"); + // print your local IP address: + Serial.print("My IP address: "); + Serial.println(Ethernet.localIP()); + break; + + default: + // nothing happened + break; + } +} diff --git a/libraries/lwIP_Ethernet/examples/LegacyUDPSendReceiveString/LegacyUDPSendReceiveString.ino b/libraries/lwIP_Ethernet/examples/LegacyUDPSendReceiveString/LegacyUDPSendReceiveString.ino new file mode 100644 index 000000000..bee4a1f80 --- /dev/null +++ b/libraries/lwIP_Ethernet/examples/LegacyUDPSendReceiveString/LegacyUDPSendReceiveString.ino @@ -0,0 +1,156 @@ +/* + UDPSendReceiveString: + This sketch receives UDP message strings, prints them to the serial port + and sends an "acknowledge" string back to the sender + + A Processing sketch is included at the end of file that can be used to send + and received messages for testing with a computer. + + Circuit: + * Ethernet Wiznet5500/Wiznet5100/ENC28J60 on esp8266 + + created 21 Aug 2010 + by Michael Margolis + + This code is in the public domain. + */ + +// specific to esp8266 w/lwIP +#include +ArduinoWiznet5500lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware +// ArduinoWiznet5100lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware +// ArduinoENC28J60lwIP Ethernet(/*SS*/ 16); // <== adapt to your hardware + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte notNeededButAllowed_mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +byte* mac = nullptr; // automatic mac +IPAddress ip(192, 168, 1, 177); + +unsigned int localPort = 8888; // local port to listen on + +// buffers for receiving and sending data +char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet, +char ReplyBuffer[] = "acknowledged"; // a string to send back + +// An EthernetUDP instance to let us send and receive packets over UDP +EthernetUDP Udp; + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + // Ethernet.init(10); // Most Arduino shields + // Ethernet.init(5); // MKR ETH shield + // Ethernet.init(0); // Teensy 2.0 + // Ethernet.init(20); // Teensy++ 2.0 + // Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet + // Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet + // // esp8266 w/lwIP: SS set in Ethernet constructor + + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start the Ethernet + // Ethernet.begin(mac, ip); + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + while (true) { + delay(1000); // do nothing, no point running without Ethernet hardware + } + } + + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1000); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + + Serial.println("Started and waiting"); + Serial.print("IP Address: "); + Serial.println(Ethernet.localIP()); + Serial.print("UDP port: "); + Serial.println(localPort); + + // start UDP + Udp.begin(localPort); +} + +void loop() { + // if there's data available, read a packet + int packetSize = Udp.parsePacket(); + if (packetSize) { + Serial.print("Received packet of size "); + Serial.println(packetSize); + Serial.print("From "); + IPAddress remote = Udp.remoteIP(); + for (int i = 0; i < 4; i++) { + Serial.print(remote[i], DEC); + if (i < 3) { + Serial.print("."); + } + } + Serial.print(", port "); + Serial.println(Udp.remotePort()); + + // read the packet into packetBufffer + Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); + Serial.println("Contents:"); + Serial.println(packetBuffer); + + // send a reply to the IP address and port that sent us the packet we received + Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); + Udp.write(ReplyBuffer); + Udp.endPacket(); + } + delay(10); +} + + +/* + Processing sketch to run with this example + ===================================================== + + // Processing UDP example to send and receive string data from Arduino + // press any key to send the "Hello Arduino" message + + + import hypermedia.net.*; + + UDP udp; // define the UDP object + + + void setup() { + udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000 + //udp.log( true ); // <-- printout the connection activity + udp.listen( true ); // and wait for incoming message + } + + void draw() + { + } + + void keyPressed() { + String ip = "192.168.1.177"; // the remote IP address + int port = 8888; // the destination port + + udp.send("Hello World", ip, port ); // the message to send + + } + + void receive( byte[] data ) { // <-- default handler + //void receive( byte[] data, String ip, int port ) { // <-- extended handler + + for(int i=0; i < data.length; i++) + print(char(data[i])); + println(); + } + */ diff --git a/libraries/lwIP_Ethernet/src/EthernetCompat.h b/libraries/lwIP_Ethernet/src/EthernetCompat.h new file mode 100644 index 000000000..e398d5719 --- /dev/null +++ b/libraries/lwIP_Ethernet/src/EthernetCompat.h @@ -0,0 +1,101 @@ + +#pragma once + +#include +#include +#include +#include + +using EthernetUDP = WiFiUDP; +using EthernetClient = WiFiClient; +using EthernetServer = ArduinoWiFiServer; + +enum EthernetLinkStatus +{ + Unknown, + LinkON, + LinkOFF +}; + +enum +{ + DHCP_CHECK_NONE = 0, + DHCP_CHECK_RENEW_FAIL = 1, + DHCP_CHECK_RENEW_OK = 2, + DHCP_CHECK_REBIND_FAIL = 3, + DHCP_CHECK_REBIND_OK = 4, +}; + +enum HardwareStatus +{ + EthernetNoHardware, + EthernetHardwareFound, +}; + +template +class ArduinoEthernet: public LwipIntfDev +{ +public: + ArduinoEthernet(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1) : + LwipIntfDev(cs, spi, intr) + { + _hardwareStatus = EthernetNoHardware; + _linkStatus = Unknown; + } + + // Arduino-Ethernet API compatibility, order can be either: + // mac, ip, gateway, netmask, dns (esp8266 or natural order) + // mac, ip, dns, gateway, netmask (Arduino legacy) + boolean begin(const uint8_t* macAddress, const IPAddress& local_ip = IPADDR_NONE, + const IPAddress& arg1 = IPADDR_NONE, const IPAddress& arg2 = IPADDR_NONE, + const IPAddress& arg3 = IPADDR_NONE) + { + SPI4EthInit(); // Arduino Ethernet self-initializes SPI + bool ret = true; + if (local_ip.isSet()) + ret = LwipIntfDev::config(local_ip, arg1, arg2, arg3); + if (ret) + { + ret = LwipIntfDev::begin(macAddress); + if (!local_ip.isSet()) + { + // Arduino API waits for DHCP answer + while (!LwipIntfDev::connected()) + { + delay(100); + } + } + } + + if (ret) + { + _hardwareStatus = EthernetHardwareFound; + _linkStatus = LinkON; + } + + return ret; + } + + HardwareStatus hardwareStatus() const + { + return _hardwareStatus; + } + + EthernetLinkStatus linkStatus() const + { + return _linkStatus; + } + + int maintain() const + { + return DHCP_CHECK_NONE; + } + +protected: + HardwareStatus _hardwareStatus; + EthernetLinkStatus _linkStatus; +}; + +using ArduinoWiznet5500lwIP = ArduinoEthernet; +using ArduinoWiznet5100lwIP = ArduinoEthernet; +using ArduinoENC28J60lwIP = ArduinoEthernet;