Go Down

Topic: Udp.beginPacket() time delay problem (Read 2 times) previous topic - next topic

eddy9

Hi All,

I am new to programming with the Arduino development boards so please bear with me. I am working on a project were I need to implement UDP to communicate between multiple Arduino Mega2560 boards (each with its own Ethernet Shield). One board will be kind of like the Master where it will communicate with the other boards by sending commands and receiving information back from the other boards. I am using an Ethernet switch to connect all the boards together and build a UDP network. Currently I have only 2 Arduino boards that I am experimenting with and I am running into a problem implementing the UDP. I noticed that when I try sending something over UDP by using the following sequence of commands:

Udp.beginPacket(IP_Remote, Port_Remote);
Udp.write("ping");
Udp.endPacket();

If there is nothing on the other end to receive this UDP pocket, then Udp.beginPacket(IP_Remote, Port_Remote) takes a long time to execute (2-5 sec). It also appears that the timing is inconsistent every time I loop through the sequence of commands above. I dug into the EhternetUdp.cpp and Dns.cpp libraries and found that beginPacket() calls getHostByName() which attempts to connect to the remote device multiple times and causes the delay. My first problem is that this timing is inconsistent. I am trying to implement the UDP send code in an interrupt routine that runs every second for n times. This is to check if the status of the remote device. And the second problem is that it takes too long. I would like this to run every 1 second or maybe less. Another thing which I don't understand is why this UDP implementation cares about if there is a remote device on the other end? My understanding of UDP is that it's connectionless; meaning it just sends information on the network and does not care if the remote device receives that information or not. Another thing I noticed is that beginPacket() always returns 1 whether connection is established or not. Is there a way to check for the remote device before I run Udp.beginPacket()? I really don't want to have to modify the libraries.  Any information is greatly appreciated.

Thanks

Code: [Select]

#include <SPI.h>         // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>         // UDP library from: bjoern@cs.stanford.edu 12/30/2008

byte mac[] = {
  0x90, 0xA2, 0xDA, 0x0D, 0x50, 0x57}; //Ethernet shield MAC Address
IPAddress IP(169, 254, 0, 1);
IPAddress IP_Remote(169, 254, 0, 2);           // IP address for Remote Arduino
unsigned int localPort = 6101;                 // local port to listen on
unsigned int Port_Remote = 6180;        // Remote Arduino remote port


const int LEDPIN = 2;
volatile byte seconds = 0;

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
EthernetClient client;


char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

void setup()
{
  pinMode(4,OUTPUT); // for the MEGA 2560 to disable SD


  pinMode(LEDPIN, OUTPUT);
  // initialize Timer1
  cli();          // disable global interrupts
  TCCR1A = 0;     // set entire TCCR1A register to 0
  TCCR1B = 0;     // same for TCCR1B

  // set compare match register to desired timer count: (for 1 sec use 15624)
  OCR1A = 46874; // set for 3 seconds but this is too long. Prefer to use 1 second

  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);

  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR1B |= (1 << CS10);
  TCCR1B |= (1 << CS12);

  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);

  // enable global interrupts:
  sei();


  // start the Ethernet and UDP:
  Ethernet.begin(mac,IP);
  Udp.begin(localPort);

  // start the Serial Port:
  Serial.begin(9600);

}

void loop()
{

  Serial.println("in loop()");

  digitalWrite(4,HIGH); // for the MEGA 2560 to disable SD
 
  // if there is nothing to receive the UDP packet, then Udp.beginPacket() takes too long to executes (2-5 sec.)
  // Udp.beginPacket() always returns 1
  if (Udp.beginPacket(IP_Remote, Port_Remote))
  {
    Serial.println("connected");
    Serial.println(Udp.beginPacket(IP_Remote, Port_Remote));
    Udp.write("ping");
    Udp.endPacket();
  }
  else
  {
    Serial.println("connection failed");
  }
  int packetSize = Udp.parsePacket();
  if(packetSize)
  {
    Serial.print("Rcvd packet size of: ");
    Serial.print(packetSize);
    Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
    Serial.print(", Contents:");
    Serial.println(packetBuffer);
  }
  delay(50);
}

ISR(TIMER1_COMPA_vect)
{
  // would like to add UDP ping here instead of the main loop
  Serial.println("in ISR()");
  digitalWrite(LEDPIN, !digitalRead(LEDPIN));
  seconds++;
  if (seconds > 10)
  {
    cli();          // disable global interrupts
    TCCR1A = 0;     // set entire TCCR1A register to 0
    TCCR1B = 0;     // same for TCCR1B
    sei();
  }

}



SurferTim

Quote
Another thing which I don't understand is why this UDP implementation cares about if there is a remote device on the other end? My understanding of UDP is that it's connectionless; meaning it just sends information on the network and does not care if the remote device receives that information or not.

It doesn't care, unless it is on the same localnet as the destination. Then it will try for a while to send the packet. If it can't, it drops the packet.

PaulS

Quote
I am trying to implement the UDP send code in an interrupt routine that runs every second for n times.

That is so far from the right way to do it that I can't even begin to tell you how to correct the problems.

You understand, I hope, that UDP is not meant to send and receive responses. It is meant to be used like a radio station. Broadcast a message, If no one hears it, that makes no difference.

If it is heard, but not responded to, no big deal.

If it is heard, and the listener then sends a e-mail to the station saying thank you, that is a bonus.

If you expect a reply, UDP is not the protocol to use. If the timing of the reply is important, UDP is even less appropriate.

eddy9

Quote
You understand, I hope, that UDP is not meant to send and receive responses. It is meant to be used like a radio station. Broadcast a message, If no one hears it, that makes no difference.


Yes I understand how UDP works  ;). But the problem is that UDP appears to behave differently based on whether there is someone listens to it or not on the other end. The line of code that contains Udp.beginPacket(IP_Remote, Port_Remote) will execute almost instantly if there is a device to receive the message on the other end but it takes 2 to 5 seconds to execute if there is no device to  receive the message on the other end. my idea is to use the interrupt routine to periodically broadcast a message using UDP (just to see if some one is out there) and the main loop would only monitor incoming messages on UDP and do other stuff. I can see where in the library files (EhternetUdp.cpp and Dns.cpp) it attempts 3 times to connect to the remote (when you call Udp.beginPacket(IP_Remote, Port_Remote)) before it gives up but what I don't understand is why it does that?

SurferTim

Quote
The line of code that contains Udp.beginPacket(IP_Remote, Port_Remote) will execute almost instantly if there is a device to receive the message on the other end but it takes 2 to 5 seconds to execute if there is no device to  receive the message on the other end.

UDP packets are routed just like a TCP packet, except no connection is established between the source and destination. A "connection" is still established between individual devices/routers to pass the packet from router to router along the way. All routers will accept the packet if they are operational, whether the destination device exists or not.

If the router currently handling the packet can route the packet towards the destination, and the next router/device in line takes it, the packet transfer is almost immediate. If the next router/device in line has failed or doesn't exist, the current router will try to pass the packet for a few seconds, then drop the packet. That is it. Nothing more. Nobody is told it dropped.

If the destination device is not on your localnet (different subnet), chances are your gateway router will take the packet immediately with no check to see if the destination device exists. If the gateway router is down, the packet will be dropped after a few seconds, and you would see that short delay there also.

If the destination device is on your localnet (same subnet), the source device will try to pass the packet directly to the destination device, but if it is not there to take it, the packet is dropped after a few seconds.

Go Up