Skip to content
10 changes: 10 additions & 0 deletions examples_uno_q/rf24_encoderadiodetails/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# 😀 RF24_EncodeRadioDetails

### Description

An example demonstrating how to get and display debug information from nRF24L01 radios on the Arduino Uno Q using both Arduino & Python


### Additional RF24 Examples

See other examples at <https://github.com/TMRh20/Sketches/tree/master/ArduinoQ>.
18 changes: 18 additions & 0 deletions examples_uno_q/rf24_encoderadiodetails/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# app.yaml: The main configuration file for your Arduino App.
# This file describes the application's metadata and properties.

# The user-visible name of the application.
name: RF24_EncodeRadioDetails

# A brief description of what the application does.
description: ""

# The icon for the application, can be an emoji or a short string.
icon: 😀

# A list of network ports that the application exposes.
# Example: [80, 443]
ports: []

# A list of bricks used by this application.
bricks: []
200 changes: 200 additions & 0 deletions examples_uno_q/rf24_encoderadiodetails/python/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
"""A simple script to take all data dumped from the nRF24L01 registers and
output it in human readable form.

Notes:
* The radio's power state is represented under the assumption that
the radio's CE pin is inactive low.
"""

# pylint: disable=consider-using-f-string
import struct
import time

from arduino.app_utils import App, Bridge

bufferByteArray = bytearray()


def RF24Callback(payload: int):
"""Append a ``payload`` byte to the global ``bufferByteArray``.
Invokes `print_details()` once the buffer hits a 43 byte length.

Args:
payload: The incoming byte (a ``uint8_t`` data type from the
microcontroller) to append.
"""
bufferByteArray.append(payload)
if len(bufferByteArray) == 43:
# once sufficient size warrants call to print_details()
print_details(bufferByteArray)
# reset bytearray buffer
bufferByteArray.clear()


Bridge.provide("RF24Callback", RF24Callback)


def address_repr(buf, reverse: bool = True, delimit: str = "") -> str:
"""Convert a buffer into a hexadecimal string."""
order = range(len(buf) - 1, -1, -1) if reverse else range(len(buf))
return delimit.join(["%02X" % buf[byte] for byte in order])


# pylint: disable=too-many-locals,too-many-statements
def print_details(encoded_buf: bytearray):
"""This debugging function outputs all details about the nRF24L01."""
# declare sequences
pipes = [bytearray(5)] * 2 + [0] * 4
pl_len = [0] * 6

# unpack bytearray
(
config, # 0x00
auto_ack, # 0x01
open_pipes, # 0x02
addr_len, # 0x03
retry_setup, # 0x04
channel, # 0x05
rf_setup, # 0x06
status, # 0x07
observer, # 0x08
rpd, # 0x09
) = struct.unpack("10B", encoded_buf[:10])
pipes[0] = encoded_buf[10:15] # 0x0A
pipes[1] = encoded_buf[15:20] # 0x0B
(
pipes[2], # 0x0C
pipes[3], # 0x0D
pipes[4], # 0x0E
pipes[5], # 0x0F
) = struct.unpack("4B", encoded_buf[20:24])
tx_address = encoded_buf[24:29] # 0x10
(
pl_len[0], # 0x11
pl_len[1], # 0x12
pl_len[2], # 0x13
pl_len[3], # 0x14
pl_len[4], # 0x15
pl_len[5], # 0x16
fifo, # 0x17
dyn_pl, # 0x1C
features, # 0x1D
) = struct.unpack("9B", encoded_buf[29:38])
ce_pin, csn_pin, spi_speed = struct.unpack(">2H1B", encoded_buf[38:44])

# do some deciphering arithmetic
addr_len += 2
crc = (2 if config & 4 else 1) if auto_ack else max(0, ((config & 0x0C) >> 2) - 1)
d_rate = rf_setup & 0x28
d_rate = (2 if d_rate == 8 else 250) if d_rate else 1
pa_level = (3 - ((rf_setup & 6) >> 1)) * -6
pa_level = (
"MIN"
if pa_level == -18
else ("LOW" if pa_level == -12 else ("HIGH" if pa_level == -6 else "MAX"))
)
dyn_p = (
("_Enabled" if dyn_pl else "Disabled")
if dyn_pl == 0x3F or not dyn_pl
else "0b" + "0" * (8 - len(bin(dyn_pl))) + bin(dyn_pl)[2:]
)
auto_ack = (
("Enabled" if auto_ack else "Disabled")
if auto_ack == 0x3F or not auto_ack
else "0b" + "0" * (8 - len(bin(auto_ack))) + bin(auto_ack)[2:]
)
pwr = "Standby" if config & 2 else "Off"
is_plus_variant = bool(spi_speed >> 4)
spi_speed = spi_speed & 0xF

# print it all out
print("CE pin____________________{}".format(ce_pin))
print("CSN pin___________________{}".format(csn_pin))
print("SPI speed_________________{} MHz".format(spi_speed))
print("Is a plus variant_________{}".format(is_plus_variant))
print(
"Channel___________________{}".format(channel),
"~ {} GHz".format((channel + 2400) / 1000),
)
print(
"RF Data Rate______________{}".format(d_rate),
"Mbps" if d_rate != 250 else "Kbps",
)
print("RF Power Amplifier________PA_{}".format(pa_level))
print(
"RF Low Noise Amplifier____{}abled".format(
"En" if bool(rf_setup & 1) else "Dis"
)
)
print("CRC Length________________{} bits".format(crc * 8))
print("Address length____________{} bytes".format(addr_len))
print("TX Payload lengths________{} bytes".format(pl_len[0]))
print(
"Auto retry delay__________{} microseconds".format(
((retry_setup & 0xF0) >> 4) * 250 + 250
)
)
print("Auto retry attempts_______{} maximum".format(retry_setup & 0x0F))
print("Re-use TX FIFO____________{}".format(bool(fifo & 64)))
print("Received Power Detected___{}".format(bool(rpd)))
print(
"Packets lost on current channel_____________________{}".format(observer >> 4)
)
print(
"Retry attempts made for last transmission___________{}".format(observer & 0xF)
)
print(
"IRQ on Data Ready__{}abled".format("Dis" if config & 64 else "_En"),
" Data Ready___________{}".format(bool(status & 0x40)),
)
print(
"IRQ on Data Sent___{}abled".format("Dis" if config & 32 else "_En"),
" Data Sent____________{}".format(bool(status & 0x20)),
)
print(
"IRQ on Data Fail___{}abled".format("Dis" if config & 16 else "_En"),
" Data Failed__________{}".format(bool(status & 0x10)),
)
print(
"TX FIFO full__________{}e".format("_Tru" if fifo & 0x20 else "Fals"),
" TX FIFO empty________{}".format(bool(fifo & 0x10)),
)
print(
"RX FIFO full__________{}e".format("_Tru" if fifo & 2 else "Fals"),
" RX FIFO empty________{}".format(bool(fifo & 1)),
)
print(
"Multicast__________{}ed Custom ACK Payload___{}abled".format(
"_Allow" if features & 1 else "Disabl",
"En" if features & 2 else "Dis",
),
)
print("Dynamic Payloads___{} Auto Acknowledgment__{}".format(dyn_p, auto_ack))
print(
"Primary Mode_____________{}X".format("R" if config & 1 else "T"),
" Power Mode___________{}".format(pwr),
)
print("TX address____________ 0x{}".format(address_repr(tx_address)))
for i in range(6):
is_open = open_pipes & (1 << i)
address = pipes[i] if i < 2 else bytes([pipes[i]]) + pipes[1][1:]
print(
"Pipe {} ({}) bound: 0x{}".format(
i, " open " if is_open else "closed", address_repr(address)
),
)
if is_open and not dyn_pl & (1 << i):
print("\t\texpecting {} byte static payloads".format(pl_len[i]))


# pylint: enable=too-many-locals,too-many-statements


def loop():
"""This function is called repeatedly by the App framework."""
# You can replace this with any code you want your App to run repeatedly.
time.sleep(10)


# See: https://docs.arduino.cc/software/app-lab/tutorials/getting-started/#app-run
App.run(user_loop=loop)
126 changes: 126 additions & 0 deletions examples_uno_q/rf24_encoderadiodetails/sketch/sketch.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
See documentation at https://nRF24.github.io/RF24
See License information at root directory of this library
Authors: Brendan Doherty (2bndy5), Douglas Quigg (dstroy0)
*/

/**
A simple example of getting debug info from the nRF24L01 transceiver on the Arduino Q.

This example was written to demonstrate alternative methods to get debugging data.
1. radio.encodeRadioDetails() will provide a data dump of all the nRF24L01's registers.
2. radio.sprintfPrettyDetails() will behave similarly to printPrettyDetails(), but it
outputs to a char buffer that can be printed to any Monitor (or other output) stream.

Additionally, this example will show all default configuration values.
*/
#include <Arduino_RouterBridge.h>
#include <SPI.h>
#include "RF24.h"

#define CE_PIN 7
#define CSN_PIN 8
// instantiate an object for the nRF24L01 transceiver
RF24 radio(CE_PIN, CSN_PIN);

/*
For this example, we'll be using a data buffer containing
radio details encoded with RF24::encodeRadioDetails().
It is meant to be decoded by an external program.

There is a python script located in this example's folder that
will take a space-delimited string of hexadecimal characters and
decode then print it out as human readable information.
*/
uint8_t encoded_details[43] = {0};

// Use this function to print out the encoded_details as a
// space-delimited string of hexadecimal characters.
void dumpRegData()
{
for (uint8_t i = 0; i < 43; ++i) {
Monitor.print(encoded_details[i], HEX);
if (i < 42)
Monitor.print(F(" "));
}
}

void setup()
{
Bridge.begin();
Monitor.begin();
delay(3000);

// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Monitor.println(F("radio hardware is not responding!!"));
while (1) {
} // hold in infinite loop
}

// print example's introductory prompt
Monitor.println(F("RF24/examples/encodedRadioDetails"));

Monitor.println(F("Press any key to show debugging information"));
while (!Monitor.available()) {
// wait for user input
}

// For debugging info
char* debug_info = new char[870];
uint16_t str_len = radio.sprintfPrettyDetails(debug_info);
Monitor.println(debug_info);
Monitor.print(F("\nThe above output used "));
Monitor.print(str_len);
Monitor.println(F(" characters."));

// encoded_details is NOT human readable.
// encodeRadioDetails() is very small when used on its own because it puts debugging information into a byte array
// No printf() support needed because it doesn't use an output stream.
radio.encodeRadioDetails(encoded_details);
Monitor.println(F("\nhexadecimal dump of all registers:"));
for (int i = 0; i < 43; i++) {
Bridge.call("RF24Callback", encoded_details[i]);
}

Monitor.println(F("\n\nThis string of hexadecimal characters (including spaces)."));
Monitor.print(F("will be transferred to the MPU via the Arduino Q bridge API: "));
dumpRegData();
} // setup

/* Registers corresponding to index of encoded_details array
0: NRF_CONFIG
1: EN_AA
2: EN_RXADDR
3: SETUP_AW
4: SETUP_RETR
5: RF_CH
6: RF_SETUP
7: NRF_STATUS
8: OBSERVE_TX
9: CD (aka RPD)
10-14: RX_ADDR_P0
15-19: RX_ADDR_P1
20: RX_ADDR_P2
21: RX_ADDR_P3
22: RX_ADDR_P4
23: RX_ADDR_P5
24-28: TX_ADDR
29: RX_PW_P0
30: RX_PW_P1
31: RX_PW_P2
32: RX_PW_P3
33: RX_PW_P4
34: RX_PW_P5
35: FIFO_STATUS
36: DYNPD
37: FEATURE
38-39: ce_pin
40-41: csn_pin
42: SPI speed MHz | (isPlusVariant << 4)
*/

void loop()
{
// Nothing to do here. We did it all at the end of setup()
}
13 changes: 13 additions & 0 deletions examples_uno_q/rf24_encoderadiodetails/sketch/sketch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
profiles:
default:
fqbn: arduino:zephyr:unoq
platforms:
- platform: arduino:zephyr
libraries:
- MsgPack (0.4.2)
- DebugLog (0.8.4)
- ArxContainer (0.7.0)
- ArxTypeTraits (0.3.1)
- RF24 (1.5.0)

default_profile: default