I'm trying to receive a packet on an Argon and save it to a variable.
I can easily get the variable c below, but I want to get the whole packet.
In my trial case I'm sending a packet:
char* packet = "12345";
What do I need to do to change the code below to iterate thru all the characters in the packet and get it back into a new variable, instead of reading the first Character and discarding the rest??
Or - alternatively, can someone point me to an example of receiving UDP data that is longer, and getting that data into a form that I can manipulate it?
void loop() {
// Check if data has been received
if (Udp.parsePacket() > 0) {
// Read first char of data received
char c = Udp.read();
// Ignore other chars
while(Udp.available())
Udp.read();
// Store sender ip and port
IPAddress ipAddress = Udp.remoteIP();
int port = Udp.remotePort();
// Echo back data to sender
Udp.beginPacket(ipAddress, port);
Udp.write(c);
Udp.endPacket();
Here is some stripped down code I use to receive UDP packets and then parse them. I’m not including the parser code, just the UDP reception. I receive the UDP message into a character array jsonString. Once received into the jsonString buffer, you should be able to do anything you want. In my case, I run it through a json parser. I made my buffer size 1500 because that is the typical MTU setting on a network. You can adjust size as needed but 1500 is quite large.
char jsonString[1500];
uint16_t UDPMaxPacketSize = 1500; //Network MTU size.
SerialLogHandler logHandler(115200, LOG_LEVEL_TRACE);
uint16_t UDPPort = 8023; //UDP listening port.
uint16_t UDPMaxPacketSize = 1500; //Network MTU size.
IPAddress MCAddress; //Multicast Address for Receiving Commands
setup() {
waitUntil(Particle.connected); //Network must be connected before calling Udp.begin() per photon reference.
IPAddress myIP = WiFi.localIP();
Log.warn("Local IP: %s; SSID: %s; RSSI: %i", myIP.toString().c_str(), WiFi.SSID(), WiFi.RSSI());
//Start UDP for receiving commands via wi-fi.
Log.warn("Starting UDP on Port %d.", UDPPort);
Udp.begin(UDPPort);
Log.warn("Joining Multicast at address: %s", MCAddress.toString().c_str());
Udp.joinMulticast(MCAddress);
}
loop() {
bool rxError = true;
int size = Udp.receivePacket((byte*)jsonString, UDPMaxPacketSize-1);
if (size > 0 && size < UDPMaxPacketSize) {
jsonString[size] = 0;
rxError = false;
} else if (size < 0) {
Log.error("UDP receive size error: size = %i", size);
rxError = true;
// need to re-initialize on error
Udp.begin(s.UDPPort);
}
//Message receive was success... parse it.
if (!rxError) {
Log.trace("UDP message received from %i : %i:", Udp.remoteIP(), Udp.remotePort());
Log.trace(jsonString);
//do something with the jsonString
}
}
@ninjatill's advice shows you how you get to your endgoal, but I sense some more fundamental and basic questions need to be addressed too.
If you what to iterate over multiple bytes and store them in a string (aka character array) you'd do something along this line
void loop() {
if (Udp.parsePacket() > 0) {
char buf[128]; // buffer to hold the string
int idx = 0;
memset(buf, 0, sizeof(buf)); // clear the buffer
while(Udp.available() && idx < sizeof(buf) - 1) // only read till buffer is full
buf[idx++] = Udp.read(); // store newly read byte at location idx and increment idx afterwards
// other stuff needed to clean up
}
}
That's how you could do it byte by byte, but reading all available data at once (as @ninjatill does in his code) is preferable.
In the code below, it comments that if there is an error, we need to re-initialize the UDP instance.
This happens every loop if there is no UDP data received, so every milli-second or so.
When I have the “Udp.begin(UDPPort);” in the ‘else if’ - I miss a lot of packets, but when I comment that line out, my reception is much more reliable.
What is the need for the reinitialization?
Is the code problematic without it?
bool rxError = true;
int size = Udp.receivePacket((byte*)jsonString, UDPMaxPacketSize-1);
if (size > 0 && size < UDPMaxPacketSize) {
jsonString[size] = 0;
rxError = false;
} else if (size < 0) {
Log.error("UDP receive size error: size = %i", size);
rxError = true;
// need to re-initialize on error
Udp.begin(UDPPort);
}
//Message receive was success... parse it.
if (!rxError) {
Log.trace("UDP message received from %i : %i:", Udp.remoteIP(), Udp.remotePort());
Log.trace(jsonString);
//do something with the jsonString
}
}
That code is not the same as the example in the docs. -1 is returned if there is no data. You should not call udp.begin() in that case.
When an actual error code < -1 occurs, then it’s not a bad idea to call udp.begin() again, though it’s actually better to monitor the connected state of WiFi and call it when reconnected, not on error.
OK, great, that makes me feel better, and I don’t miss many packets.
I’ll just call udp.begin when < -1is returned. I’ll look into monitoring the wifi later.