-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UDP totally broken with Arduino Nano #57
Comments
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 #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):
New output (terminal):
At 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()
|
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):
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:
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
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 |
Maybe we can overload |
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 |
I am using PlatformIO. The setting in the
to define a macro. platformio.ini
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)
bash command nc -ul -p 32769 | while read -r line; do printf "%s\t%s\n" "$(date +"%T.%N")" "$line"; done output (terminal)
|
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.
The text was updated successfully, but these errors were encountered: