Stress test of UDP messages leads to weird behaviors

Post here all questions related to STM32 core if you can't find a relevant section!
Post Reply
Step73
Posts: 27
Joined: Tue Jan 14, 2020 2:55 pm

Stress test of UDP messages leads to weird behaviors

Post by Step73 »

Nucleo-144 F429ZI.
Here my test setup:

PC ---> ethernet switch ---> one or more Nucleo-144 F429ZI boards

A software that runs on the PC (other details below) sends OSC bundles (UDP packets) to one or more devices.
The device does something and then answer with another OSC bundle after some time.

I set up a fake test firmware, that does nothing but it reproduce the weird behaviors:

Code: Select all

#include <LwIP.h>
#include <ArduinoQueue.h>
#include <STM32Ethernet.h>
#include <EthernetUdp.h>
#include <OSCMessage.h>
#include <OSCBundle.h>
#include <OSCData.h>

#define UDP_TX_PACKET_MAX_SIZE 1024

EthernetUDP Udp;
IPAddress remoteIP;
unsigned long oldTick;
OSCBundle bundleServo;
char answer[128];
int ch;
float pos;

int getIndex(OSCMessage &msg, int patternOffset)
{
  char buf[8];
  msg.getAddress(buf, patternOffset + 1, 8);

  return atoi(buf);
}

void servo_fade_handler(OSCMessage &msg, int patternOffset)
{
    ch = getIndex(msg, patternOffset);
    pos = msg.getFloat(0);    
    oldTick = millis();
}

void bundle_send(OSCBundle *bundle)
{
  Udp.beginPacket(remoteIP, 8888); 
  bundle->send(Udp);
  Udp.endPacket();
  bundle->empty();
}

void setup() 
{
  Serial.begin(115200);
  delay(1000);

  IPAddress localIP = IPAddress(192, 168, 100, 2);
  IPAddress netmask = IPAddress(255, 255, 0, 0);
  IPAddress dns = IPAddress(192, 168, 1, 1);
  IPAddress gateway = IPAddress(192, 168, 1, 1);

  Ethernet.begin(localIP, netmask, dns, gateway);
  Udp.begin(8888);
}

void loop() 
{
  uint8_t data[UDP_TX_PACKET_MAX_SIZE];
  uint16_t size = Udp.parsePacket();
  
  if (size > 0 && size < UDP_TX_PACKET_MAX_SIZE)
  {
    Udp.read(data, size);
    remoteIP = Udp.remoteIP();

    OSCBundle bundle;
    bundle.fill(data, sizeof(data) - 1);
    data[size] = '\0';
  
    if (bundle.getError())
    {
      Serial.print("[OSC] Error: ");
      Serial.println(bundle.getError());
      return;
    }
  
    int bundleSize = bundle.size();
    for (int i = 0; i < bundleSize; i++)
    {
      OSCMessage msg = bundle.getOSCMessage(i);  
      msg.route("/servo/fade", servo_fade_handler);
    }  
  }
  else Udp.flush();

  if ((oldTick > 0) && ((millis() - oldTick) > 500))
  {
      bundleServo.empty();
      sprintf(answer, "/servo/fade/2/%u", ch);
      bundleServo.add(answer).add(pos);
      bundle_send(&bundleServo);
      oldTick = 0;    
  }
}
The two wrong behavior are:
  • huge ping time, up to 3-4 seconds
  • loss of packets from board to PC
To narrow down the possible causes I changed:
  • PC (MAC, Windows, Linux)
  • Software (MAX, Qt5 application I wrote by myself)
  • Switch (and I also tried to remove it, but this doesn't allow to test with multiple boards, see below)
  • Cables (CAT5 and CAT6, not crimped by self)
  • Nucleo-144 F429ZI (at least 10+)
Of course those issues appears quite rarely. Sometimes after a couple of minutes, after after some hours.
I'm aware the UDP protocol is not fully reliable, but I worked with it for 15 years and I never lost a single packet. I used it in very noisy and complex networks. Here the scenario is pretty ideal: one PC only, one or more (< 5) devices. No internet, no routers, no firewall, nothing.

When the board enter in the "high latency" mode, it seems it receives ( = processes) the packets with some delay. The same delay shown by the pings.
The only way to get out is to reset the board. Even disconnecting and reconnecting the Ethernet cable does nothing.

Both issues fire more frequently if the PC sends packets to multiple boards.
For example, let's say I have 4 boards connected to the switch. The PC, every second sends five OSC bundles, on for each board ( = to a different IP address). The bundles are sent "simultaneously" because all the devices should receive the messages about at the same time.

In detail, the loss of packets happens in any case even with a single board connected to the PC (without the router).
I checked the return values of the functions and all seems correct - no errors.

Someone on another forum suggested to set up a filter to discard the packets that have a different destination MAC address, but I didn't find a way to do this.

Any thought is welcome. And of course feel free to ask other useful details.
Post Reply

Return to “General discussion”