diff --git a/examples_uno_q/rf24_encoderadiodetails/README.md b/examples_uno_q/rf24_encoderadiodetails/README.md new file mode 100644 index 00000000..5d22d646 --- /dev/null +++ b/examples_uno_q/rf24_encoderadiodetails/README.md @@ -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 . \ No newline at end of file diff --git a/examples_uno_q/rf24_encoderadiodetails/app.yaml b/examples_uno_q/rf24_encoderadiodetails/app.yaml new file mode 100644 index 00000000..c75587f2 --- /dev/null +++ b/examples_uno_q/rf24_encoderadiodetails/app.yaml @@ -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: [] diff --git a/examples_uno_q/rf24_encoderadiodetails/python/main.py b/examples_uno_q/rf24_encoderadiodetails/python/main.py new file mode 100644 index 00000000..d0eb9e77 --- /dev/null +++ b/examples_uno_q/rf24_encoderadiodetails/python/main.py @@ -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) diff --git a/examples_uno_q/rf24_encoderadiodetails/sketch/sketch.ino b/examples_uno_q/rf24_encoderadiodetails/sketch/sketch.ino new file mode 100644 index 00000000..470dc1d3 --- /dev/null +++ b/examples_uno_q/rf24_encoderadiodetails/sketch/sketch.ino @@ -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 +#include +#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() +} diff --git a/examples_uno_q/rf24_encoderadiodetails/sketch/sketch.yaml b/examples_uno_q/rf24_encoderadiodetails/sketch/sketch.yaml new file mode 100644 index 00000000..875c826e --- /dev/null +++ b/examples_uno_q/rf24_encoderadiodetails/sketch/sketch.yaml @@ -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