Nano 33 IoT: Need help to resolve IP addresses of queued UDP packets

I have some difficulties to use UDP for communication with miltiple devices such as displays and sensors.

It appears that the data becomes exchanged, but the assignement of IP addresses becomes mixed up under specific circumstances

Setup Deskription:

  • Multiple Arduino Nano IOT 33
  • WiFiNina Module FW 1.4.8
  • WiFiNINA Arduino Lib 1.8.13
  • ArduinoCore-SAMD 1.8.11

there is one "sensor device"

  • the sensor device checks for new UDP packets about every about 1.2 seconds requesting sensor data (in the mean time a lot of sensor reading and calutation is done)
  • in case such request packet is received, the sensor device sends an UDP packet with sensor data to the IP address the request was received from
    Note: the receive function in code of the sensor is shown below

there are multiple "display" devices

  • each desplay device syncs up its internal RTC via NTP
  • each display device sends a UDP packet requesting new sensor data to the sensor device every minute

What I observe:
At system startup the display device clocks are not synchronized and everithing works as expected:

  • once a minute the display devices send their request
  • the sensor device receives (by luck) every request separated in 1.2 second "main" loops
  • the sensor device responses propperly to each display device by usind the IP address indicated for the request packet

Then, the display device sync their RTCs via NTP over time, so the timing of the request messages is synchronized as well

  • once a minute the display devices send their request, New: now these are (almost) send at the same time
  • due to that, the sensor receives (most likely) multiple request in one 1.2 second loop
  • the sensor detects this multiple packets correctly (see while loop below), but it appears the WiFi Nina FW/Lib reports all of the for one and the same IP address

As a result :

  • I can see in the debug logs that multiple display devices send their request packets
  • I can see in the debug logs that the sensor device reveives a corresponding numbers of request packages
  • BUT: the sensor device reports the same IP address for all of these request packages (not different ones identifying each display separately)
    ==> due to that, the sensor sends its responses multiple times to one display, not one time to each display

Please help me finding the caus for this...
As reference I show my receive function of the sensor device here (the display devices use the same approach)

Short description of the code:
All messages exchanged between devices use the same header, only the following contend is message specific.
Due to that, I first load the header data to figure out what message was reveived to then load the message specific part in a separate step
As described, the mechanism works well in general even for multiple displays as long as only one message is received at the time while such loop.
It apperas that the WiFi Nina firmware / lib runs in trouble identifying the correct and packet specific IP address in case UDP packages queue up in the FIFO/pipeline/Module while the scetch is busy with other tasks.

My expectation how the receive for multiple UDP packets from multiple devices works is:

  • use 'Udp.parsePacket()' to check if packet [N] is available and get size of that package
  • use 'Udp.remoteIP()' to get IP address of device that was sending packet[N]
  • use 'Udp.read()' to read data of packet [N]
  • optional: use 'Udp.flush()' to clean receive buffer for last remoteIP
  • use 'Udp.parsePacket()' to check if packet [N+1] is available and get size of that package
  • use 'Udp.remoteIP()' to get IP address of device that was sending packet[N+1]
    . . . . .
    This works so far, I get multiple packets, but I get the same IP address for all of them what is not true.
void checkForMessages(void)
{
         IPAddress        remoteIP;
         uint16_t         remotePort;
         Message_t        msg;
         pMessageHeader_t pMsgHeader  = (pMessageHeader_t)&msg;
         bool             clearBuffer = false;
         int              bufferSize  = Udp.parsePacket();                  // do we have received data? 
 

         while((bufferSize>=sizeof(MessageHeader_t))&&(clearBuffer==false)) // if there's potentially valid data available
         {
            delay(100);                                                     // no idea if this is needed...
            
            remoteIP   = Udp.remoteIP();
            remotePort = Udp.remotePort();

            Serial.print("Received data of size "); Serial.print(bufferSize);          // expected to be the size of the next UDP packet
            Serial.print(" from ");                 Serial.print(remoteIP);            // expected to be the IP address from the orgin of the next UDP package
            Serial.print(", port ");                Serial.println(remotePort);        // expected to be the UDP port the next packet is received on (for now: allways the same)

            if((bufferSize>0)&&(bufferSize<sizeof(MessageHeader_t)))                   // check if we got at least a message header
            {  clearBuffer = true                                                      // if not...
               goto LableClearBuffer;                                                  // got some garbage, clear it
            }

            bufferSize-=Udp.read((byte*)&msg, sizeof(MessageHeader_t));                // read msg header to figure out if, and what msg that is
            
            switch(pMsgHeader->magicOpcode)
            {  case MAGIC_MEASUREMENT_EXT_REQ: /*------------------------------------------------------------------------*/
                  if(bufferSize>=sizeof(MeasurementExtReq_t)-sizeof(MessageHeader_t))  // if it is complete, read rest of message
                  {  
				     bufferSize-=Udp.read((byte*)(&msg+sizeof(MessageHeader_t)),sizeof(MeasurementExtReq_t)-sizeof(MessageHeader_t));
                     
					 // valid message... handle it
					 Serial.println(">>> message is MeasurementExtReq <<<<<<<<<<<<<<<<<<<<<<<<<");     
                  } else                                                              // something is wrong, we are out of sync
                  {  Serial.println(">>> message is corrupted MeasurementExtReq  ==> flush");
                     clearBuffer = true;
                  }
                  break;
               default: /*------------------------------------------------------------------------------------------------*/
                  Serial.print(">>> unknown opcode received: 0x");
                  Serial.print(pMsgHeader->magicOpcode,HEX);
                  Serial.println(" ==> flush!!!! <<<");
                  clearBuffer = true;                                    // unknown msg, dump it
                  break;
            }

            if(clearBuffer==false)                                      // signal valid packet received
            {  digitalWrite(STATUS_LED,true);                           // start signalling we have a packet 
               delay(150);
               digitalWrite(STATUS_LED,false);                          // end signalling we have a packet
               delay(50);
            } else                                                      // dump received data
            {  Serial.println("clear receive buffer 1");
               Udp.flush();                                             // clear package receive buffer (for active IP only?) 
               bufferSize  = 0;
               clearBuffer = false;
            }

            Serial.print("rec Buffer left: ");                          // check if there is more packet data left 
            Serial.println(bufferSize);                                 // there should not....

            if(bufferSize==0)
            {   bufferSize = Udp.parsePacket();                         // do we have received some more UDP packet data?
                                                                        // if so, we would expect that it comes from a different IP address
                if(bufferSize>0)                                        // if yes: handle it in next turn of "while" loop
                {  Serial.print(">>> got more data: ");
                   Serial.print(bufferSize);
                   Serial.println(" <<<");
                } else
                {  Serial.println("got no more data...");               // if not, the "while" loop will be terminated
                   Udp.flush();                                         // just to be sure, might not be needed...
                }
            }
         };

         LableClearBuffer:                                             // hard break, we are out of sync (never called until today)      

         if(clearBuffer)                                               // garbage in the receive buffer... clear it
         {  Serial.println("clear receive buffer 2");
            Udp.flush();
         }   
 }

Wouldn't be easier to just broadcast the sensor data to the network? Or just let the sensor source send unsolicited messages to each display? The display can either accept or disregard the message

First of all, thanks for your reply.

The use case I describe is quite simplified to just point out the issue I have.
E.g. it should be possible to run multiple of such sensor+display setups in the same network. There are several use cases I have in mind that require a reliable IP address signaling for packets received.

I know that UDP is not reliable in the sense that packets can get lost, but my expectation is that if a packet is received it gehts the correct IP address assigned… it would be quite misleading for every implementation if not since the IP address is the common way to identify devices in a network.

First of all I would like to figure out if I got the Implementation right and use the API in the correct way…. Can somebody please either confirm that or hint out how to improve it?

Thanks

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.