Closed MBanucu closed 11 months ago
maybe changing some settings could help.
there is not enough 'ticks' to handle the sending in time. try to add a few calls to Ethernet.maintain() after endPacket
New code (using Ethernet.maintain()
):
#include <Arduino.h>
#include <EthernetENC.h>
void sendPacket(EthernetUDP &Udp, IPAddress &remoteIP, uint16_t remotePort)
{
auto endPacket = Udp.endPacket();
Serial.println(String() + "endPacket = " + endPacket);
delay(3000);
auto beginPacket = Udp.beginPacket(remoteIP, remotePort);
Serial.println(String() + "beginPacket = " + beginPacket);
for (int i = 0; !beginPacket; i++)
{
Serial.println(String() + i + " " + micros() + ": maintain = " + Ethernet.maintain());
beginPacket = Udp.beginPacket(remoteIP, remotePort);
Serial.println(String() + i + " " + micros() + ": beginPacket = " + beginPacket);
}
}
void setup()
{
Serial.begin(115200);
while (!Serial)
{
}
delay(3000);
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xA0, 0x36, 0xBC, 0x30, 0xC1, 0x16};
IPAddress ip(169, 254, 116, 89);
unsigned int localPort = 32768; // local port to listen on
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
// You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(10);
// start the Ethernet
Ethernet.begin(mac, ip);
// 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
}
}
// start UDP
Udp.begin(localPort);
IPAddress remoteIP(169, 254, 116, 90);
uint16_t remotePort = 32769;
Serial.println(String() + "beginPacket = " + Udp.beginPacket(remoteIP, remotePort));
for (int i = 0; i < 10; i++)
{
Serial.println("next try");
Serial.println(String() + "i = " + i);
Serial.println();
Serial.println(Udp.println(i));
sendPacket(Udp, remoteIP, remotePort);
Serial.println("---------------------------------");
}
}
void loop()
{
}
New output (Serial):
beginPacket = 1
next try
i = 0
3
endPacket = 1
beginPacket = 0
0 6054004: maintain = 0
0 6055104: beginPacket = 0
1 6055784: maintain = 0
1 6056420: beginPacket = 0
2 6058780: maintain = 0
2 6060912: beginPacket = 0
3 6063284: maintain = 0
3 6065420: beginPacket = 0
4 6067788: maintain = 0
4 6069924: beginPacket = 0
5 6072296: maintain = 0
5 6074432: beginPacket = 0
6 6076800: maintain = 0
6 6078932: beginPacket = 0
7 6081304: maintain = 0
7 6083440: beginPacket = 0
8 6085808: maintain = 0
8 6087944: beginPacket = 0
9 6090316: maintain = 0
9 6092448: beginPacket = 0
10 6094820: maintain = 0
10 6097040: beginPacket = 0
11 6099492: maintain = 0
11 6101712: beginPacket = 0
12 6104168: maintain = 0
12 6106388: beginPacket = 0
13 6108844: maintain = 0
13 6111064: beginPacket = 0
14 6113520: maintain = 0
14 6115740: beginPacket = 0
15 6118196: maintain = 0
15 6120412: beginPacket = 0
16 6122868: maintain = 0
16 6125088: beginPacket = 0
17 6127544: maintain = 0
17 6129764: beginPacket = 0
18 6132220: maintain = 0
18 6134440: beginPacket = 0
19 6136896: maintain = 0
19 6139112: beginPacket = 0
20 6141568: maintain = 0
20 6143788: beginPacket = 0
21 6146244: maintain = 0
21 6148464: beginPacket = 0
22 6150920: maintain = 0
22 6153836: beginPacket = 1
---------------------------------
next try
i = 1
3
endPacket = 1
beginPacket = 1
---------------------------------
next try
i = 2
3
endPacket = 1
beginPacket = 1
---------------------------------
next try
i = 3
3
endPacket = 1
beginPacket = 1
---------------------------------
next try
i = 4
3
endPacket = 1
beginPacket = 1
---------------------------------
next try
i = 5
3
endPacket = 1
beginPacket = 1
---------------------------------
next try
i = 6
3
endPacket = 1
beginPacket = 1
---------------------------------
next try
i = 7
3
endPacket = 1
beginPacket = 1
---------------------------------
next try
i = 8
3
endPacket = 1
beginPacket = 1
---------------------------------
next try
i = 9
3
endPacket = 1
beginPacket = 1
---------------------------------
New output (terminal):
0
1
2
3
4
5
6
7
8
9
At i == 0
the 0 is appearing in the terminal when beginPacket == 1
for the next packet. The other times the number is appearing in the terminal when endPacket == 1
for the current packet as expected. So there has to be established a connection first and then everything works as expected.
I think it is worth mentioning this behavior in the Wiki, because it causes a lot of confusion, I believe.
And also it is worth providing this code as example to explain the UDP behavior of the library/chip.
try to add in setup()
if (Ethernet.linkStatus() == LinkOFF) {
delay(500);
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}
}
New code:
#include <Arduino.h>
#include <EthernetENC.h>
void beginPacket(EthernetUDP &Udp, IPAddress &remoteIP, uint16_t remotePort)
{
auto beginPacket = Udp.beginPacket(remoteIP, remotePort);
Serial.println(String() + "beginPacket = " + beginPacket);
for (int i = 0; !beginPacket; i++)
{
Serial.println(String() + i + "\t" + micros() + "\tmaintain = " + Ethernet.maintain());
beginPacket = Udp.beginPacket(remoteIP, remotePort);
Serial.println(String() + i + "\t" + micros() + "\tbeginPacket = " + beginPacket);
}
}
void endPacket(EthernetUDP &Udp)
{
auto endPacket = Udp.endPacket();
Serial.println(String() + "endPacket = " + endPacket);
}
void setup()
{
Serial.begin(115200);
while (!Serial)
{
}
delay(3000);
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xA0, 0x36, 0xBC, 0x30, 0xC1, 0x16};
IPAddress ip(169, 254, 116, 89);
unsigned int localPort = 32768; // local port to listen on
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
// You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(10);
// start the Ethernet
Ethernet.begin(mac, ip);
// 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
}
}
// start UDP
Udp.begin(localPort);
IPAddress remoteIP(169, 254, 116, 90);
uint16_t remotePort = 32769;
auto linkStatus = Ethernet.linkStatus();
Serial.println(String() + micros() + "\tlinkStatus = " + linkStatus);
while (linkStatus == LinkOFF)
{
linkStatus = Ethernet.linkStatus();
Serial.println(String() + micros() + "\tlinkStatus = " + linkStatus);
}
Serial.println("---------------------------------");
for (int i = 0; i < 10; i++)
{
Serial.println("next try");
Serial.println(String() + "i = " + i);
Serial.println();
beginPacket(Udp, remoteIP, remotePort);
auto stringToSend = String() + i + "\t" + micros();
auto bytesSent = Udp.println(stringToSend);
Serial.println(String() + "bytesSent = " + bytesSent + "\tstringToSend = \"" + stringToSend + "\"");
endPacket(Udp);
Serial.println("---------------------------------");
}
}
void loop()
{
}
New output (Serial):
3051344 linkStatus = 2
3052124 linkStatus = 2
3052944 linkStatus = 2
3053752 linkStatus = 2
3054600 linkStatus = 2
3056636 linkStatus = 2
3058676 linkStatus = 2
3060716 linkStatus = 2
3062756 linkStatus = 1
---------------------------------
next try
i = 0
beginPacket = 1
bytesSent = 11 stringToSend = "0 3070548"
endPacket = 1
---------------------------------
next try
i = 1
beginPacket = 0
0 3081572 maintain = 0
0 3083588 beginPacket = 0
1 3085876 maintain = 0
1 3087924 beginPacket = 0
2 3090208 maintain = 0
2 3092260 beginPacket = 0
3 3094552 maintain = 0
3 3096600 beginPacket = 0
4 3098880 maintain = 0
4 3101648 beginPacket = 1
bytesSent = 11 stringToSend = "1 3103188"
endPacket = 1
---------------------------------
next try
i = 2
beginPacket = 1
bytesSent = 11 stringToSend = "2 3114152"
endPacket = 1
---------------------------------
next try
i = 3
beginPacket = 1
bytesSent = 11 stringToSend = "3 3125116"
endPacket = 1
---------------------------------
next try
i = 4
beginPacket = 1
bytesSent = 11 stringToSend = "4 3136084"
endPacket = 1
---------------------------------
next try
i = 5
beginPacket = 1
bytesSent = 11 stringToSend = "5 3147048"
endPacket = 1
---------------------------------
next try
i = 6
beginPacket = 1
bytesSent = 11 stringToSend = "6 3158012"
endPacket = 1
---------------------------------
next try
i = 7
beginPacket = 1
bytesSent = 11 stringToSend = "7 3168976"
endPacket = 1
---------------------------------
next try
i = 8
beginPacket = 1
bytesSent = 11 stringToSend = "8 3179944"
endPacket = 1
---------------------------------
next try
i = 9
beginPacket = 1
bytesSent = 11 stringToSend = "9 3190908"
endPacket = 1
---------------------------------
New bash line in Debian GNU/Linux 11 (bullseye):
nc -ul -p 32769 | while read -r line; do printf "%s\t%s\n" "$(date +"%T.%N")" "$line"; done
New output in terminal:
00:19:14.665008110 0 3070548
00:19:14.669857686 1 3103188
00:19:14.682479886 2 3114152
00:19:14.689398773 3 3125116
00:19:14.701770366 4 3136084
00:19:14.712442270 5 3147048
00:19:14.727768421 6 3158012
00:19:14.734423976 7 3168976
00:19:14.754557364 8 3179944
00:19:14.765623250 9 3190908
With these lines commented out
// auto linkStatus = Ethernet.linkStatus();
// Serial.println(String() + micros() + "\tlinkStatus = " + linkStatus);
// while (linkStatus == LinkOFF)
// {
// linkStatus = Ethernet.linkStatus();
// Serial.println(String() + micros() + "\tlinkStatus = " + linkStatus);
// }
the output (Serial) is
---------------------------------
next try
i = 0
beginPacket = 1
bytesSent = 11 stringToSend = "0 3052052"
endPacket = 1
---------------------------------
next try
i = 1
beginPacket = 0
0 3062692 maintain = 0
0 3064708 beginPacket = 0
1 3066992 maintain = 0
1 3069044 beginPacket = 0
2 3071328 maintain = 0
2 3073376 beginPacket = 0
3 3075664 maintain = 0
3 3077712 beginPacket = 0
4 3080000 maintain = 0
4 3082048 beginPacket = 0
5 3084340 maintain = 0
5 3086388 beginPacket = 0
6 3088668 maintain = 0
6 3090716 beginPacket = 0
7 3093004 maintain = 0
7 3095052 beginPacket = 0
8 3097340 maintain = 0
8 3099388 beginPacket = 0
9 3102384 maintain = 0
9 3103780 beginPacket = 1
bytesSent = 11 stringToSend = "1 3105984"
endPacket = 1
---------------------------------
[...]
so here the first packet is sent to the ENC28J60 18 ms earlier (3052052 vs 3070548) but it is sent by the ENC28J60 to the Ethernet port approximately at the same time as before (3103780 vs 3101648). But also the time needed for the first packet to be sent changed from 100 ms in this post to 40 ms in the new code. I don't know. I will just use my custom beginPacket()
function that spams Udp.beginPacket()
and Ethernet.maintain()
until it returns true
or breaks if it takes more than 200 ms to begin the new packet.
Maybe we can overload int UIPUDP::beginPacket(IPAddress ip, uint16_t port, unsigned long timeout)
in the library?
don't check the return value of maintain. it only returns true when DHCP was renewed. so if you would even use DHCP, it would be in a few hours.
try to uncomment in Eheternt.h #define UIPETHERNET_DEBUG_UDP
I am using PlatformIO. The setting in the platformio.ini
file is
build_flags = -D UIPETHERNET_DEBUG_UDP
to define a macro.
platformio.ini
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:nanoatmega328]
platform = atmelavr
board = nanoatmega328
framework = arduino
monitor_speed = 115200
lib_deps =
; jandrassy/EthernetENC@^2.0.4
https://github.com/JAndrassy/EthernetENC.git
build_flags = -D UIPETHERNET_DEBUG_UDP
src/main.cpp
#include <Arduino.h>
#include <EthernetENC.h>
// Start building up a packet to send to the remote host specific in ip and port
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
int beginPacket(EthernetUDP &Udp, IPAddress &remoteIP, uint16_t remotePort, unsigned long timeoutMillis)
{
auto start = millis();
auto beginPacket = Udp.beginPacket(remoteIP, remotePort);
Serial.println(String() + "beginPacket = " + beginPacket);
for (int i = 0; !beginPacket && millis() - start <= timeoutMillis; i++)
{
Serial.println(String() + i + "\t" + micros() + "\tmaintain = " + Ethernet.maintain());
beginPacket = Udp.beginPacket(remoteIP, remotePort);
Serial.println(String() + i + "\t" + micros() + "\tbeginPacket = " + beginPacket);
}
return beginPacket;
}
void endPacket(EthernetUDP &Udp)
{
auto endPacket = Udp.endPacket();
Serial.println(String() + "endPacket = " + endPacket);
}
void setup()
{
Serial.begin(115200);
while (!Serial)
{
}
delay(3000);
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xA0, 0x36, 0xBC, 0x30, 0xC1, 0x16};
IPAddress ip(169, 254, 116, 89);
unsigned int localPort = 32768; // local port to listen on
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
// You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(10);
// start the Ethernet
Ethernet.begin(mac, ip);
// 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
}
}
// start UDP
Udp.begin(localPort);
IPAddress remoteIP(169, 254, 116, 90);
uint16_t remotePort = 32769;
// auto linkStatus = Ethernet.linkStatus();
// Serial.println(String() + micros() + "\tlinkStatus = " + linkStatus);
// while (linkStatus == LinkOFF)
// {
// linkStatus = Ethernet.linkStatus();
// Serial.println(String() + micros() + "\tlinkStatus = " + linkStatus);
// }
Serial.println("---------------------------------");
for (int i = 0; i < 10; i++)
{
Serial.println("next try");
Serial.println(String() + "i = " + i);
Serial.println();
if (!beginPacket(Udp, remoteIP, remotePort, 200))
{
Serial.println("Error at \"beginPacket\".");
break;
}
auto stringToSend = String() + i + "\t" + micros();
auto bytesSent = Udp.println(stringToSend);
Serial.println(String() + "bytesSent = " + bytesSent + "\tstringToSend = \"" + stringToSend + "\"");
endPacket(Udp);
Serial.println("---------------------------------");
}
}
void loop()
{
}
output (Serial)
---------------------------------
next try
i = 0
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "0 3056000"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_poll results in ARP-packet
endPacket = 1
---------------------------------
next try
i = 1
udp beginPacket, rip: 169.254.116.90, port: 32769
previous packet on that connection not sent yet
beginPacket = 0
0 3083176 maintain = 0
udp beginPacket, rip: 169.254.116.90, port: 32769
previous packet on that connection not sent yet
0 3093648 beginPacket = 0
1 3095980 maintain = 0
udp beginPacket, rip: 169.254.116.90, port: 32769
previous packet on that connection not sent yet
1 3106484 beginPacket = 0
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
2 3115672 maintain = 0
udp beginPacket, rip: 169.254.116.90, port: 32769
2 3122052 beginPacket = 1
bytesSent = 11 stringToSend = "1 3124344"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
next try
i = 2
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "2 3146528"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
next try
i = 3
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "3 3168712"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
next try
i = 4
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "4 3190896"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
next try
i = 5
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "5 3213080"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
next try
i = 6
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "6 3235268"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
next try
i = 7
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "7 3257452"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
next try
i = 8
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "8 3279636"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
next try
i = 9
udp beginPacket, rip: 169.254.116.90, port: 32769
beginPacket = 1
bytesSent = 11 stringToSend = "9 3301820"
udp, uip_poll preparing packet to send: 1, size: 61
udp, uip_packet to send: 0
endPacket = 1
---------------------------------
bash command
nc -ul -p 32769 | while read -r line; do printf "%s\t%s\n" "$(date +"%T.%N")" "$line"; done
output (terminal)
01:32:47.552072005 0 3056000
01:32:47.572464755 1 3124344
01:32:47.593342844 2 3146528
01:32:47.615048660 3 3168712
01:32:47.638821992 4 3190896
01:32:47.660478563 5 3213080
01:32:47.682470830 6 3235268
01:32:47.705098687 7 3257452
01:32:47.726660511 8 3279636
01:32:47.749267772 9 3301820
ARP packet asks for the MAC address of the device at the iP address. until a response to ARP packet is not received, the UDP packet can't be send. the uIP library can only have one UDP packet processed at time. the ARP response is cached for some time so next UDP packet is sent immediately.
Trying to send only UDP messages totally does not work. I have the following workaround:
The output is:
I am using the following command on a "Debian GNU/Linux 11 (bullseye)" machine to set up the UDP receiver:
The output is:
The numbers in the Debian terminal are only appearing if
endPacket == 0
. You can put delays here and there to verify. Am I doing something wrong? Can someone reproduce the issue?My setup:
This issue is probably related to #3.