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();
}
}