Recieving UDP packets on Boron

boron
Tags: #<Tag:0x00007f1ca2daec40>

#1

I’m trying to set up a Boron board as a serial passthrough to UDP. Essentially it takes anything it receives via serial and sends it to a server in a UDP packet. That part is working just fine. The problem is the second part where incoming UDP packets should be passed on through serial. I have not been able to receive any packets using Udp.parsePacket() and Udp.recievePacket() won’t even compile with the example in the docs. I’m using a third party SIM (AT&T) and cloud is disabled. To send to the boron I’m using the IP I get from the packets sent by the boron and the port I set using Udp.begin(). Is there a better example on receiving UDP packets via LTE or is there a better way for me to get the public IP of the boron?


#2

That is a limitation of how cellular providers route the packets.
There isn’t a lot you can do about that AFAIK, but @rickkas7 can probably give some more background on the limitations and also how the Particle cloud circumvents these.


#3

Your server must send to the port the packet came from, not the port that you are listening on. The carriers do large-scale port forwarding and your Boron shares an IP address with many other users.

Also, the return channel will only be kept alive as long as the carrier keep alive. So for AT&T, once you send a packet to your server, the return path for the UDP packets will only be around for 30 seconds after the last data transmission in either direction. You can continue sending packets indefinitely, but once you stop, the port forwarding will be deleted.


#4

That makes sense, although after trying to send the packets back to the port they came still no luck. Is there a way to do Udp.begin() without setting a port or a way to let the boron know what port to listen on?
Here’s my code for trying to receive maybe I’m doing something wrong:

if(Cellular.ready()){
				rxCount = Udp.parsePacket();
			}
			
			if (rxCount > 0) {
				Serial.println(rxCount);
				Udp.read(rxBuff, 128);
			} else if (rxCount < -1) {
				rxError = rxCount;
				// need to re-initialize on error
				Udp.begin(UDPRXPORT);
			}
			if (!rxError) {
				Serial.write(rxBuff, rxCount);
				rxCount = 0;
			}

That’s just in the loop and parsePacket() never returns anything other than 0 even when we reply with messages quickly to the adress they came from. I’ve also tried using Udp.recievePacket() but my boron goes into a fault mode (red blinking light) every time I use it.
Thanks for the help


#5

I tested this code on a Boron LTE running 0.9.0 and it worked properly. This is the device firmware:

#include "Particle.h"

SerialLogHandler logHandler;

SYSTEM_THREAD(ENABLED);

const unsigned long PACKET_INTERVAL_MS = 10000;

const IPAddress remoteAddr(65, 19, 178, 42);
const int remotePort = 7123;

unsigned long lastPacketTime = 0;

UDP udp;
bool networkConnected = false;
int counter = 0;

void setup() {

}

void loop() {
	// Check the network connection status
	if (networkConnected) {
		if (!Cellular.ready()) {
			Log.info("disconnected from network");
			networkConnected = false;
		}
	}
	else {
		// Not yet connected
		if (Cellular.ready()) {
			Log.info("connected to network");
			networkConnected = true;

			// Must call udp.begin only after connected to the cellular or Wi-Fi network
			udp.begin(0);
		}
	}

	if (networkConnected && millis() - lastPacketTime >= PACKET_INTERVAL_MS) {
		lastPacketTime = millis();

		char buf[64];
		snprintf(buf, sizeof(buf), "counter=%d", ++counter);

		int count = udp.sendPacket(buf, strlen(buf), remoteAddr, remotePort);
		if (count > 0) {
			Log.info("sent %s", buf);
		}
		else {
			Log.info("send failed error %d", count);
		}
	}
	if (networkConnected) {
		char buf[64];
		int count = udp.receivePacket((uint8_t *)buf, sizeof(buf) - 1);
		if (count > 0) {
			buf[count] = 0;

			Log.info("rcvd %s", buf);
		}
	}
}


This is the server code. It’s node.js but it’s just a simple program that echos UDP packets back to the host and port they came from.


// To run:
// node server.js

const dgram = require('dgram');

const server = dgram.createSocket('udp4');

const listenPort = 7123;

server.on('error', (err) => {
	console.log('server error', err.stack);
	server.close();
});

server.on('message', (msg, rinfo) => {
	console.log('server got ' + msg + ' from ' + rinfo.address + ':' + rinfo.port);
	server.send(msg, 0, msg.length, rinfo.port, rinfo.address);
});

server.on('listening', () => {
	console.log('server listening on port ' + listenPort);
});

server.bind(listenPort);

Here’s the USB serial debug log:

0000009224 [app] INFO: connected to network
0000009275 [system] ERROR: Failed to load session data from persistent storage
0000010000 [app] INFO: sent counter=1
0000020000 [app] INFO: sent counter=2
0000030000 [app] INFO: sent counter=3
0000040000 [app] INFO: sent counter=4
0000050000 [app] INFO: sent counter=5
0000060000 [app] INFO: sent counter=6    <- this is where I started the server
0000060525 [app] INFO: rcvd counter=6
0000070000 [app] INFO: sent counter=7
0000070526 [app] INFO: rcvd counter=7
0000080000 [app] INFO: sent counter=8
0000080526 [app] INFO: rcvd counter=8

Here’s the node.js console output:

$ node udpecho.js 
server listening on port 7123
server got counter=6 from 162.244.250.194:15751
server got counter=7 from 162.244.250.194:15751
server got counter=8 from 162.244.250.194:15751