Arduino hangs with multiple UDP packets

Hi, I’m going crazy with this problem :~

Basically, I’m “polling” my Arduino with ethernet shield from an ajax webpage. Every a few seconds a PHP script sends an UDP packet to Arduino, and it answers with the status of a LED. I can also press a button on the page to make the LED switch on or off.

When I click on the button WHILE the script is already asking Arduino for the LED state, everything crashes and I have to reset Arduino to make it work again.

I suspect that this is somehow related to this bug: https://code.google.com/p/arduino/issues/detail?id=669
But I tried to download the latest nightly build of the IDE – and also to compile it from the current master on Github, but the problem persists.

This is my complete source code:

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

/* #define UDP_TX_PACKET_MAX_SIZE 64; */

int ledPin = 7; // ORANGE
int lightStatus1 = 3; // YELLOW
int val;

byte mac[] = {  
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 220);
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,

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




void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(lightStatus1, INPUT);
  digitalWrite(ledPin, HIGH);
  
  Ethernet.begin(mac,ip);
  Udp.begin(localPort);
  Serial.begin(9600);
}




void loop() {
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if(packetSize)
  {
    memset(packetBuffer,0,sizeof(packetBuffer)); // reset the buffer
    
    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("NEW PACKET");
    Serial.println(packetBuffer);
    
    if(auth()){
      if ( (getValue(packetBuffer, ',', 2) == "A:1" && digitalRead(lightStatus1) == LOW) || (getValue(packetBuffer, ',', 2) == "A:0" && digitalRead(lightStatus1) == HIGH) ) {
        digitalWrite(ledPin, LOW);
        delay(50);
        digitalWrite(ledPin, HIGH);
      }
  
      // send a reply, to the IP address and port that sent us the packet we received
      Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
      
      Udp.write("A:");
      Udp.write(digitalRead(lightStatus1) == LOW ? "0" : "1");
      Udp.endPacket();
    }
  }

  delay(10);
}


boolean auth(){
  if(getValue(packetBuffer, ',', 0) !="MYUSER" || getValue(packetBuffer, ',', 1) != "MYPASS"){
    Serial.println("AUTH ERROR");
    return false;
  }
  Serial.println("AUTH OK");
  return true;
}


/* UTILITIES */

 String getValue(String data, char separator, int index)
{
  int found = 0;
  int strIndex[] = {0, -1};
  int maxIndex = data.length()-1;

  for(int i=0; i<=maxIndex && found<=index; i++){
    if(data.charAt(i)==separator || i==maxIndex){
        found++;
        strIndex[0] = strIndex[1]+1;
        strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }

  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}

When I click on the button WHILE the script is already asking Arduino for the LED state,

To me it sounds like this is your problem - your confusing the website - add a safety to you web page to stop a second request being sent.

Mark

holmes4:

When I click on the button WHILE the script is already asking Arduino for the LED state,

To me it sounds like this is your problem - your confusing the website - add a safety to you web page to stop a second request being sent.

Mark

Nope, this is a stability problem on the Arduino side, this is the "root".
I can implement some sort of limiter on the web page, but what will happen if the same page is opened by two different clients? :slight_smile:

Does your incoming UDP packet actually always contain a null-terminated ascii string? Aim to prove that it does rather than assume it.

Does the Arduino serial output give you any clue what it's doing just before / during the lockup?

I see you're using the problematic String class. I recommend you stop doing that. You don't need it in any case - it's just providing a wrapper for the standard c-string library functions and it's safer and easier just to use those directly.

but what will happen if the same page is opened by two different clients?

Then you get to different UDP connections. How else dose the right response go to the right requester! :slight_smile: :slight_smile: :slight_smile:

Mark

Any reason you are resorting to use of UDP packets? TCP/IP protocol might be more robust.

PeterH:
Does the Arduino serial output give you any clue what it's doing just before / during the lockup?

I've just added a simple Serial.print(" ... "); at the end of the loop, discovering that Arduino is not completely crashing: it continues to run (logging "... ... ... ..." and so on), but Udp.parsePacket() begins to always return zero.

PeterH:
Does your incoming UDP packet actually always contain a null-terminated ascii string? Aim to prove that it does rather than assume it.

Can this be my problem? I'm sending a simple socket_sendto with PHP:

socket_sendto($socket, $message, strlen($message), 0, $server_ip, $server_port);

Maybe I have to add a flag instead of "0" as the 4th parameter, or to add a null character to the $message variable?

PeterH:
I see you're using the problematic String class. I recommend you stop doing that. You don't need it in any case - it's just providing a wrapper for the standard c-string library functions and it's safer and easier just to use those directly.

Which class? I'm not including Strings.h (?)

Any reason you are resorting to use of UDP packets? TCP/IP protocol might be more robust.

I want it to be fast, it can also lose some packet.... but it must not completely stop working :slight_smile:

flip79:

socket_sendto($socket, $message, strlen($message), 0, $server_ip, $server_port);

Maybe I have to add a flag instead of "0" as the 4th parameter, or to add a null character to the $message variable?

Yes, that will be a problem, because strlen will give you the number of characters excluding the null terminator. In order to convert the PHP string to a null-terminated C++ string I think you would need to append a null (zero) character to $message.

flip79:
Which class? I'm not including Strings.h (?)

The String class. Search for the word "String" in your sketch. Then get rid of it.

I'm using it only in the last function, to parse the csv variable that I receive via the udp call, do I have to replace it to work with char instead of strings? I can't simply delete the two "String" words... I think :slight_smile:

flip79:
I'm using it only in the last function, to parse the csv variable that I receive via the udp call, do I have to replace it to work with char instead of strings? I can't simply delete the two "String" words... I think :slight_smile:

That's correct. To remove use of the String class, you will need to delete that code and replace it with code that does the equivalent thing using null-terminated char arrays.

I found what is happening: when I turn on (or off) the relay from the web interface, sometimes the ethernet shield turn itself off for a couple of seconds. I can see the LEDs on the ethernet plug that turn off and then on. SOMETIMES when this occurs, the ethernet shield doesn't resume; it lose the IP and I have to manually reset Arduino.

    if(auth()){
      if ( (getValue(packetBuffer, ',', 2) == "A:1" && digitalRead(lightStatus1) == LOW) || (getValue(packetBuffer, ',', 2) == "A:0" && digitalRead(lightStatus1) == HIGH) ) {
        digitalWrite(ledPin, LOW);
        delay(50);
        digitalWrite(ledPin, HIGH);
      }

After digitalWrite, network activity stops.

Could it be related to power consumption? I'm using a small 5V relay produced by finder, it shouldn't absorb too much corrent (if I'm not wrong, it should be 40mA):

flip79:
After digitalWrite, network activity stops.

Could it be related to power consumption? I'm using a small 5V relay produced by finder, it shouldn't absorb too much corrent (if I'm not wrong, it should be 40mA):
http://www.farnell.com/datasheets/1792619.pdf

Absolutely. I suggest you disconnect the relay (but leave everything else the same) and see whether the problem goes away. If so it indicates that the relay is either taking too much current or causing too much noise. I don't know how you've connected the relay but since it's an inductive load you'd need to include a flyback diode to stop it zapping the I/O pin's driver when you turn it off. Also note that the maximum safe current per I/O pin is around 20mA and very few relays can be operated by such low current; for most relays, you would need to use a driver circuit between the Arduino and the relay.