Arduino shield crashes/stops after sending and receiving 50,000+ Udp packets

Hi

I have Ethernet shield on my arduino due with the w5100 chip. My arduino is meant to read udp (a packet size 76), then send an acknoledgement (28 bytes) back meanwhile spaming udp packets (76 bytes), however my arduino will work fine for about 50,000+ packets then crash/stop. I am using a packetsniffer to see this working (wireshark), and generating packets using c#.

Here is a modified version of the original send receive example where the problem also occurs.

#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,0x13,0xFB,0x6B };
 
 
unsigned int localPort = 18865;
 
char packetBuffer[100];
byte  ReplyBuffer[] = "acknowledged";
byte  ReplyBuffer2[] = "aasdasdfasfasfa";
 
EthernetUDP Udp;
 
void setup() {
  Serial.begin(57600);
  
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);
  
    Serial.println("Initialize DHCP: ");
  if (Ethernet.begin(mac)){
     Serial.print("[success] IP: ");
     Serial.println(Ethernet.localIP());
  }
  else
     Serial.println("[Failed]");
  Udp.begin(localPort);
  Serial.println(UDP_TX_PACKET_MAX_SIZE);
}
 
void loop() {
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    Udp.read(packetBuffer, 100);
    Udp.beginPacket(IPAddress(My ip), 18007);
    Udp.write(ReplyBuffer, 28);
    Udp.endPacket();
  }
  Udp.beginPacket(IPAddress(MY ip), 18008);
  Udp.write(ReplyBuffer2, 76);
  Udp.endPacket();
}

Here is my actual code its decodes the packet and some other functions

#include <EthernetClient.h>
#include <EthernetServer.h>
#include <SPI.h>         // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>  

EthernetUDP udp;
EthernetClient client;
typedef struct __attribute__((__packed__)) acknowledgement 
{
  unsigned short majorAck;
  unsigned short minorAck;
  byte messageTypeAck;
  byte channelAck;
  unsigned short payLoadLengthAck;
  unsigned long IDAck;
  double dateTimeAck;
  byte sourceIP1Ack;
  byte sourceIP2Ack;
  byte sourceIP3Ack;
  byte sourceIP4Ack;
  signed short zeroes1Ack;
  signed short zeroes2Ack;
} acknowledgement;

typedef struct __attribute__((__packed__)) data 
{
  unsigned short major;
  unsigned short minor;
  byte messageType;
  byte channel;
  unsigned short payLoadLength;
  unsigned long ID;
  double dateTime;
  byte sourceIP1;
  byte sourceIP2;
  byte sourceIP3;
  byte sourceIP4;
  signed short zeroes1;
  signed short zeroes2;
  byte payLoadType;
  byte pinNumber;
  byte digitalValue;
  byte digitalPullUpEnable;
  signed short analogADCConversion;
  signed short zeroes3;
  char variableName;
  double analogValue;
} data;

unsigned short majorVersion = 2;//for functions
unsigned short minorVersion = 0;
unsigned long IDCountAck = 1;
unsigned long IDCount= 1;
double messageTimeStampAck = 0;
double messageTimeStamp = 0;
byte timeStampBuffAck[8];
byte IDBuffAck[4];

byte majorBuffAck[2];//for major and minor checks
unsigned short msgMajorVersionAck;
byte minorBuffAck[2];
unsigned short msgMinorVersionAck;

char variableNameBuff[32];

int a = 1;//loop iteration
int count = 1;

void setup() 
{
  Serial.begin(57600);
  uint8_t mac[6] = {0x90, 0xA2, 0xDA, 0x00, 0xFA, 0x7D};

  Ethernet.begin(mac);
  udp.begin(18005);//listener port

  pinMode(4, OUTPUT); //disable sd card
  digitalWrite(4, HIGH);

  Serial.print("localIP: ");
  Serial.println(Ethernet.localIP());
  Serial.print("subnetMask: ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("gatewayIP: ");
  Serial.println(Ethernet.gatewayIP());
  Serial.print("dnsServerIP: ");
  Serial.println(Ethernet.dnsServerIP());

}

void acknowledgementCreator () //function create and acknowledgement of 28 bytes
{
  acknowledgement* sentAck = (acknowledgement*) malloc(sizeof(acknowledgement));//allocate memory
  sentAck->majorAck = majorVersion;
  sentAck->minorAck = minorVersion;
  sentAck->messageTypeAck = 2;
  sentAck->channelAck = 3;
  sentAck->payLoadLengthAck = 36;
  sentAck->IDAck = IDCountAck;
  sentAck->dateTimeAck = messageTimeStampAck;
  sentAck->sourceIP1Ack = Ethernet.localIP()[0];
  sentAck->sourceIP2Ack = Ethernet.localIP()[1];
  sentAck->sourceIP3Ack = Ethernet.localIP()[2];
  sentAck->sourceIP4Ack = Ethernet.localIP()[3];
  sentAck->zeroes1Ack = 00;
  sentAck->zeroes2Ack = 00;
  udp.beginPacket(IPAddress(MY ip), 18006);
  udp.write((byte*) sentAck, 28);
  udp.endPacket();
  free(sentAck);
}

void packetCreator () //function to create a packet with a head and payload of 76 bytes
{
  data* sentData = (data*) malloc(sizeof(data));//allocate memory
  sentData->major = majorVersion;
  sentData->minor = minorVersion;
  sentData->messageType = 1;
  sentData->channel = 3;
  sentData->payLoadLength = 36;
  sentData->ID = IDCount;
  IDCount++;//increment the id count
  sentData->dateTime;
  sentData->sourceIP1 = Ethernet.localIP()[0];
  sentData->sourceIP2 = Ethernet.localIP()[1];
  sentData->sourceIP3 = Ethernet.localIP()[2];
  sentData->sourceIP4 = Ethernet.localIP()[3];
  sentData->zeroes1 = 00;
  sentData->zeroes2 = 00;
  sentData->payLoadType;
  sentData->pinNumber;
  sentData->digitalValue;
  sentData->digitalPullUpEnable;
  sentData->analogADCConversion;
  sentData->zeroes3;
  sentData->variableName;
  sentData->analogValue;
  udp.beginPacket(IPAddress(MY ip), 18006);
  udp.write((byte*) sentData, 76);
  udp.endPacket();
  free(sentData);
}

void remove_all_chars(char* str, char c) //function to remove unwanted character from a string
{
    char *pr = str, *pw = str;
    while (*pr) {
        *pw = *pr++;//always advance the reading pointer
        pw += (*pw != c);//and advance the writing pointer only when it's not pointing to a given character
    }
    *pw = '\0';
}

void variableDecoder () 
{//function to decode variable name
   remove_all_chars(variableNameBuff, '.');
   if (strcmp(variableNameBuff, "IMV_DRIVE")==0) 
   {
      //writepin 4
      Serial.println(1);
   }
   else if (strcmp(variableNameBuff, "HPV_DRIVE")==0) 
   {
     //writepin 5
     Serial.println(2);
   }
   else if (strcmp(variableNameBuff, "VVT_DRIVE")==0) 
   {
     //writepin 6
     Serial.println(3);
   } 
   else if (strcmp(variableNameBuff, "VEHICLE_CAN")==0) 
   {
     //writepin ???
     Serial.println(4);
   } 
   else if (strcmp(variableNameBuff, "INJECTOR_DRIVE1")==0) 
   {
     //writepin 7
     Serial.println(5);
   }  
}

void readPins ()//function to read all pins
{
  //read pins all
}

void loop() 
{
  //check for new udp-packet:
  int size = 0;
  size = udp.parsePacket();
  if (size == 76)
  {
    char* msg = (char*)malloc(1024);//alocate memory
    int len = udp.read(msg, 1024);
    msg[len] = 0;
    udp.flush();

    //check major Version and minor and channel and if message type == 2
    majorBuffAck[0] = msg[0];
    majorBuffAck[1] = msg[1];
    minorBuffAck[0] = msg[2];
    minorBuffAck[1] = msg[3];
    memcpy(&msgMinorVersionAck, minorBuffAck, sizeof msgMinorVersionAck);//alocate memory for major and minor check
    memcpy(&msgMajorVersionAck, majorBuffAck, sizeof msgMajorVersionAck);
    if ((msgMajorVersionAck == majorVersion) && (msgMinorVersionAck == minorVersion) && (msg[5] == 2) && ((msg[4] == 1) || (msg[4] == 3)))
    {
      if (msg[4] == 3)
      {
        IDCount = 1;
        for (int i = 0; i < len; i++)//loop through the packet to get to timestamp
        {
          if (i >= 12 && i <= 19)//copy timestamp and ID back for the acknoledgement
            {
              timeStampBuffAck[i - 12] = msg[i];
            }
          if (i >= 8 && i <= 11)
          {
            IDBuffAck[i - 8] = msg[i];
          }
        }
      }
      if (msg[4] == 1)
      {
         for (int i = 0; i < len; i++)//loop through the packet to get to timestamp
         {
            if (i >= 12 && i <= 19)//copy timestamp and ID back for the acknoledgement
            {
              timeStampBuffAck[i - 12] = msg[i];
            }
            if (i >= 8 && i <= 11)
            {
              IDBuffAck[i - 8] = msg[i];
            }
            if (i >= 36 && i <= 67)
            {
              variableNameBuff[i -36] = msg[i];
            }
          }
          Serial.println(F(variableNameBuff));//print the variable name to serial
          Serial.println(count);
          count++;
          //variableDecoder();
       }
      memcpy(&messageTimeStampAck, timeStampBuffAck, sizeof messageTimeStampAck);//copy and convert timeStamBuff into messageTimeStamp
      memcpy(&IDCountAck, IDBuffAck, sizeof IDCountAck);//copy and convert IDBuff into IDCount
      acknowledgementCreator();
    }
    free(msg);
  }
  if ((a % 10) == 0 )
  {
    packetCreator();
  }
  a++;
}

thanks for your help!

Do the UDP packets go through the router to get to the destination device? How long does it take to send the 50,000 packets? How long is the dhcp lease time in the router?

I don't see where you are renewing the dhcp lease. Maybe that causes the fail? http://arduino.cc/en/Reference/EthernetMaintain

Yes they go through the router to get to the destination device. The packets being sent were 5ms apart. The dhcp lease is at least 2-3 days so not an issue.

Could it be the Rx/tx buffer due to them being sent so fast?

Where in your code is it failing? Is it freezing or just not sending the packets?

Thanks for your continued help Surfer Tim!

It freezes and doesn’t send anymore packets until it is reset.

Debugging it with code posted below, i ran it a few time and it seemed to freeze on the Serial.println(2), and froze once on the Serial.println(5);

It appears that it doesn’t endpacket properly after a while, not sure why this would happen any ideas?

Thanks

Manewc

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


EthernetUDP udp;
EthernetClient client;
byte sentAck[28];
char msg[76]; 

void setup() 
{
  Serial.begin(57600);
  uint8_t mac[6] = {0x90,0xA2,0xDA,0x00,0xFA,0x7D};

  Ethernet.begin(mac);
  udp.begin(18005);//listener port

  pinMode(4, OUTPUT); //disable sd card
  digitalWrite(4, HIGH);

  Serial.print("localIP: ");
  Serial.println(Ethernet.localIP());
}

void loop() 
{
  //check for new udp-packet:
  int size = udp.parsePacket();
  if (size > 0 )
  {
    udp.read(msg, size);
    udp.beginPacket(IPAddress(My IP), 18006);
    Serial.println(1);
    udp.write(sentAck, 28);
    Serial.println(2);
    udp.endPacket();
    Serial.println(3);
  }
  udp.beginPacket(IPAddress(My IP), 18008);
  Serial.println(4);
  udp.write(sentAck, 28);
  Serial.println(5);
  udp.endPacket();
  Serial.println(6);
}

UDP.endPacket() has a return value, even though the reference page doesn't mention it. http://arduino.cc/en/Reference/EthernetUDPEndPacket

The EthernetUdp.h file has the return value documented.

  // Finish off this packet and send it
  // Returns 1 if the packet was sent successfully, 0 if there was an error
  virtual int endPacket();

Evaluate the endPacket return value like this:

    // replace this
    udp.endPacket();
    // with this
    if(!udp.endPacket()) Serial.println(F("packet send fail"));

A fail indicates the next device en route refused the packet, usually your router. A success does not indicate the packet reached its destination, only that it was accepted by the next device en route (your router).

If the destination device is localnet, then this can be used to determine if the destination device received the packet.

Using your if statement it appears that it doesn't fail to send the packet.

If i serial.print the value returned it never seems to print 0 or a 1, its just freezes which means the if statement in the library never become true, or it gets stuck before this (maybe the while loop?), not sure why this is.

int sendUDP(SOCKET s)
{
  W5100.execCmdSn(s, Sock_SEND);

  /* +2008.01 bj */
  while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) 
  {
    if (W5100.readSnIR(s) & SnIR::TIMEOUT)
    {
      /* +2008.01 [bj]: clear interrupt */
      W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT));
      return 0;
    }
  }

  /* +2008.01 bj */    
  W5100.writeSnIR(s, SnIR::SEND_OK);

  /* Sent ok */
  return 1;
}

The destination is localnet but i don't think it sends that last packet due to it not returning a value.

Are you certain there are no other SPI devices on the SPI bus, like a SD card in the shield's slot? That is a notorious reason for a SPI bus fail.

There is no other device plugged in, just got the shield (with poe) plugged into the arduino, no sd card slot (which i also disable).

I have 2 ethernet shields which i have tested in the same way getting the same results.

It does not always stop on the same endpacket(), what i mean is it sometimes stops on the one inside the if statement and sometimes on the one outside the ifstatement, could this mean a library error, or the buffer which the endpacket sends gets corrupt somehow?

Thanks

Manewc

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

EthernetUDP udp;
EthernetClient client;
byte sentAck[28];
char msg[76]; 

void setup() 
{
  Serial.begin(57600);
  uint8_t mac[6] = {0x90,0xA2,0xDA,0x00,0xE9,0x07};

  Ethernet.begin(mac);
  udp.begin(18005);//listener port

  pinMode(4, OUTPUT); //disable sd card
  digitalWrite(4, HIGH);

  Serial.print("localIP: ");
  Serial.println(Ethernet.localIP());
}

void loop() 
{
  //check for new udp-packet:
  int size = udp.parsePacket();
  if (size > 0 )
  {
    udp.read(msg, size);
    udp.beginPacket(IPAddress(My IP), 18006);    
    Serial.println(udp.write(sentAck, 28));   
    Serial.println(udp.endPacket());
    Serial.println(2);
  }
  udp.beginPacket(IPAddress(My IP), 18008);
  Serial.println(udp.write(sentAck, 28)); 
  Serial.println(udp.endPacket());
  Serial.println(4);
}

Then I don't know. I'm not familiar with the Due. May be a memory or buffer overflow.

However, if you plan on using a SD card, you must disable the SD SPI BEFORE you call Ethernet.begin(), not after.

Well thanks for help SurferTim, you have a least helped me narrow down the possibilities.

I tried it on my mega and my uno with the same setup no luck.

As you say i reckon it might be the sockets on the w5100, too many open maybe or the rx/tx buffer overflowing.

I will keep trying!