Sunday

Monitoring an RF24/NRF52x Network & Creating a Scanner with the XIAO 52840 Sense

Monitoring an RF24/NRF52x Network & Creating a Scanner with the XIAO 52840 Sense

Monitoring the data from a scanner and other sources in real-time


I've been trying automate analysis of the RF24/NRF52 communication stack lately and decided it was time to automate things to a degree further. I've setup a system using MQTT and a failover node in the network, so at any given time, I can switch my main RF24/RF52 network to a different channel for testing purposes. The results have been a bit interesting, with interference popping up on channels that appear clean for long periods of time, going away after I switch to a new channel... for a while.

I also leverage NodeRed, MQTT, and other methods to monitor the radio network. To put things in perspective, I am using TCP/IP over the radio network, using the NRF24 radios as a standard NIC, to test connectivity etc, so the radios are very busy, transmitting many 32-byte packets for every TCP/IP packet sent. The network layer handles routing, fragmentation/reassembly, and the mesh layer ensures nodes stay connected to the network even under adverse conditions.

Here is a couple pictures showing ping statistics for a RPi5 running RF24Gateway in close proximity to a very busy master node:




This last picture shows a clean channel with minimal interference over a long period of time.



The % success rate of pinging the RPi5 from the master node, showing 2.24% packet loss on a busy network after a couple hours after changing to a better channel:


This is with 17 RF42Ethernet and/or RF24Gateway nodes running on the network and communicating large MQTT messages typically every few seconds each, so I'd say that amount of packet loss is very much acceptable. The network runs on a variety of NRF24 modules as well as the newer NRF52x modules.

The following is a graph of how long each of 10 nodes stay connected to the MQTT server over the radio network before having to re-connect. This tends to happen when there is interference and/or the mesh breaks down a bit and needs to re-converge. In some cases, in good radio conditions, nodes stay connected up to 5 hours or longer. With a recent update to RF24Ethernet, nodes should now stay connected even longer!



You see, I was thinking that 17 nodes pumping out constant traffic might be a bit too much for a the mesh network, but the results of testing indicate that this is not the case. I've had more nodes on a single network in the past, but was doubting recent changes to the network and the network itself. Testing on separate channels shows that the mesh works great with this number of nodes, its just the interference causing problems, which would occur with any number nodes.

One good example is the following screenshot, you can see the RX Packets (user): 327 line. Since none of my nodes are sending RF24Mesh or RF24Network messages, this is just one more pretty good indicator that one of my neighbors has an affinity for RF24 programming and is constantly hitting my network with spam and garbage. There is a history of DOS attacks as well, which took advantage of limited functionality of the is_valid_address() function of RF24Network at the time, and continue in very limited fashion due to the simplicity and effectiveness of RF24Mesh. Its been going on for years, almost daily, and I just can't understand the obsession with trying to hack my radio network. Its for testing purposes and contains no useful data. 
For somebody who was able to study the RF24 stack and identify a quality DOS attack that required only one small radio and took down my whole network, why not do something constructive with those skills?


The following is a good example of interference on the network, with my main network experiencing massive interference, with a node about 1.5-meters from the master unable to establish connectivity for a long period of time. I'm not sure what creates this level of interference, but it seems most if not all of my nodes on the main testing network using channel 111 lost connectivity for this same period of time between 10:33pm and 12:18am Jun 28th to Jun 29th 2024.



With that, I've developed a scanner sketch for the XIAO NRF52840 Sense, since the radio has a feature to directly monitor RSSI levels, and it also has an option to monitor received packets separately. This is a little different from the scanner sketch included with the library, since it uses the RGB LEDs onboard to indicate signal strength in real time. It also outputs data for the Serial Plotter in the Arduino IDE, so you can see what is going on on a graph as well as the LED indicators.

The Scanner:

The images below show the Serial Plotter output in the Arduino IDE. Since I have a very busy master node, it is normal to see a fair number of 'RX 'packets. The 'Values' indicator shows the count of how often the radio received a signal with an RSSI better than -65dBm.



The scan in the pics are during normal mesh operation, with not much happening. When there is a large amount of interference the RSSI (green) line goes way up, communication is hindered, but the mesh nature of the system ensures that nodes re-converge around the master node in a short period of time after the interference stops. Testing shows the mesh is very stable and reliable at this point, with interference measured showing a direct correlation to the communication abilities of the mesh.

The Sketch:

The sketch is fairly simple, but very useful for pulling in data regarding noise and received packets on a given channel over time. 

The sketch is also available on GitHub here.

/*
* Single channel scanner for XIAO 52840 Sense
*
* Monitoring of a single channel using the built-in radio of the NRF52840
* Scans a single channel for noise using the RSSI measurement feature
* Can also listen for received packets
*
* Used for monitoring level of traffic and noise separately for a given RF24Mesh master node
* Default is RSSI level monitoring, uncomment USE_RX to enable monitoring of received packets also
*
* ** LED Indicators: **
* Blue: Minimal traffic,
* Green: Medium traffic, 15/100 signals > -65dBm
* Red: Heavy traffic,  25/100 signals > -65dBm
* Orange: Very heavy traffic, 35/100 signals > -65dBm
*
*/
#include "nrf_to_nrf.h"
#include <RF24Network.h>
#include <RF24Mesh.h>

/**********************************************************/
#define CHANNEL 3   // What channel to scan on
#define MIN_DBM 65  // The minimum RSSI (dBm) for counting signals. Higher value == greater sensitivity.
#define USE_RX      // Also listen for and count received packets
/**********************************************************/

// Set up nRF24L01 radio on SPI bus plus pins 7 & 8

nrf_to_nrf radio;
RF52Network network(radio);
RF52Mesh mesh(radio, network);

const uint8_t num_channels = 1;
uint8_t values = 0;
uint8_t valuesR = 0;

// LED Setup
void red() {
  digitalWrite(LED_BLUE, HIGH);
  digitalWrite(LED_RED, LOW);
  digitalWrite(LED_GREEN, HIGH);
}
void green() {
  digitalWrite(LED_BLUE, HIGH);
  digitalWrite(LED_RED, HIGH);
  digitalWrite(LED_GREEN, LOW);
}
void blue() {
  digitalWrite(LED_BLUE, LOW);
  digitalWrite(LED_RED, HIGH);
  digitalWrite(LED_GREEN, HIGH);
}
void orange() {
  digitalWrite(LED_BLUE, HIGH);
  digitalWrite(LED_RED, LOW);
  digitalWrite(LED_GREEN, LOW);
}

void setup(void) {
  Serial.begin(115200);
  Serial.println(F("\n\rRF24/examples/scanner/"));

  // Setup and configure rf radio
  mesh.setNodeID(0);
  mesh.begin(CHANNEL);
  radio.setAutoAck(false);
  radio.setCRCLength(NRF_CRC_DISABLED);
  radio.setAddressWidth(2);
  radio.setChannel(CHANNEL);
  radio.startListening();
}

const int num_reps = 100;  // Max 255

void loop(void) {

  // Clear measurement values
  values = 0;
  valuesR = 0;

  // Scan channel num_reps times
  int rep_counter = num_reps;
  while (rep_counter--) {

    if (radio.testCarrier(MIN_DBM)) {
      ++values;
    }
    delayMicroseconds(256);

#if defined USE_RX
    if (radio.available()) {
      radio.read(0, 0);
      valuesR++;
    }
#endif
    delayMicroseconds(256);
  }

  // Print out channel measurements
  Serial.print("Low:");
  Serial.println(15);
  Serial.print("Med:");
  Serial.println(25);
  Serial.print("High:");
  Serial.println(35);
  Serial.print("Values:");
  Serial.println(values);
  if (values >= 15 && values < 25) {
    green();
  } else if (values >= 25 && values < 35) {
    red();
  } else if (values >= 35) {
    orange();
  } else {
    blue();
  }
#if defined USE_RX
  Serial.print("RX:");
  if (valuesR) {
    Serial.println(valuesR);
  } else {
    Serial.println(0);
  }
#endif
}

Tuesday

RF24Mesh and RF24Network Enhancements

 RF24Mesh and RF24Network Enhancements

Libraries updated with better functionality

So we've been putting in a bunch of work lately on the RF24/NRF52x communication stack for Arduino, and surprisingly, given the age of the libraries, we were able to make a number of changes that significantly impact the performance of the network and mesh.

RF24Mesh:

1. Utilize all poll requests. 

The prior behavior of the mesh was to send out a poll request via multicast and gather the responses. Then the mesh layer would attempt to request an address via one of the nodes that responded to the poll. If this failed however, the node would continue on and send out another poll. The current behavior now utilizes up to 4 received poll responses and loops through them all until either failure or a successful address request is made before moving to the next multicast level and sending out another poll request.

2. Enhance the ability to verify connectivity

The prior behavior of the mesh was to call `getAddress(_nodeID);` and verify its own address with the master node. The call would fail if anything but a successful address response was received. Now there is some logic added to return immediately if the address is not found in the master list or is default. It will also return immediately if the nodes address has been zeroed out. Retries will take place if the request failed or timed out. Finally, the node actually verifies that the received address matches its own address.

Update: I am currently testing a new method of connection checking, where each node only contacts their parent node instead of the master node. This appears to reduce traffic, increase connection times, and improve the overall stability of the mesh.

It may not seem like much, but the changes should tend to reduce network traffic, while providing more seamless mesh operation.

RF24Network:

1. Fix error sending data

Per the RF24 documentation and behavior, when using some of the advanced write functions, there is a need to call `radio.txStandby()` if a write fails, otherwise the radio will essentially hang and all subsequent writes will fail. This was partially missed in RF24Network, so a call has been added when an auto-ack payload fails. This should improve reliability and consistency in sending data.

RF24:

1. Interrupt enhancements. 

The use of interrupts on Linux platforms like the Raspberry Pi has been greatly improved and no longer requires root access to operate. Unlike the RF24 library, the interrupt functionality uses GPIO pin numbers instead of BCM pin numbers. ie: Use GPIO 24 instead of pin 18.

RF24Ethernet

1. Fix re-transmit mechanism

The associated UIP IP stack incorporated with RF24Ethernet uses a retransmit mechanism when acks are not received etc, but it was not working. This is now fixed and results in much more reliable, longer connectivity with MQTT, HTTP and other protocols & applications that transmit data.


All in all its been a good year for the RF24/NRF52x communication stack, with support also recently added for Nordics NRF52x SOCs, there are so many potential ways these libraries can be configured! Encryption and authentication features are also available with the newer radio modules, which will easily handle audio streaming and more advanced functionality.

AutoAnalogAudio Library - nRF52 Now supports Successive Approximation Analog-to-Digital Converter for Audio Input

 AutoAnalogAudio Library - nRF52 Now supports SAADC Support for Successive Approximation Analog-to-Digital Converter for Audio Input I'v...