Hi there,
sending UDP packages (and waiting for the return code) seems to slow down the sketch. I am sending one package per second.
Is there any possibility to make this more asynchronous?
I am using <Ethernet.h> and <EthernetUdp.h>.
Thanks
Hi there,
sending UDP packages (and waiting for the return code) seems to slow down the sketch. I am sending one package per second.
Is there any possibility to make this more asynchronous?
I am using <Ethernet.h> and <EthernetUdp.h>.
Thanks
what microcontroller are you using? what interface?
UDP is unreliable and datagrams may not be received
are you using blocking code?
post code using < CODE > tags?
Sorry, for some missing information:
My approach is (minimal code):
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <ArduinoJson.h>
byte mac[] = { 0x34, 0xF1, 0x38, 0xA1, 0xED, 0x30 };
IPAddress ip(192, 168, 1, 17);
IPAddress targetIP1(192, 168, 1, 130);
IPAddress targetIP2(192, 168, 1, 131);
IPAddress targetIP3(192, 168, 1, 132);
unsigned int targetPort = 8889;
EthernetClient client;
EthernetUDP Udp;
StaticJsonDocument<200> jsonMap;
String targetMessage;
void setup() {
Serial.begin(115200);
unsigned long time = millis();
while (!Serial && (millis() - time < 5000)) { ; }
SPI.begin(W5500_SCK, W5500_MISO, W5500_MOSI, W5500_CS);
Ethernet.init(W5500_CS);
Ethernet.begin(mac, ip);
Udp.begin(8888); // Not used.
if (Ethernet.localIP() == IPAddress(0, 0, 0, 0)) {
Serial.println("Failed to configure Ethernet with static IP");
while (true);
}
}
void loop() {
delay(5);
counter = 12345; // Set some value
sendUDP(targetIP1, counter);
sendUDP(targetIP2, counter);
sendUDP(targetIP3, counter);
}
void sendUDP(IPAddress targetIP, int counter) {
jsonMap["timestamp"] = millis();
jsonMap["counter"] = counter;
serializeJson(jsonMap, targetMessage); // Create package content (json)
Udp.beginPacket(targetIP, targetPort);
Udp.println(targetMessage);
int status = Udp.endPacket();
if (status == 0) {
Serial.println("WARN: Udp.endPacket returns value 0.");
}
}
Based on sending this package to one existing target ip the performance is ok. But I have the feeling, in case of a non existing target (return value = 0), this code slows down.
UDP is a connectionless unreliable protocol so in theory just sends a datagram and has no idea if the receiver is available and the datagram arrives or not
could you time your loop under various test conditions using micros()?
I agree with your explanation of UDP.
unsigned long time = millis();
int status = Udp.endPacket();
unsigned long time2 = millis();
unsigned long time3 = time2 - time;
Serial.println(time3);
For the case, that the destination is not reachable in the network, I have measured just the Udp.endPacket() method. This yields into a time of 1618 ms.
Thats a lot for me …
the IP must be first resolved to MAC of the target with an ARP packet and response. that is why it takes more time if there is no replay to the ARP request.
as an experiment I implemented a program transmitting datagrams to three IP addresses using a Waveshare ESP32-S3 ETH Development Board (W5500
// Waveshare ESP32-S3 ETH Development Board (W5500) UDP test
// sending datagrams to three IP addresses
#include <EthernetESP32.h>
#include <EthernetUdp.h> // for UDP
// Define Waveshare ESP32-S3-ETHW5500 pin assignments
#define W5500_CS 14 // Chip Select pin
#define W5500_RST 9 // Reset pin
#define W5500_INT 10 // Interrupt pin
#define W5500_MISO 12 // MISO pin
#define W5500_MOSI 11 // MOSI pin
#define W5500_SCK 13 // Clock pin
// W5500Driver(int8_t cs = SS, int8_t irq = -1, int8_t rst = -1)
W5500Driver driver(W5500_CS, W5500_INT, W5500_RST);
// ***** IP of this machine and remote machine *********
IPAddress localIP(192, 168, 1, 174); // local static localIP address
IPAddress remoteIP(192, 168, 1, 65); // local static localIP address
unsigned int port = 10000; // port to receive/transmit
// Enter a MAC address
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xAA };
unsigned int localPort = 10000; // local port to listen on
unsigned int remotePort = 10000; // remote port to transmiit too
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
SPIClass SPI1(SPI);
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial)
;
Serial.println("\nWaveshare ESP32-S3 ETH Development Board (W5500) Ethernet UDP test program");
// Check for Ethernet hardware present
// bool begin(int8_t sck = -1, int8_t miso = -1, int8_t mosi = -1, int8_t ss = -1);
SPI1.begin(W5500_SCK, W5500_MISO, W5500_MOSI, W5500_CS);
driver.setSPI(SPI1);
Ethernet.init(driver);
Serial.println("Initialize Ethernet with DHCP:");
if (Ethernet.begin(mac)) {
Serial.print(" DHCP assigned IP ");
Serial.println(Ethernet.localIP());
} else {
Serial.println("Failed to configure Ethernet using DHCP");
Serial.print("\nDefault localIP");
displayIPaddress(localIP, localPort);
Serial.println("Failed to configure Ethernet using DHCP - using static IP");
getIPaddress("local IP address (<return> use default)? ", localIP, localPort);
Ethernet.begin(mac, localIP); // static IP initialize Ethernet shield
}
Serial.print("My localIP address: "); // print local localIP address:
displayIPaddress(Ethernet.localIP(), localPort);
// Initializes the ethernet UDP library and network settings.
if (Udp.begin(port)) Serial.println("UDP begin() OK");
else Serial.println("UDP begin() failed!");
// get remote IP and port
Serial.print("\nDefault remoteIP ");
displayIPaddress(remoteIP, remotePort);
//getIPaddress("remote IP address (<return> use default)? ", remoteIP, remotePort);
Serial.print("\nRemote ");
displayIPaddress(remoteIP, remotePort);
}
// loop sending datagrams to three IP addresses
IPAddress remoteIP2(192, 168, 1, 176); // local static localIP address
IPAddress remoteIP3(192, 168, 1, 167); // local static localIP address
void loop() {
static char text[] = "hello1";
uint32_t timer1 = micros();
// if Serial text entered transmit as a datagram
Serial.printf("status %d ", Udp.beginPacket(remoteIP, remotePort)); // transmit datagram
Serial.printf("%d ", Udp.print(text));
Serial.printf("%d ", Udp.endPacket());
Serial.printf("transmit time 1 %lduSec\n", micros() - timer1);
//-------------------------------------------
//yield();
//delay(5);
timer1 = micros();
Serial.printf("status %d ", Udp.beginPacket(remoteIP2, remotePort)); // transmit datagram
Serial.printf("%d ", Udp.print(text));
Serial.printf("%d ", Udp.endPacket());
//delay(5);
Serial.printf("status %d ", Udp.beginPacket(remoteIP, remotePort)); // transmit datagram
Serial.printf("%d ", Udp.print(text));
Serial.printf("%d ", Udp.endPacket());
Serial.printf("transmit time 2 %lduSec\n", micros() - timer1);
// -------------------------------------------------------------
//yield();
//delay(5);
timer1 = micros();
Serial.printf("status %d ", Udp.beginPacket(remoteIP2, remotePort)); // transmit datagram
Serial.printf("%d ", Udp.print(text));
Serial.printf("%d ", Udp.endPacket());
//delay(5);
Serial.printf("status %d ", Udp.beginPacket(remoteIP, remotePort)); // transmit datagram
Serial.printf("%d ", Udp.print(text));
Serial.printf("%d ", Udp.endPacket());
//delay(5);
Serial.printf("status %d ", Udp.beginPacket(remoteIP3, remotePort)); // transmit datagram
Serial.printf("%d ", Udp.print(text));
Serial.printf("%d ", Udp.endPacket());
Serial.printf("transmit time 3 %lduSec\n\n", micros() - timer1);
if (text[5] == '9') text[5] = '0';
else text[5]++;
delay(1000);
}
// read IP address and port from keyboard and check it
void getIPaddress(const char* prompt, IPAddress& defaultIP, unsigned int& defaultPort) {
IPAddress ip;
while (1) { // read IP (end with new line)
char text[40] = { 0 };
Serial.print(prompt); // prompt and wait for input
while (Serial.available() == 0) delay(10);
Serial.readBytesUntil('\n', (char*)text, 40);
for (int i = 0; i < 40; i++) // convert IP address
if (text[i] < ' ') text[i] = 0;
if (text[0] == 0) return; // ig just <enter> return defaultIP;
//Serial.println(text);
if (ip.fromString(text)) break; // if IP OK break while
Serial.println("\ninvalid IP try again");
}
char text[40] = { 0 };
// read port number
while (Serial.available()) Serial.read();
defaultIP = ip;
Serial.print("\nport ? "); // prompt and wait for input
while (Serial.available() == 0) delay(10);
Serial.readBytesUntil('\n', (char*)text, 40); // read value
sscanf(text, "%u", &defaultPort); // convert value
}
// print IPAdress and port
void displayIPaddress(const IPAddress address, unsigned int port) {
Serial.print(" IP ");
Serial.print(address);
Serial.print(" port ");
Serial.println(port);
}
if the IPs exist the UDP functions all return 1 (success)
Waveshare ESP32-S3 ETH Development Board (W5500) Ethernet UDP test program
Initialize Ethernet with DHCP:
DHCP assigned IP 192.168.1.106
My localIP address: IP 192.168.1.106 port 10000
UDP begin() OK
Default remoteIP IP 192.168.1.65 port 10000
Remote IP 192.168.1.65 port 10000
status 1 6 1 transmit time 1 802uSec
status 1 6 1 status 1 6 1 transmit time 2 991uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1303uSec
status 1 6 1 transmit time 1 618uSec
status 1 6 1 status 1 6 1 transmit time 2 906uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1300uSec
status 1 6 1 transmit time 1 650uSec
status 1 6 1 status 1 6 1 transmit time 2 887uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1298uSec
status 1 6 1 transmit time 1 657uSec
status 1 6 1 status 1 6 1 transmit time 2 915uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1319uSec
status 1 6 1 transmit time 1 626uSec
status 1 6 1 status 1 6 1 transmit time 2 855uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1309uSec
status 1 6 1 transmit time 1 626uSec
status 1 6 1 status 1 6 1 transmit time 2 855uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1309uSec
status 1 6 1 transmit time 1 660uSec
status 1 6 1 status 1 6 1 transmit time 2 869uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1311uSec
status 1 6 1 transmit time 1 643uSec
status 1 6 1 status 1 6 1 transmit time 2 844uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1281uSec
status 1 6 1 transmit time 1 654uSec
status 1 6 1 status 1 6 1 transmit time 2 860uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1302uSec
status 1 6 1 transmit time 1 605uSec
status 1 6 1 status 1 6 1 transmit time 2 844uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1299uSec
status 1 6 1 transmit time 1 585uSec
status 1 6 1 status 1 6 1 transmit time 2 859uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1270uSec
status 1 6 1 transmit time 1 597uSec
status 1 6 1 status 1 6 1 transmit time 2 859uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1268uSec
status 1 6 1 transmit time 1 584uSec
status 1 6 1 status 1 6 1 transmit time 2 874uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1253uSe
if only IPAddress remoteIP(192, 168, 1, 65) exists it's UDP calls return success 1
the other two IPs (which don't exist) sometimes indicate success 1 sometimes Udp.endPacket() returns fail 0
Waveshare ESP32-S3 ETH Development Board (W5500) Ethernet UDP test program
Initialize Ethernet with DHCP:
DHCP assigned IP 192.168.1.106
My localIP address: IP 192.168.1.106 port 10000
UDP begin() OK
Default remoteIP IP 192.168.1.65 port 10000
Remote IP 192.168.1.65 port 10000
status 1 6 1 transmit time 1 790uSec
status 1 6 1 status 1 6 1 transmit time 2 763uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 731uSec
status 1 6 1 transmit time 1 650uSec
status 1 6 1 status 1 6 1 transmit time 2 681uSec
status 1 6 0 status 1 6 1 status 1 6 1 transmit time 3 925uSec
status 1 6 1 transmit time 1 646uSec
status 1 6 0 status 1 6 1 transmit time 2 719uSec
status 1 6 0 status 1 6 1 status 1 6 1 transmit time 3 880uSec
status 1 6 1 transmit time 1 706uSec
status 1 6 0 status 1 6 1 transmit time 2 735uSec
status 1 6 0 status 1 6 1 status 1 6 0 transmit time 3 894uSec
status 1 6 1 transmit time 1 682uSec
status 1 6 0 status 1 6 1 transmit time 2 714uSec
status 1 6 0 status 1 6 1 status 1 6 0 transmit time 3 901uSec
status 1 6 1 transmit time 1 575uSec
status 1 6 1 status 1 6 1 transmit time 2 982uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1140uSec
status 1 6 1 transmit time 1 668uSec
status 1 6 1 status 1 6 1 transmit time 2 676uSec
status 1 6 0 status 1 6 1 status 1 6 1 transmit time 3 897uSec
status 1 6 1 transmit time 1 651uSec
status 1 6 0 status 1 6 1 transmit time 2 704uSec
status 1 6 0 status 1 6 1 status 1 6 1 transmit time 3 882uSec
status 1 6 1 transmit time 1 706uSec
status 1 6 0 status 1 6 1 transmit time 2 735uSec
status 1 6 0 status 1 6 1 status 1 6 0 transmit time 3 894uSec
status 1 6 1 transmit time 1 682uSec
status 1 6 0 status 1 6 1 transmit time 2 714uSec
status 1 6 0 status 1 6 1 status 1 6 0 transmit time 3 901uSec
status 1 6 1 transmit time 1 575uSec
status 1 6 1 status 1 6 1 transmit time 2 982uSec
status 1 6 1 status 1 6 1 status 1 6 1 transmit time 3 1140uSec
status 1 6 1 transmit time 1 668uSec
status 1 6 1 status 1 6 1 transmit time 2 676uSec
status 1 6 0 status 1 6 1 status 1 6 1 transmit time 3 897uSec
status 1 6 1 transmit time 1 651uSec
status 1 6 0 status 1 6 1 transmit time 2 704uSec
status 1 6 0 status 1 6 1 status 1 6 1 transmit time 3 882uSec
one treats UDP as being unreliable
if reliable communication is required use TCP which returns indication of sucess/failed delivery
is there a need to send unicast messages to each individual target (at least I just see a timestamp and a counter in your message)?
Could you send a broadcast into you network and just let each “existing” target answer the message?
maybe worth trying
using the Waveshare ESP32-S3 ETH Development Board using Broadcast IP 192.168.1.255 multiple receivers received the datagrams OK
I don't know this UDP library but @Juraj surely does since he wrote it. Anyway this seems rather long:
In the bad old days, before the ESP native NTP was well understood and documented, I implemented a simple finite state machine to sent a UDP request transaction to a time server and periodically test (non blocking) for any response and, if necessary, timing out. This was using an ESP8266 and the library WiFiUdp.h . This was necessary because the blocking caused all sorts of havoc for an audio application running simultaneously.
Maybe you can use a similar approach if your UDP library supports a separation of the request transaction and testing for any returned result.
abuech2s uses the old Arduino Ethernet library.
horace uses the EthernetESP32 library, which I wrote but it only has the Ethernet object which initializes the hardware for use with the platform’s TCP/IP stack. the EthernetClient and EthernetUDP are ESP32 platform’s NetworkClient and NetworkUdp classes.
https://github.com/Networking-for-Arduino/EthernetESP32?tab=readme-ov-file#implementation-details
OK. It could be more or less the same with the old Arduino Ethernet UDP. This is the "essence" of what I used with ESP8266 WiFiUdp.h and, as far as I remember, the endPacket() method did not wait/block. But, anyway, the principle may be useful :
To initialise it:
udp.begin(localPort);
while (udp.parsePacket() > 0) ; // discard any previously received packets
To send something:
if (u->beginPacket(nsConfig::config.timeServer , 123)) { // port 123
u->write(packetBuffer, NTP_PACKET_SIZE);
u->endPacket();
}
Where u is an instance of WiFiUDP
.
To test if/when the there is a response:
if (udp.parsePacket()) { // tests if something is there
udp.read(packetBuffer, NTP_PACKET_SIZE); // read and process response
// other stuff
udp.flush();
}
If the response is checked for only periodically in a non-blocking code section (maybe an ESP32 RTOS task would be good), then it will be "asynchronous"
The entire code can be found here: Arduino ESP8266 Speaking Clock (attachment spck_v1.00p.zip) files TimeSync.cpp and TimeSync.h but the OP would have to filter it for the relevant bits and adapt it for the ESP32.
Well, actually there are exactly three IPs (which a constant), so I do not believe that Broadcast make any sense here.
In my environment I can not apply Wifi and my ESP32 is just a sender (it will not receive anything). The intention is to send periodically (every second) a specific frequency measured by a sensor (Core1). If a client is not reachable and the delay is >>1s, then I get stupid effects on the sender side (Core2).
I just know it from other languages, where I can send a udp package and even die destination is not reachable, you dont feel the delay - the package is just gone (and thats fine for clients, which are e.g. not online).
So is there any “flag” or something to optimize this sending process?
did you try with EthernetESP32 now? does it too wait if the target is unreachable?
The delay occurs from the timeout in the ARP call (translate one specific IP to its MAC). As a broadcast will not be translated in that way - there should be no such timeout at all.
By the way … a one way call with an information from the sender is a good example for a UDP broadcast.
Thanks guys. I think I have enough input to optimize it.