Skip to content

Commit 5b209c5

Browse files
TMRh202bndy5
andauthored
Arduino Uno Q Preliminary Example (#1054)
* Preliminary example for Arduino Q * Add link to additional examples Co-authored-by: Brendan <2bndy5@gmail.com>
1 parent 74b300d commit 5b209c5

File tree

5 files changed

+367
-0
lines changed

5 files changed

+367
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# 😀 RF24_EncodeRadioDetails
2+
3+
### Description
4+
5+
An example demonstrating how to get and display debug information from nRF24L01 radios on the Arduino Uno Q using both Arduino & Python
6+
7+
8+
### Additional RF24 Examples
9+
10+
See other examples at <https://github.com/TMRh20/Sketches/tree/master/ArduinoQ>.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# app.yaml: The main configuration file for your Arduino App.
2+
# This file describes the application's metadata and properties.
3+
4+
# The user-visible name of the application.
5+
name: RF24_EncodeRadioDetails
6+
7+
# A brief description of what the application does.
8+
description: ""
9+
10+
# The icon for the application, can be an emoji or a short string.
11+
icon: 😀
12+
13+
# A list of network ports that the application exposes.
14+
# Example: [80, 443]
15+
ports: []
16+
17+
# A list of bricks used by this application.
18+
bricks: []
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
"""A simple script to take all data dumped from the nRF24L01 registers and
2+
output it in human readable form.
3+
4+
Notes:
5+
* The radio's power state is represented under the assumption that
6+
the radio's CE pin is inactive low.
7+
"""
8+
9+
# pylint: disable=consider-using-f-string
10+
import struct
11+
import time
12+
13+
from arduino.app_utils import App, Bridge
14+
15+
bufferByteArray = bytearray()
16+
17+
18+
def RF24Callback(payload: int):
19+
"""Append a ``payload`` byte to the global ``bufferByteArray``.
20+
Invokes `print_details()` once the buffer hits a 43 byte length.
21+
22+
Args:
23+
payload: The incoming byte (a ``uint8_t`` data type from the
24+
microcontroller) to append.
25+
"""
26+
bufferByteArray.append(payload)
27+
if len(bufferByteArray) == 43:
28+
# once sufficient size warrants call to print_details()
29+
print_details(bufferByteArray)
30+
# reset bytearray buffer
31+
bufferByteArray.clear()
32+
33+
34+
Bridge.provide("RF24Callback", RF24Callback)
35+
36+
37+
def address_repr(buf, reverse: bool = True, delimit: str = "") -> str:
38+
"""Convert a buffer into a hexadecimal string."""
39+
order = range(len(buf) - 1, -1, -1) if reverse else range(len(buf))
40+
return delimit.join(["%02X" % buf[byte] for byte in order])
41+
42+
43+
# pylint: disable=too-many-locals,too-many-statements
44+
def print_details(encoded_buf: bytearray):
45+
"""This debugging function outputs all details about the nRF24L01."""
46+
# declare sequences
47+
pipes = [bytearray(5)] * 2 + [0] * 4
48+
pl_len = [0] * 6
49+
50+
# unpack bytearray
51+
(
52+
config, # 0x00
53+
auto_ack, # 0x01
54+
open_pipes, # 0x02
55+
addr_len, # 0x03
56+
retry_setup, # 0x04
57+
channel, # 0x05
58+
rf_setup, # 0x06
59+
status, # 0x07
60+
observer, # 0x08
61+
rpd, # 0x09
62+
) = struct.unpack("10B", encoded_buf[:10])
63+
pipes[0] = encoded_buf[10:15] # 0x0A
64+
pipes[1] = encoded_buf[15:20] # 0x0B
65+
(
66+
pipes[2], # 0x0C
67+
pipes[3], # 0x0D
68+
pipes[4], # 0x0E
69+
pipes[5], # 0x0F
70+
) = struct.unpack("4B", encoded_buf[20:24])
71+
tx_address = encoded_buf[24:29] # 0x10
72+
(
73+
pl_len[0], # 0x11
74+
pl_len[1], # 0x12
75+
pl_len[2], # 0x13
76+
pl_len[3], # 0x14
77+
pl_len[4], # 0x15
78+
pl_len[5], # 0x16
79+
fifo, # 0x17
80+
dyn_pl, # 0x1C
81+
features, # 0x1D
82+
) = struct.unpack("9B", encoded_buf[29:38])
83+
ce_pin, csn_pin, spi_speed = struct.unpack(">2H1B", encoded_buf[38:44])
84+
85+
# do some deciphering arithmetic
86+
addr_len += 2
87+
crc = (2 if config & 4 else 1) if auto_ack else max(0, ((config & 0x0C) >> 2) - 1)
88+
d_rate = rf_setup & 0x28
89+
d_rate = (2 if d_rate == 8 else 250) if d_rate else 1
90+
pa_level = (3 - ((rf_setup & 6) >> 1)) * -6
91+
pa_level = (
92+
"MIN"
93+
if pa_level == -18
94+
else ("LOW" if pa_level == -12 else ("HIGH" if pa_level == -6 else "MAX"))
95+
)
96+
dyn_p = (
97+
("_Enabled" if dyn_pl else "Disabled")
98+
if dyn_pl == 0x3F or not dyn_pl
99+
else "0b" + "0" * (8 - len(bin(dyn_pl))) + bin(dyn_pl)[2:]
100+
)
101+
auto_ack = (
102+
("Enabled" if auto_ack else "Disabled")
103+
if auto_ack == 0x3F or not auto_ack
104+
else "0b" + "0" * (8 - len(bin(auto_ack))) + bin(auto_ack)[2:]
105+
)
106+
pwr = "Standby" if config & 2 else "Off"
107+
is_plus_variant = bool(spi_speed >> 4)
108+
spi_speed = spi_speed & 0xF
109+
110+
# print it all out
111+
print("CE pin____________________{}".format(ce_pin))
112+
print("CSN pin___________________{}".format(csn_pin))
113+
print("SPI speed_________________{} MHz".format(spi_speed))
114+
print("Is a plus variant_________{}".format(is_plus_variant))
115+
print(
116+
"Channel___________________{}".format(channel),
117+
"~ {} GHz".format((channel + 2400) / 1000),
118+
)
119+
print(
120+
"RF Data Rate______________{}".format(d_rate),
121+
"Mbps" if d_rate != 250 else "Kbps",
122+
)
123+
print("RF Power Amplifier________PA_{}".format(pa_level))
124+
print(
125+
"RF Low Noise Amplifier____{}abled".format(
126+
"En" if bool(rf_setup & 1) else "Dis"
127+
)
128+
)
129+
print("CRC Length________________{} bits".format(crc * 8))
130+
print("Address length____________{} bytes".format(addr_len))
131+
print("TX Payload lengths________{} bytes".format(pl_len[0]))
132+
print(
133+
"Auto retry delay__________{} microseconds".format(
134+
((retry_setup & 0xF0) >> 4) * 250 + 250
135+
)
136+
)
137+
print("Auto retry attempts_______{} maximum".format(retry_setup & 0x0F))
138+
print("Re-use TX FIFO____________{}".format(bool(fifo & 64)))
139+
print("Received Power Detected___{}".format(bool(rpd)))
140+
print(
141+
"Packets lost on current channel_____________________{}".format(observer >> 4)
142+
)
143+
print(
144+
"Retry attempts made for last transmission___________{}".format(observer & 0xF)
145+
)
146+
print(
147+
"IRQ on Data Ready__{}abled".format("Dis" if config & 64 else "_En"),
148+
" Data Ready___________{}".format(bool(status & 0x40)),
149+
)
150+
print(
151+
"IRQ on Data Sent___{}abled".format("Dis" if config & 32 else "_En"),
152+
" Data Sent____________{}".format(bool(status & 0x20)),
153+
)
154+
print(
155+
"IRQ on Data Fail___{}abled".format("Dis" if config & 16 else "_En"),
156+
" Data Failed__________{}".format(bool(status & 0x10)),
157+
)
158+
print(
159+
"TX FIFO full__________{}e".format("_Tru" if fifo & 0x20 else "Fals"),
160+
" TX FIFO empty________{}".format(bool(fifo & 0x10)),
161+
)
162+
print(
163+
"RX FIFO full__________{}e".format("_Tru" if fifo & 2 else "Fals"),
164+
" RX FIFO empty________{}".format(bool(fifo & 1)),
165+
)
166+
print(
167+
"Multicast__________{}ed Custom ACK Payload___{}abled".format(
168+
"_Allow" if features & 1 else "Disabl",
169+
"En" if features & 2 else "Dis",
170+
),
171+
)
172+
print("Dynamic Payloads___{} Auto Acknowledgment__{}".format(dyn_p, auto_ack))
173+
print(
174+
"Primary Mode_____________{}X".format("R" if config & 1 else "T"),
175+
" Power Mode___________{}".format(pwr),
176+
)
177+
print("TX address____________ 0x{}".format(address_repr(tx_address)))
178+
for i in range(6):
179+
is_open = open_pipes & (1 << i)
180+
address = pipes[i] if i < 2 else bytes([pipes[i]]) + pipes[1][1:]
181+
print(
182+
"Pipe {} ({}) bound: 0x{}".format(
183+
i, " open " if is_open else "closed", address_repr(address)
184+
),
185+
)
186+
if is_open and not dyn_pl & (1 << i):
187+
print("\t\texpecting {} byte static payloads".format(pl_len[i]))
188+
189+
190+
# pylint: enable=too-many-locals,too-many-statements
191+
192+
193+
def loop():
194+
"""This function is called repeatedly by the App framework."""
195+
# You can replace this with any code you want your App to run repeatedly.
196+
time.sleep(10)
197+
198+
199+
# See: https://docs.arduino.cc/software/app-lab/tutorials/getting-started/#app-run
200+
App.run(user_loop=loop)
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
See documentation at https://nRF24.github.io/RF24
3+
See License information at root directory of this library
4+
Authors: Brendan Doherty (2bndy5), Douglas Quigg (dstroy0)
5+
*/
6+
7+
/**
8+
A simple example of getting debug info from the nRF24L01 transceiver on the Arduino Q.
9+
10+
This example was written to demonstrate alternative methods to get debugging data.
11+
1. radio.encodeRadioDetails() will provide a data dump of all the nRF24L01's registers.
12+
2. radio.sprintfPrettyDetails() will behave similarly to printPrettyDetails(), but it
13+
outputs to a char buffer that can be printed to any Monitor (or other output) stream.
14+
15+
Additionally, this example will show all default configuration values.
16+
*/
17+
#include <Arduino_RouterBridge.h>
18+
#include <SPI.h>
19+
#include "RF24.h"
20+
21+
#define CE_PIN 7
22+
#define CSN_PIN 8
23+
// instantiate an object for the nRF24L01 transceiver
24+
RF24 radio(CE_PIN, CSN_PIN);
25+
26+
/*
27+
For this example, we'll be using a data buffer containing
28+
radio details encoded with RF24::encodeRadioDetails().
29+
It is meant to be decoded by an external program.
30+
31+
There is a python script located in this example's folder that
32+
will take a space-delimited string of hexadecimal characters and
33+
decode then print it out as human readable information.
34+
*/
35+
uint8_t encoded_details[43] = {0};
36+
37+
// Use this function to print out the encoded_details as a
38+
// space-delimited string of hexadecimal characters.
39+
void dumpRegData()
40+
{
41+
for (uint8_t i = 0; i < 43; ++i) {
42+
Monitor.print(encoded_details[i], HEX);
43+
if (i < 42)
44+
Monitor.print(F(" "));
45+
}
46+
}
47+
48+
void setup()
49+
{
50+
Bridge.begin();
51+
Monitor.begin();
52+
delay(3000);
53+
54+
// initialize the transceiver on the SPI bus
55+
if (!radio.begin()) {
56+
Monitor.println(F("radio hardware is not responding!!"));
57+
while (1) {
58+
} // hold in infinite loop
59+
}
60+
61+
// print example's introductory prompt
62+
Monitor.println(F("RF24/examples/encodedRadioDetails"));
63+
64+
Monitor.println(F("Press any key to show debugging information"));
65+
while (!Monitor.available()) {
66+
// wait for user input
67+
}
68+
69+
// For debugging info
70+
char* debug_info = new char[870];
71+
uint16_t str_len = radio.sprintfPrettyDetails(debug_info);
72+
Monitor.println(debug_info);
73+
Monitor.print(F("\nThe above output used "));
74+
Monitor.print(str_len);
75+
Monitor.println(F(" characters."));
76+
77+
// encoded_details is NOT human readable.
78+
// encodeRadioDetails() is very small when used on its own because it puts debugging information into a byte array
79+
// No printf() support needed because it doesn't use an output stream.
80+
radio.encodeRadioDetails(encoded_details);
81+
Monitor.println(F("\nhexadecimal dump of all registers:"));
82+
for (int i = 0; i < 43; i++) {
83+
Bridge.call("RF24Callback", encoded_details[i]);
84+
}
85+
86+
Monitor.println(F("\n\nThis string of hexadecimal characters (including spaces)."));
87+
Monitor.print(F("will be transferred to the MPU via the Arduino Q bridge API: "));
88+
dumpRegData();
89+
} // setup
90+
91+
/* Registers corresponding to index of encoded_details array
92+
0: NRF_CONFIG
93+
1: EN_AA
94+
2: EN_RXADDR
95+
3: SETUP_AW
96+
4: SETUP_RETR
97+
5: RF_CH
98+
6: RF_SETUP
99+
7: NRF_STATUS
100+
8: OBSERVE_TX
101+
9: CD (aka RPD)
102+
10-14: RX_ADDR_P0
103+
15-19: RX_ADDR_P1
104+
20: RX_ADDR_P2
105+
21: RX_ADDR_P3
106+
22: RX_ADDR_P4
107+
23: RX_ADDR_P5
108+
24-28: TX_ADDR
109+
29: RX_PW_P0
110+
30: RX_PW_P1
111+
31: RX_PW_P2
112+
32: RX_PW_P3
113+
33: RX_PW_P4
114+
34: RX_PW_P5
115+
35: FIFO_STATUS
116+
36: DYNPD
117+
37: FEATURE
118+
38-39: ce_pin
119+
40-41: csn_pin
120+
42: SPI speed MHz | (isPlusVariant << 4)
121+
*/
122+
123+
void loop()
124+
{
125+
// Nothing to do here. We did it all at the end of setup()
126+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
profiles:
2+
default:
3+
fqbn: arduino:zephyr:unoq
4+
platforms:
5+
- platform: arduino:zephyr
6+
libraries:
7+
- MsgPack (0.4.2)
8+
- DebugLog (0.8.4)
9+
- ArxContainer (0.7.0)
10+
- ArxTypeTraits (0.3.1)
11+
- RF24 (1.5.0)
12+
13+
default_profile: default

0 commit comments

Comments
 (0)