From 7441eefbfb9c2750649d76de70b1d80fec013c66 Mon Sep 17 00:00:00 2001
From: Brendan <2bndy5@gmail.com>
Date: Tue, 26 Mar 2024 11:49:58 -0700
Subject: [PATCH] update python wrapper/examples/doc (#967)
- expose selected `RF24_DRIVER` in the python wrapper (for programmatically specifying the right pins)
- update for the python examples
- interrupt_configure.py usees gpiod instead of RPi.GPIO
- removed argparse from examples for simplicity
- use the appropriate pin numbers for the selected `RF24_DRIVER`
- revised the python wrapper's install doc
---
.github/workflows/doxygen.yml | 1 +
docs/Doxyfile | 13 +-
docs/doxygen-custom.css | 104 ++++++
docs/python_wrapper.md | 82 +++--
examples_linux/acknowledgementPayloads.cpp | 2 +-
examples_linux/acknowledgement_payloads.py | 136 +++-----
examples_linux/getting_started.py | 138 +++-----
examples_linux/gettingstarted.cpp | 2 +-
examples_linux/interruptConfigure.cpp | 2 +-
examples_linux/interrupt_configure.py | 320 ++++++++----------
.../interrupts/transfer_interrupt.cpp | 2 +-
examples_linux/manualAcknowledgements.cpp | 2 +-
examples_linux/manual_acknowledgements.py | 135 +++-----
examples_linux/multiceiverDemo.cpp | 2 +-
examples_linux/multiceiver_demo.py | 99 +++---
examples_linux/ncurses/scanner_curses.cpp | 2 +-
examples_linux/scanner.cpp | 2 +-
examples_linux/scanner.py | 14 +-
examples_linux/streamingData.cpp | 2 +-
examples_linux/streaming_data.py | 138 +++-----
pyRF24/pyRF24.cpp | 13 +
21 files changed, 603 insertions(+), 608 deletions(-)
diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml
index 7824d83c5..86b695d11 100644
--- a/.github/workflows/doxygen.yml
+++ b/.github/workflows/doxygen.yml
@@ -40,4 +40,5 @@ jobs:
uses: nRF24/.github/.github/workflows/build_docs.yaml@main
with:
deploy-gh-pages: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master') }}
+ doxygen-version: '1.10.0'
secrets: inherit
diff --git a/docs/Doxyfile b/docs/Doxyfile
index d5015a11d..de8a00450 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -332,14 +332,15 @@ HTML_EXTRA_STYLESHEET = doxygen-custom.css
HTML_COLORSTYLE = TOGGLE
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to YES can help to show when doxygen was last run and thus if the
-# documentation is up to date.
+# If the TIMESTAMP tag is set different from NO then each generated page will contain
+# the date or date and time when the page was generated. Setting this to NO can help
+# when comparing the output of multiple runs.
+#
+# Possible values are: YES, NO, DATETIME and DATE.
+#
# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_TIMESTAMP = YES
+TIMESTAMP = DATE
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
diff --git a/docs/doxygen-custom.css b/docs/doxygen-custom.css
index 7d56191d7..2b5ef5a1b 100644
--- a/docs/doxygen-custom.css
+++ b/docs/doxygen-custom.css
@@ -1,3 +1,107 @@
table.markdownTable th {
color: unset;
}
+
+/* overrides from default CSSS for some admonitions */
+dl.note, dl.remark,
+dl.warning, dl.attention {
+ color: unset;
+}
+dl.remark {
+ background: var(--remark-color-bg);
+ border-left: 8px solid var(--remark-color-hl);
+}
+dl.remark dt {
+ color: var(--remark-color-hl);
+}
+
+/* special rules to accent `/see` or `/sa` command output */
+dl.see {
+ background: var(--seealso-color-bg);
+ border-left: 8px solid var(--seealso-color-hl);
+}
+dl.see dt {
+ color: var(--seealso-color-hl);
+}
+dl.see {
+ padding: 10px;
+ margin: 10px 0px;
+ overflow: hidden;
+ margin-left: 0;
+ border-radius: 4px;
+}
+
+/* admonition icons */
+dl.note dt::before {
+ background-color: var(--note-color-hl);
+ mask-image: var(--note-icon);
+}
+dl.see dt::before {
+ background-color: var(--seealso-color-hl);
+ mask-image: var(--seealso-icon);
+}
+dl.remark dt::before {
+ background-color: var(--remark-color-hl);
+ mask-image: var(--remark-icon);
+}
+dl.warning dt::before {
+ background-color: var(--warning-color-hl);
+ mask-image: var(--warning-icon);
+}
+dl.deprecated dt::before {
+ background-color: var(--deprecated-color-hl);
+ mask-image: var(--deprecated-icon);
+}
+dl.note dt::before,
+dl.see dt::before,
+dl.warning dt::before,
+dl.remark dt::before,
+dl.deprecated dt::before {
+ vertical-align: middle;
+ background-repeat: no-repeat;
+ content: "";
+ display: inline-block;
+ height: 2em;
+ width: 2em;
+ margin-right: 0.25rem;
+}
+dl.note dt,
+dl.see dt,
+dl.warning dt,
+dl.remark dt,
+dl.deprecated dt {
+ margin-top: -0.35em;
+ margin-bottom: 0.5em;
+}
+
+/* icon SVG data */
+*:root {
+ --note-icon: url('data:image/svg+xml;utf8,');
+ --seealso-icon: url('data:image/svg+xml;utf8,');
+ --warning-icon: url('data:image/svg+xml;utf8,');
+ --remark-icon: url('data:image/svg+xml;utf8,');
+ --deprecated-icon: url('data:image/svg+xml;utf8,');
+}
+
+/* color overrides */
+html {
+ /* light theme CSS variables */
+ --note-color-bg: hsla(47.6, 77.3%, 91.4%, 65%);
+ --warning-color-bg: hsla(6.8, 75.9%, 88.6%, 65%);
+ --deprecated-color-bg: hsla(205.7, 22.6%, 93.9%, 65%);
+ --seealso-color-bg: hsla(215, 76%, 89%, 65%);
+ --seealso-color-hl: hsl(215, 98%, 48%);
+ --remark-color-bg: hsla(133, 75%, 89%, 65%);
+ --remark-color-hl: hsl(133, 98.9%, 35.3%);
+}
+
+html.dark-mode {
+ /* dark theme CSS variables */
+ --note-color-bg: hsla(45.8, 87.3%, 12.4%, 65%);
+ --warning-color-bg: hsla(5.2, 33.3%, 13.5%, 65%);
+ --deprecated-color-bg: hsla(221.5, 12.4%, 20.6%, 65%);
+ --seealso-color-bg: hsla(215, 33%, 14%, 0.65);
+ --seealso-color-hl: hsl(215, 98%, 48%);
+ --remark-color-bg: hsla(133, 32%, 14%, 65%);
+ --remark-color-hl: hsl(133, 98%, 48%);
+}
\ No newline at end of file
diff --git a/docs/python_wrapper.md b/docs/python_wrapper.md
index 7bcadee74..60e73a42c 100644
--- a/docs/python_wrapper.md
+++ b/docs/python_wrapper.md
@@ -2,22 +2,41 @@
@tableofcontents
-
-By [mz-fuzzy](https://github.com/mz-fuzzy)
+@remark
+@parblock
+We recommend using the newer [pyRF24 package](https://github.com/nRF24/pyRF24)
+[available from pypi](https://pypi.org/project/pyrf24/) because
+
+1. it is [practically drop-in compatible](https://nrf24.github.io/pyRF24/#migrating-to-pyrf24)
+2. easier to install or get updates with popular package managers like pip
+3. does not require the C++ libraries to be installed -- it uses its own isolated binaries
+4. includes wrappers for RF24, RF24Network, RF24Mesh libraries
+5. includes a new [fake BLE implementation](https://nrf24.github.io/pyRF24/ble_api.html)
+6. has its own [dedicated documentation](https://nRF24.github.io/pyRF24)
+7. is compatible with python's builtin `help()`
+8. includes typing stub files for type checking tools like mypy
+
+The only reason that you should need to keep using these older individual python
+wrappers is if you must to use python v3.6 or older.
+
+You **cannot** use these individual wrappers in combination with the pyRF24 package.
+@endparblock
## Python Wrapper Prerequisites
-### RF24
+These instructions work for the RF24, RF24Network, and RF24Mesh libraries, but
+the C++ source code needs to be built and installed for the corresponding
+python wrapper(s) to work.
-The RF24 lib needs to be built in C++ & installed for the python wrapper to wrap it.
+@see Review [installing with CMake](md_docs_using_cmake.html) and [Linux/RPi General](md_docs_rpi_general.html).
-See [Linux Installation](md_docs_linux_install.html) (or [installing with CMake](md_docs_using_cmake.html)
-alternatively) and [Linux/RPi General](md_docs_rpi_general.html)
+@note The interrupt_configure.py example uses the
+[gpiod library](https://pypi.org/project/gpiod) to watch the radio's IRQ pin.
### Python2
```shell
-sudo apt-get install python-dev libboost-python-dev python-pip python-rpi.gpio
+sudo apt-get install python-dev libboost-python-dev python-pip
```
Next, install some up-to-date python packages.
@@ -29,7 +48,7 @@ python -m pip install --upgrade pip setuptools
### Python3
```shell
-sudo apt-get install python3-dev libboost-python-dev python3-pip python3-rpi.gpio
+sudo apt-get install python3-dev libboost-python-dev python3-pip
```
Next, install some up-to-date python3 packages.
@@ -40,7 +59,7 @@ python3 -m pip install --upgrade pip setuptools
## Installation
-@note Steps 2 and 3 have to be repeated if installing the python wrappers for
+@note Only step 2 has to be repeated if installing the python wrappers for
RF24Network and RF24Mesh libraries. The prerequisites stated above still apply
to each library.
@@ -48,9 +67,9 @@ to each library.
```shell
sudo ln -s $(ls /usr/lib/$(ls /usr/lib/gcc | tail -1)/libboost_python3*.so | tail -1) /usr/lib/$(ls /usr/lib/gcc | tail -1)/libboost_python3.so
```
-2. Build the library.
+2. Install the library.
- This step and the next step need to be executed from the appropriate directory of
+ This step needs to be executed from the appropriate directory of
the cloned RF24* repository:
- navigate to *pyRF24* directory in the RF24 cloned repository
- navigate to *RPi/pyRF24Network* directory in the RF24Network cloned repository
@@ -58,25 +77,20 @@ to each library.
When in the correct directory, run the following command:
```shell
- ./setup.py build
+ python setup.py install
```
or for python3
```shell
- python3 setup.py build
- ```
- @note Build takes several minutes on arm-based machines. Machines with RAM less than 1GB may need to increase amount of swap for build.
-3. Install the library
- ```shell
- sudo ./setup.py install
- ```
- or for python3
- ```shell
- sudo python3 setup.py install
+ python3 -m pip install -v .
```
+ @note Building/installing takes several minutes on arm-based machines.
+ Machines with RAM less than 1GB may need to increase amount of swap for build.
+ The `-v` option enables pip's verbose output to show that the process has not frozen.
+
See the additional [Platform Support pages](pages.html) for information on connecting your hardware.
See the included [\*.py files in the "examples_linux" folder](examples.html) for usage information.
-4. Running the Example
+3. Running the Example
The python examples location differ for each RF24* resopitories.
- navigate to *examples_linux* directory in the RF24 cloned repository
@@ -95,9 +109,27 @@ to each library.
Run the example
```shell
- sudo python getting_started.py
+ python getting_started.py
```
or for python3
```shell
- sudo python3 getting_started.py
+ python3 getting_started.py
```
+
+ @note
+ @parblock
+ Running the python wrappers built with 'pigpio' or 'RPi' drivers requires `sudo` permission.
+
+ If you are working in a python virtual environment (aka "venv"), then the
+ virtual environment's python executable must be specified after `sudo`. Otherwise,
+ `sudo` may invoke the system-installed python executable which can lead to errors.
+
+ Assuming the python virtual environment is located in `~/venv`, use the following command:
+ ```
+ sudo ~/venv/bin/python getting_started.py
+ ```
+ This `sudo` advice must be observed even while the virtual environment is activated.
+
+ See more information about python virtual environments in the
+ [python documentation](https://docs.python.org/3/library/venv.html).
+ @endparblock
diff --git a/examples_linux/acknowledgementPayloads.cpp b/examples_linux/acknowledgementPayloads.cpp
index 2138c19a0..1c784548a 100644
--- a/examples_linux/acknowledgementPayloads.cpp
+++ b/examples_linux/acknowledgementPayloads.cpp
@@ -36,7 +36,7 @@ using namespace std;
RF24 radio(CE_PIN, CSN_PIN);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// For this example, we'll be using a payload containing
diff --git a/examples_linux/acknowledgement_payloads.py b/examples_linux/acknowledgement_payloads.py
index b0afb3741..8a2bf9a8a 100644
--- a/examples_linux/acknowledgement_payloads.py
+++ b/examples_linux/acknowledgement_payloads.py
@@ -3,30 +3,14 @@
with Acknowledgement (ACK) payloads attached to ACK packets.
This example was written to be used on 2 devices acting as 'nodes'.
+
+See documentation at https://nRF24.github.io/RF24
"""
-import sys
-import argparse
-import time
-from RF24 import RF24, RF24_PA_LOW
+import time
+from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER
-parser = argparse.ArgumentParser(
- description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
-)
-parser.add_argument(
- "-n",
- "--node",
- type=int,
- choices=range(2),
- help="the identifying radio number (or node ID number)",
-)
-parser.add_argument(
- "-r",
- "--role",
- type=int,
- choices=range(2),
- help="'1' specifies the TX role. '0' specifies the RX role.",
-)
+print(__file__) # print example name
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
@@ -35,14 +19,50 @@
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev.
# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc..
-CSN_PIN = 0 # connected to GPIO8
-CE_PIN = 22 # connected to GPIO22
+CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
+if RF24_DRIVER == "MRAA":
+ CE_PIN = 15 # for GPIO22
+elif RF24_DRIVER == "wiringPi":
+ CE_PIN = 3 # for GPIO22
+else:
+ CE_PIN = 22
radio = RF24(CE_PIN, CSN_PIN)
-################## Linux (BBB,x86,etc) #########################
-# See http://nRF24.github.io/RF24/pages.html for more information on usage
-# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
-# See https://www.kernel.org/doc/Documentation/spi/spidev for more
-# information on SPIDEV
+
+# initialize the nRF24L01 on the spi bus
+if not radio.begin():
+ raise RuntimeError("radio hardware is not responding")
+
+# For this example, we will use different addresses
+# An address need to be a buffer protocol object (bytearray)
+address = [b"1Node", b"2Node"]
+# It is very helpful to think of an address as a path instead of as
+# an identifying device destination
+
+radio_number = bool(
+ int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
+)
+
+# ACK payloads are dynamically sized.
+radio.enableDynamicPayloads() # to use ACK payloads
+
+# to enable the custom ACK payload feature
+radio.enableAckPayload()
+
+# set the Power Amplifier level to -12 dBm since this test example is
+# usually run with nRF24L01 transceivers in close proximity of each other
+radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
+
+# set the TX address of the RX node into the TX pipe
+radio.openWritingPipe(address[radio_number]) # always uses pipe 0
+
+# set the RX address of the TX node into a RX pipe
+radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
+
+# for debugging, we have 2 options that print a large block of details
+# (smaller) function that prints raw register values
+# radio.printDetails()
+# (larger) function that prints human readable data
+# radio.printPrettyDetails()
# using the python keyword global is bad practice. Instead we'll use a
# 1 item list to store our integer number for the payloads' counter
@@ -166,63 +186,11 @@ def set_role() -> bool:
if __name__ == "__main__":
-
- args = parser.parse_args() # parse any CLI args
-
- # initialize the nRF24L01 on the spi bus
- if not radio.begin():
- raise RuntimeError("radio hardware is not responding")
-
- # For this example, we will use different addresses
- # An address need to be a buffer protocol object (bytearray)
- address = [b"1Node", b"2Node"]
- # It is very helpful to think of an address as a path instead of as
- # an identifying device destination
-
- print(sys.argv[0]) # print example name
-
- # to use different addresses on a pair of radios, we need a variable to
- # uniquely identify which address this radio will use to transmit
- # 0 uses address[0] to transmit, 1 uses address[1] to transmit
- radio_number = args.node # uses default value from `parser`
- if args.node is None: # if '--node' arg wasn't specified
- radio_number = bool(
- int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
- )
-
- # ACK payloads are dynamically sized.
- radio.enableDynamicPayloads() # to use ACK payloads
-
- # to enable the custom ACK payload feature
- radio.enableAckPayload()
-
- # set the Power Amplifier level to -12 dBm since this test example is
- # usually run with nRF24L01 transceivers in close proximity of each other
- radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
-
- # set the TX address of the RX node into the TX pipe
- radio.openWritingPipe(address[radio_number]) # always uses pipe 0
-
- # set the RX address of the TX node into a RX pipe
- radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
-
- # for debugging, we have 2 options that print a large block of details
- # (smaller) function that prints raw register values
- # radio.printDetails()
- # (larger) function that prints human readable data
- # radio.printPrettyDetails()
-
try:
- if args.role is None: # if not specified with CLI arg '-r'
- while set_role():
- pass # continue example until 'Q' is entered
- else: # if role was set using CLI args
- # run role once and exit
- if bool(args.role):
- master()
- else:
- slave()
+ while set_role():
+ pass # continue example until 'Q' is entered
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Exiting...")
radio.powerDown()
- sys.exit()
+else:
+ print(" Run slave() on receiver\n Run master() on transmitter")
diff --git a/examples_linux/getting_started.py b/examples_linux/getting_started.py
index 52199bbf8..6701b88d8 100644
--- a/examples_linux/getting_started.py
+++ b/examples_linux/getting_started.py
@@ -1,32 +1,15 @@
"""
A simple example of sending data from 1 nRF24L01 transceiver to another.
This example was written to be used on 2 devices acting as 'nodes'.
+
+See documentation at https://nRF24.github.io/RF24
"""
-import sys
-import argparse
+
import time
import struct
-from RF24 import RF24, RF24_PA_LOW
-
-
-parser = argparse.ArgumentParser(
- description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
-)
-parser.add_argument(
- "-n",
- "--node",
- type=int,
- choices=range(2),
- help="the identifying radio number (or node ID number)",
-)
-parser.add_argument(
- "-r",
- "--role",
- type=int,
- choices=range(2),
- help="'1' specifies the TX role. '0' specifies the RX role.",
-)
+from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER
+print(__file__) # print example name
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
@@ -35,14 +18,53 @@
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev.
# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc..
-CSN_PIN = 0 # connected to GPIO8
-CE_PIN = 22 # connected to GPIO22
+CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
+if RF24_DRIVER == "MRAA":
+ CE_PIN = 15 # for GPIO22
+elif RF24_DRIVER == "wiringPi":
+ CE_PIN = 3 # for GPIO22
+else:
+ CE_PIN = 22
radio = RF24(CE_PIN, CSN_PIN)
-################## Linux (BBB,x86,etc) #########################
-# See http://nRF24.github.io/RF24/pages.html for more information on usage
-# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
-# See https://www.kernel.org/doc/Documentation/spi/spidev for more
-# information on SPIDEV
+
+# initialize the nRF24L01 on the spi bus
+if not radio.begin():
+ raise RuntimeError("radio hardware is not responding")
+
+# For this example, we will use different addresses
+# An address need to be a buffer protocol object (bytearray)
+address = [b"1Node", b"2Node"]
+# It is very helpful to think of an address as a path instead of as
+# an identifying device destination
+
+
+# to use different addresses on a pair of radios, we need a variable to
+# uniquely identify which address this radio will use to transmit
+# 0 uses address[0] to transmit, 1 uses address[1] to transmit
+radio_number = bool(
+ int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
+)
+
+# set the Power Amplifier level to -12 dBm since this test example is
+# usually run with nRF24L01 transceivers in close proximity of each other
+radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
+
+# set the TX address of the RX node into the TX pipe
+radio.openWritingPipe(address[radio_number]) # always uses pipe 0
+
+# set the RX address of the TX node into a RX pipe
+radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
+
+# To save time during transmission, we'll set the payload size to be only
+# what we need. A float value occupies 4 bytes in memory using
+# struct.pack(); "f" means an unsigned float
+radio.payloadSize = struct.calcsize("f")
+
+# for debugging, we have 2 options that print a large block of details
+# (smaller) function that prints raw register values
+# radio.printDetails()
+# (larger) function that prints human readable data
+# radio.printPrettyDetails()
# using the python keyword global is bad practice. Instead we'll use a 1 item
# list to store our float number for the payloads sent/received
@@ -137,61 +159,11 @@ def set_role() -> bool:
if __name__ == "__main__":
-
- args = parser.parse_args() # parse any CLI args
-
- # initialize the nRF24L01 on the spi bus
- if not radio.begin():
- raise RuntimeError("radio hardware is not responding")
-
- # For this example, we will use different addresses
- # An address need to be a buffer protocol object (bytearray)
- address = [b"1Node", b"2Node"]
- # It is very helpful to think of an address as a path instead of as
- # an identifying device destination
-
- print(sys.argv[0]) # print example name
-
- # to use different addresses on a pair of radios, we need a variable to
- # uniquely identify which address this radio will use to transmit
- # 0 uses address[0] to transmit, 1 uses address[1] to transmit
- radio_number = args.node # uses default value from `parser`
- if args.node is None: # if '--node' arg wasn't specified
- radio_number = bool(
- int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
- )
-
- # set the Power Amplifier level to -12 dBm since this test example is
- # usually run with nRF24L01 transceivers in close proximity of each other
- radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
-
- # set the TX address of the RX node into the TX pipe
- radio.openWritingPipe(address[radio_number]) # always uses pipe 0
-
- # set the RX address of the TX node into a RX pipe
- radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
-
- # To save time during transmission, we'll set the payload size to be only
- # what we need. A float value occupies 4 bytes in memory using
- # struct.pack(); "f" means an unsigned float
- radio.payloadSize = struct.calcsize("f")
-
- # for debugging, we have 2 options that print a large block of details
- # (smaller) function that prints raw register values
- # radio.printDetails()
- # (larger) function that prints human readable data
- # radio.printPrettyDetails()
-
try:
- if args.role is None: # if not specified with CLI arg '-r'
- while set_role():
- pass # continue example until 'Q' is entered
- else: # if role was set using CLI args
- # run role once and exit
- if bool(args.role):
- master()
- else:
- slave()
+ while set_role():
+ pass # continue example until 'Q' is entered
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Powering down radio.")
radio.powerDown()
+else:
+ print(" Run slave() on receiver\n Run master() on transmitter")
diff --git a/examples_linux/gettingstarted.cpp b/examples_linux/gettingstarted.cpp
index 88991177c..c5916a390 100644
--- a/examples_linux/gettingstarted.cpp
+++ b/examples_linux/gettingstarted.cpp
@@ -35,7 +35,7 @@ using namespace std;
RF24 radio(CE_PIN, CSN_PIN);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// For this example, we'll be using a payload containing
diff --git a/examples_linux/interruptConfigure.cpp b/examples_linux/interruptConfigure.cpp
index f032e163a..916868465 100644
--- a/examples_linux/interruptConfigure.cpp
+++ b/examples_linux/interruptConfigure.cpp
@@ -44,7 +44,7 @@ volatile bool got_interrupt = false; // used to signify that the event started
RF24 radio(CE_PIN, CSN_PIN);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// For this example, we'll be using a payload containing
diff --git a/examples_linux/interrupt_configure.py b/examples_linux/interrupt_configure.py
index 9c635db49..b42930a6f 100644
--- a/examples_linux/interrupt_configure.py
+++ b/examples_linux/interrupt_configure.py
@@ -1,35 +1,34 @@
"""
-This example uses Acknowledgement (ACK) payloads attached to ACK packets to
-demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be
-configured to detect when data is received, or when data has transmitted
-successfully, or when data has failed to transmit.
+Simple example of detecting (and verifying) the IRQ (interrupt) pin on the
+nRF24L01
-This example was written to be used on 2 devices acting as "nodes".
+See documentation at https://nRF24.github.io/RF24
"""
-import sys
-import argparse
-import time
-import RPi.GPIO as GPIO
-from RF24 import RF24, RF24_PA_LOW
+import time
+from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER
+
+try:
+ import gpiod
+ from gpiod.line import Edge
+except ImportError as exc:
+ raise ImportError(
+ "This script requires gpiod installed for observing the IRQ pin. Please run\n"
+ "\n pip install gpiod\n\nMore details at https://pypi.org/project/gpiod/"
+ ) from exc
+
+try: # try RPi5 gpio chip first
+ chip_path = "/dev/gpiochip4"
+ chip = gpiod.Chip(chip_path)
+except FileNotFoundError: # fall back to gpio chip for RPi4 or older
+ chip_path = "/dev/gpiochip0"
+ chip = gpiod.Chip(chip_path)
+finally:
+ print(__file__) # print example name
+ # print gpio chip info
+ info = chip.get_info()
+ print(f"Using {info.name} [{info.label}] ({info.num_lines} lines)")
-parser = argparse.ArgumentParser(
- description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
-)
-parser.add_argument(
- "-n",
- "--node",
- type=int,
- choices=range(2),
- help="the identifying radio number (or node ID number)",
-)
-parser.add_argument(
- "-r",
- "--role",
- type=int,
- choices=range(2),
- help="'1' specifies the TX role. '0' specifies the RX role.",
-)
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
@@ -38,17 +37,55 @@
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev.
# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc..
-CSN_PIN = 0 # connected to GPIO8
-CE_PIN = 22 # connected to GPIO22
+CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
+if RF24_DRIVER == "MRAA":
+ CE_PIN = 15 # for GPIO22
+elif RF24_DRIVER == "wiringPi":
+ CE_PIN = 3 # for GPIO22
+else:
+ CE_PIN = 22
radio = RF24(CE_PIN, CSN_PIN)
-################## Linux (BBB,x86,etc) #########################
-# See http://nRF24.github.io/RF24/pages.html for more information on usage
-# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
-# See https://www.kernel.org/doc/Documentation/spi/spidev for more
-# information on SPIDEV
# select your digital input pin that's connected to the IRQ pin on the nRF24L01
-IRQ_PIN = 12
+IRQ_PIN = 24
+
+# For this example, we will use different addresses
+# An address need to be a buffer protocol object (bytearray)
+address = [b"1Node", b"2Node"]
+# It is very helpful to think of an address as a path instead of as
+# an identifying device destination
+
+# to use different addresses on a pair of radios, we need a variable to
+# uniquely identify which address this radio will use to transmit
+# 0 uses address[0] to transmit, 1 uses address[1] to transmit
+radio_number = bool(
+ int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
+)
+
+# initialize the nRF24L01 on the spi bus
+if not radio.begin():
+ raise OSError("nRF24L01 hardware isn't responding")
+
+# this example uses the ACK payload to trigger the IRQ pin active for
+# the "on data received" event
+radio.enableDynamicPayloads() # ACK payloads are dynamically sized
+radio.enableAckPayload() # enable ACK payloads
+
+# set the Power Amplifier level to -12 dBm since this test example is
+# usually run with nRF24L01 transceivers in close proximity of each other
+radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
+
+# set the TX address of the RX node into the TX pipe
+radio.openWritingPipe(address[radio_number]) # always uses pipe 0
+
+# set the RX address of the TX node into a RX pipe
+radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
+
+# for debugging, we have 2 options that print a large block of details
+# (smaller) function that prints raw register values
+# radio.printDetails()
+# (larger) function that prints human readable data
+# radio.printPrettyDetails()
# For this example, we'll be using a payload containing
# a string that changes on every transmission. (successful or not)
@@ -58,61 +95,40 @@
ack_payloads = (b"Yak ", b"Back", b" ACK")
-def interrupt_handler(channel):
+def interrupt_handler():
"""This function is called when IRQ pin is detected active LOW"""
- print("IRQ pin", channel, "went active LOW.")
- tx_ds, tx_df, rx_dr = radio.whatHappened() # get IRQ status flags
- if tx_df:
- radio.flush_tx()
+ print("\tIRQ pin went active LOW.")
+ tx_ds, tx_df, rx_dr = radio.whatHappened() # update IRQ status flags
print(f"\ttx_ds: {tx_ds}, tx_df: {tx_df}, rx_dr: {rx_dr}")
if pl_iterator[0] == 0:
print(" 'data ready' event test", ("passed" if rx_dr else "failed"))
elif pl_iterator[0] == 1:
print(" 'data sent' event test", ("passed" if tx_ds else "failed"))
- elif pl_iterator[0] == 3:
+ elif pl_iterator[0] == 2:
print(" 'data fail' event test", ("passed" if tx_df else "failed"))
# setup IRQ GPIO pin
-GPIO.setmode(GPIO.BCM)
-GPIO.setup(IRQ_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
-GPIO.add_event_detect(IRQ_PIN, GPIO.FALLING, callback=interrupt_handler)
-# IMPORTANT: do not call radio.available() before calling
-# radio.whatHappened() when the interruptHandler() is triggered by the
-# IRQ pin FALLING event. According to the datasheet, the pipe information
-# is unreliable during the IRQ pin FALLING transition.
-
-
-def _ping_n_wait(pl_iter):
- """private function to ping RX node and wait for IRQ pin to be handled
-
- :param int pl_iter: The index of the buffer in `tx_payloads` tuple to
- send. This number is also used to determine if event test was
- successful or not.
- """
- # set pl_iterator[0] so interrupt_handler() can determine if test was
- # successful or not
- pl_iterator[0] = pl_iter
- # the following False parameter means we're expecting an ACK packet
- radio.startFastWrite(tx_payloads[pl_iter], False)
- time.sleep(0.1) # wait 100 ms for interrupt_handler() to complete
-
+irq_line = gpiod.request_lines(
+ path=chip_path,
+ consumer="RF24_interrupt_py-example", # optional
+ config={IRQ_PIN: gpiod.LineSettings(edge_detection=Edge.FALLING)},
+)
-def print_rx_fifo(pl_size: int):
- """Flush RX FIFO by printing all available payloads with 1 buffer
- :param int pl_size: the expected size of each payload
+def _wait_for_irq(timeout: float = 5):
+ """Wait till IRQ_PIN goes active (LOW).
+ IRQ pin is LOW when activated. Otherwise it is always HIGH
"""
- if radio.rxFifoFull():
- # all 3 payloads received were 5 bytes each, and RX FIFO is full
- # so, fetching 15 bytes from the RX FIFO also flushes RX FIFO
- print("Complete RX FIFO:", radio.read(pl_size * 3).decode("utf-8"))
- else:
- buffer = bytearray()
- while radio.available():
- buffer += radio.read(pl_size)
- if buffer: # if any payloads were read from the RX FIFO
- print("Complete RX FIFO:", buffer.decode("utf-8"))
+ # wait up to ``timeout`` seconds for event to be detected.
+ if not irq_line.wait_edge_events(timeout):
+ print(f"\tInterrupt event not detected for {timeout} seconds!")
+ return False
+ # read event from kernel buffer
+ for event in irq_line.read_edge_events():
+ if event.line_offset == IRQ_PIN and event.event_type is event.Type.FALLING_EDGE:
+ return True
+ return False
def master():
@@ -129,65 +145,70 @@ def master():
# on data ready test
print("\nConfiguring IRQ pin to only ignore 'on data sent' event")
radio.maskIRQ(True, False, False) # args = tx_ds, tx_df, rx_dr
- print(" Pinging slave node for an ACK payload...", end=" ")
- _ping_n_wait(0)
+ print(" Pinging slave node for an ACK payload...")
+ pl_iterator[0] = 0
+ radio.startFastWrite(tx_payloads[0], False) # False means expecting an ACK
+ if _wait_for_irq():
+ interrupt_handler()
# on "data sent" test
print("\nConfiguring IRQ pin to only ignore 'on data ready' event")
radio.maskIRQ(False, False, True) # args = tx_ds, tx_df, rx_dr
- print(" Pinging slave node again... ", end=" ")
- _ping_n_wait(1)
+ print(" Pinging slave node again...")
+ pl_iterator[0] = 1
+ radio.startFastWrite(tx_payloads[1], False) # False means expecting an ACK
+ if _wait_for_irq():
+ interrupt_handler()
- # trigger slave node to stopListening() by filling slave node's RX FIFO
+ # trigger slave node to exit by filling the slave node's RX FIFO
print("\nSending one extra payload to fill RX FIFO on slave node.")
- radio.maskIRQ(1, 1, 1) # disable IRQ pin for this step
+ print("Disabling IRQ pin for all events.")
+ radio.maskIRQ(True, True, True) # args = tx_ds, tx_df, rx_dr
if radio.write(tx_payloads[2]):
- # when send_only parameter is True, send() ignores RX FIFO usage
- if radio.rxFifoFull():
- print("RX node's FIFO is full; it is not listening any more")
- else:
- print(
- "Transmission successful, but the RX node might still be listening."
- )
+ print("Slave node should not be listening anymore.")
else:
- radio.flush_tx()
- print("Transmission failed or timed out. Continuing anyway.")
+ print("Slave node was unresponsive.")
# on "data fail" test
print("\nConfiguring IRQ pin to go active for all events.")
radio.maskIRQ(False, False, False) # args = tx_ds, tx_df, rx_dr
- print(" Sending a ping to inactive slave node...", end=" ")
- _ping_n_wait(3)
-
- # CE pin is still HIGH which consumes more power. Example is now idling so...
- radio.stopListening() # ensure CE pin is LOW
- # stopListening() also calls flush_tx() when ACK payloads are enabled
-
- print_rx_fifo(len(ack_payloads[0])) # empty RX FIFO
-
-
-def slave(timeout: int = 6):
- """Only listen for 3 payload from the master node
-
- :param int timeout: The number of seconds to wait (with no transmission)
- until exiting function.
- """
- pl_iterator[0] = 0 # reset this to indicate event is a 'data_ready' event
+ print(" Sending a ping to inactive slave node...")
+ radio.flush_tx() # just in case any previous tests failed
+ pl_iterator[0] = 2
+ radio.startFastWrite(tx_payloads[3], False) # False means expecting an ACK
+ if _wait_for_irq():
+ interrupt_handler()
+ radio.flush_tx() # flush artifact payload in TX FIFO from last test
+ # all 3 ACK payloads received were 4 bytes each, and RX FIFO is full
+ # so, fetching 12 bytes from the RX FIFO also flushes RX FIFO
+ print("\nComplete RX FIFO:", radio.read(12))
+
+
+def slave(timeout=6): # will listen for 6 seconds before timing out
+ """Only listen for 3 payload from the master node"""
+ # the "data ready" event will trigger in RX mode
+ # the "data sent" or "data fail" events will trigger when we
+ # receive with ACK payloads enabled (& loaded in TX FIFO)
+ print("\nDisabling IRQ pin for all events.")
+ radio.maskIRQ(True, True, True) # args = tx_ds, tx_df, rx_dr
# setup radio to receive pings, fill TX FIFO with ACK payloads
radio.writeAckPayload(1, ack_payloads[0])
radio.writeAckPayload(1, ack_payloads[1])
radio.writeAckPayload(1, ack_payloads[2])
- radio.startListening() # start listening & clear status flags
+ radio.startListening() # start listening & clear irq_dr flag
start_timer = time.monotonic() # start timer now
while not radio.rxFifoFull() and time.monotonic() - start_timer < timeout:
# if RX FIFO is not full and timeout is not reached, then keep waiting
pass
- time.sleep(0.1) # wait for last ACK payload to transmit
+ time.sleep(0.5) # wait for last ACK payload to transmit
radio.stopListening() # put radio in TX mode & discard any ACK payloads
- print_rx_fifo(len(tx_payloads[0]))
+ if radio.available(): # if RX FIFO is not empty (timeout did not occur)
+ # all 3 payloads received were 5 bytes each, and RX FIFO is full
+ # so, fetching 15 bytes from the RX FIFO also flushes RX FIFO
+ print("Complete RX FIFO:", radio.read(15))
-def set_role() -> bool:
+def set_role():
"""Set the role using stdin stream. Timeout arg for slave() can be
specified using a space delimiter (e.g. 'R 10' calls `slave(10)`)
@@ -197,6 +218,7 @@ def set_role() -> bool:
"""
user_input = (
input(
+ f"Make sure the IRQ pin is connected to the GPIO{IRQ_PIN}\n"
"*** Enter 'R' for receiver role.\n"
"*** Enter 'T' for transmitter role.\n"
"*** Enter 'Q' to quit example.\n"
@@ -205,10 +227,7 @@ def set_role() -> bool:
)
user_input = user_input.split()
if user_input[0].upper().startswith("R"):
- if len(user_input) > 1:
- slave(int(user_input[1]))
- else:
- slave()
+ slave(*[int(x) for x in user_input[1:2]])
return True
if user_input[0].upper().startswith("T"):
master()
@@ -221,63 +240,16 @@ def set_role() -> bool:
if __name__ == "__main__":
-
- args = parser.parse_args() # parse any CLI args
-
- # initialize the nRF24L01 on the spi bus
- if not radio.begin():
- raise RuntimeError("radio hardware is not responding")
-
- # For this example, we will use different addresses
- # An address need to be a buffer protocol object (bytearray)
- address = [b"1Node", b"2Node"]
- # It is very helpful to think of an address as a path instead of as
- # an identifying device destination
-
- print(sys.argv[0]) # print example name
-
- # to use different addresses on a pair of radios, we need a variable to
- # uniquely identify which address this radio will use to transmit
- # 0 uses address[0] to transmit, 1 uses address[1] to transmit
- radio_number = args.node # uses default value from `parser`
- if args.node is None: # if '--node' arg wasn't specified
- radio_number = bool(
- int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
- )
-
- # set the Power Amplifier level to -12 dBm since this test example is
- # usually run with nRF24L01 transceivers in close proximity of each other
- radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
-
- # ACK payloads are dynamically sized.
- radio.enableDynamicPayloads() # to use ACK payloads
-
- # this example uses the ACK payload to trigger the IRQ pin active for
- # the "on data received" event
- radio.enableAckPayload() # enable ACK payloads
-
- # set the TX address of the RX node into the TX pipe
- radio.openWritingPipe(address[radio_number]) # always uses pipe 0
-
- # set the RX address of the TX node into a RX pipe
- radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
-
- # for debugging, we have 2 options that print a large block of details
- # (smaller) function that prints raw register values
- # radio.printDetails()
- # (larger) function that prints human readable data
- # radio.printPrettyDetails()
-
try:
- if args.role is None: # if not specified with CLI arg '-r'
- while set_role():
- pass # continue example until 'Q' is entered
- else: # if role was set using CLI args
- # run role once and exit
- if bool(args.role):
- master()
- else:
- slave()
+ while set_role():
+ pass # continue example until 'Q' is entered
except KeyboardInterrupt:
- print(" Keyboard Interrupt detected. Powering down radio.")
+ print(" Keyboard Interrupt detected. Exiting...")
radio.powerDown()
+else:
+ print(
+ f"Make sure the IRQ pin is connected to the GPIO{IRQ_PIN}",
+ "Run slave() on receiver",
+ "Run master() on transmitter",
+ sep="\n",
+ )
diff --git a/examples_linux/interrupts/transfer_interrupt.cpp b/examples_linux/interrupts/transfer_interrupt.cpp
index 46387bf2d..b634c6807 100644
--- a/examples_linux/interrupts/transfer_interrupt.cpp
+++ b/examples_linux/interrupts/transfer_interrupt.cpp
@@ -51,7 +51,7 @@ RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://tmrh20.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// Setup for ARM(Linux) devices like BBB using spidev (default is "/dev/spidev1.0" )
diff --git a/examples_linux/manualAcknowledgements.cpp b/examples_linux/manualAcknowledgements.cpp
index 83bf77baf..a10280b15 100644
--- a/examples_linux/manualAcknowledgements.cpp
+++ b/examples_linux/manualAcknowledgements.cpp
@@ -41,7 +41,7 @@ using namespace std;
RF24 radio(CE_PIN, CSN_PIN);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// For this example, we'll be using a payload containing
diff --git a/examples_linux/manual_acknowledgements.py b/examples_linux/manual_acknowledgements.py
index 3ce24de90..d310626b9 100644
--- a/examples_linux/manual_acknowledgements.py
+++ b/examples_linux/manual_acknowledgements.py
@@ -8,30 +8,15 @@
transmission.
This example was written to be used on 2 devices acting as 'nodes'.
+
+See documentation at https://nRF24.github.io/RF24
"""
-import sys
-import argparse
+
import time
-from RF24 import RF24, RF24_PA_LOW
+from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER
-parser = argparse.ArgumentParser(
- description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
-)
-parser.add_argument(
- "-n",
- "--node",
- type=int,
- choices=range(2),
- help="the identifying radio number (or node ID number)",
-)
-parser.add_argument(
- "-r",
- "--role",
- type=int,
- choices=range(2),
- help="'1' specifies the TX role. '0' specifies the RX role.",
-)
+print(__file__) # print example name
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
@@ -40,14 +25,52 @@
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev.
# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc..
-CSN_PIN = 0 # connected to GPIO8
-CE_PIN = 22 # connected to GPIO22
+CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
+if RF24_DRIVER == "MRAA":
+ CE_PIN = 15 # for GPIO22
+elif RF24_DRIVER == "wiringPi":
+ CE_PIN = 3 # for GPIO22
+else:
+ CE_PIN = 22
radio = RF24(CE_PIN, CSN_PIN)
-################## Linux (BBB,x86,etc) #########################
-# See http://nRF24.github.io/RF24/pages.html for more information on usage
-# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
-# See https://www.kernel.org/doc/Documentation/spi/spidev for more
-# information on SPIDEV
+
+# initialize the nRF24L01 on the spi bus
+if not radio.begin():
+ raise RuntimeError("radio hardware is not responding")
+
+# For this example, we will use different addresses
+# An address need to be a buffer protocol object (bytearray)
+address = [b"1Node", b"2Node"]
+# It is very helpful to think of an address as a path instead of as
+# an identifying device destination
+
+# to use different addresses on a pair of radios, we need a variable to
+# uniquely identify which address this radio will use to transmit
+# 0 uses address[0] to transmit, 1 uses address[1] to transmit
+radio_number = bool(
+ int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
+)
+
+# set the Power Amplifier level to -12 dBm since this test example is
+# usually run with nRF24L01 transceivers in close proximity of each other
+radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
+
+# set the TX address of the RX node into the TX pipe
+radio.openWritingPipe(address[radio_number]) # always uses pipe 0
+
+# set the RX address of the TX node into a RX pipe
+radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
+
+# To save time during transmission, we'll set the payload size to be only
+# what we need. For this example, we'll be using a byte for the
+# payload counter and 7 bytes for the payload message
+radio.payloadSize = 8
+
+# for debugging, we have 2 options that print a large block of details
+# (smaller) function that prints raw register values
+# radio.printDetails()
+# (larger) function that prints human readable data
+# radio.printPrettyDetails()
# using the python keyword global is bad practice. Instead we'll use a 1 item
# list to store our integer number for the payloads' counter
@@ -180,61 +203,11 @@ def set_role() -> bool:
if __name__ == "__main__":
-
- args = parser.parse_args() # parse any CLI args
-
- # initialize the nRF24L01 on the spi bus
- if not radio.begin():
- raise RuntimeError("radio hardware is not responding")
-
- # For this example, we will use different addresses
- # An address need to be a buffer protocol object (bytearray)
- address = [b"1Node", b"2Node"]
- # It is very helpful to think of an address as a path instead of as
- # an identifying device destination
-
- print(sys.argv[0]) # print example name
-
- # to use different addresses on a pair of radios, we need a variable to
- # uniquely identify which address this radio will use to transmit
- # 0 uses address[0] to transmit, 1 uses address[1] to transmit
- radio_number = args.node # uses default value from `parser`
- if args.node is None: # if '--node' arg wasn't specified
- radio_number = bool(
- int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
- )
-
- # set the Power Amplifier level to -12 dBm since this test example is
- # usually run with nRF24L01 transceivers in close proximity of each other
- radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
-
- # set the TX address of the RX node into the TX pipe
- radio.openWritingPipe(address[radio_number]) # always uses pipe 0
-
- # set the RX address of the TX node into a RX pipe
- radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
-
- # To save time during transmission, we'll set the payload size to be only
- # what we need. For this example, we'll be using a byte for the
- # payload counter and 7 bytes for the payload message
- radio.payloadSize = 8
-
- # for debugging, we have 2 options that print a large block of details
- # (smaller) function that prints raw register values
- # radio.printDetails()
- # (larger) function that prints human readable data
- # radio.printPrettyDetails()
-
try:
- if args.role is None: # if not specified with CLI arg '-r'
- while set_role():
- pass # continue example until 'Q' is entered
- else: # if role was set using CLI args
- # run role once and exit
- if bool(args.role):
- master()
- else:
- slave()
+ while set_role():
+ pass # continue example until 'Q' is entered
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Powering down radio.")
radio.powerDown()
+else:
+ print(" Run slave() on receiver\n Run master() on transmitter")
diff --git a/examples_linux/multiceiverDemo.cpp b/examples_linux/multiceiverDemo.cpp
index d46463c9b..9a405fa88 100644
--- a/examples_linux/multiceiverDemo.cpp
+++ b/examples_linux/multiceiverDemo.cpp
@@ -39,7 +39,7 @@ using namespace std;
RF24 radio(CE_PIN, CSN_PIN);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// For this example, we'll be using 6 addresses; 1 for each TX node
diff --git a/examples_linux/multiceiver_demo.py b/examples_linux/multiceiver_demo.py
index fd1040d9f..c0cc1496b 100644
--- a/examples_linux/multiceiver_demo.py
+++ b/examples_linux/multiceiver_demo.py
@@ -5,24 +5,15 @@
This example was written to be used on up to 6 devices acting as TX nodes &
only 1 device acting as the RX node (that's a maximum of 7 devices).
+
+See documentation at https://nRF24.github.io/RF24
"""
-import sys
-import argparse
+
import time
import struct
-from RF24 import RF24, RF24_PA_LOW
+from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER
-
-parser = argparse.ArgumentParser(
- description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
-)
-parser.add_argument(
- "-n",
- "--node",
- choices=("0", "1", "2", "3", "4", "5", "R", "r"),
- help="the identifying node ID number for the TX role. "
- "Use 'R' or 'r' to specify the RX role",
-)
+print(__file__)
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
@@ -31,23 +22,41 @@
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev.
# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc..
-CSN_PIN = 0 # connected to GPIO8
-CE_PIN = 22 # connected to GPIO22
+CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
+if RF24_DRIVER == "MRAA":
+ CE_PIN = 15 # for GPIO22
+elif RF24_DRIVER == "wiringPi":
+ CE_PIN = 3 # for GPIO22
+else:
+ CE_PIN = 22
radio = RF24(CE_PIN, CSN_PIN)
-################## Linux (BBB,x86,etc) #########################
-# See http://nRF24.github.io/RF24/pages.html for more information on usage
-# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
-# See https://www.kernel.org/doc/Documentation/spi/spidev for more
-# information on SPIDEV
+
+# initialize the nRF24L01 on the spi bus
+if not radio.begin():
+ raise RuntimeError("radio hardware is not responding")
+
+# set the Power Amplifier level to -12 dBm since this test example is
+# usually run with nRF24L01 transceivers in close proximity of each other
+radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
+
+# To save time during transmission, we'll set the payload size to be only what
+# we need.
+# 2 int occupy 8 bytes in memory using struct.pack()
+# "ii" means 2 unsigned integers
+radio.payloadSize = struct.calcsize("ii")
+
+# for debugging, we have 2 options that print a large block of details
+# radio.printDetails(); # (smaller) function that prints raw register values
+# radio.printPrettyDetails(); # (larger) function that prints human readable data
# setup the addresses for all transmitting radio nodes
addresses = [
b"\x78" * 5,
- b"\xF1\xB6\xB5\xB4\xB3",
- b"\xCD\xB6\xB5\xB4\xB3",
- b"\xA3\xB6\xB5\xB4\xB3",
- b"\x0F\xB6\xB5\xB4\xB3",
- b"\x05\xB6\xB5\xB4\xB3",
+ b"\xf1\xb6\xb5\xb4\xb3",
+ b"\xcd\xb6\xb5\xb4\xb3",
+ b"\xa3\xb6\xb5\xb4\xb3",
+ b"\x0f\xb6\xb5\xb4\xb3",
+ b"\x05\xb6\xb5\xb4\xb3",
]
# It is very helpful to think of an address as a path instead of as
# an identifying device destination
@@ -157,39 +166,13 @@ def set_role() -> bool:
if __name__ == "__main__":
-
- args = parser.parse_args() # parse any CLI args
-
- # initialize the nRF24L01 on the spi bus
- if not radio.begin():
- raise RuntimeError("radio hardware is not responding")
-
- print(sys.argv[0]) # print example name
-
- # set the Power Amplifier level to -12 dBm since this test example is
- # usually run with nRF24L01 transceivers in close proximity of each other
- radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
-
- # To save time during transmission, we'll set the payload size to be only what
- # we need.
- # 2 int occupy 8 bytes in memory using struct.pack()
- # "ii" means 2 unsigned integers
- radio.payloadSize = struct.calcsize("ii")
-
- # for debugging, we have 2 options that print a large block of details
- # radio.printDetails(); # (smaller) function that prints raw register values
- # radio.printPrettyDetails(); # (larger) function that prints human readable data
-
try:
- if args.node is None: # if not specified with CLI arg '-n'
- while set_role():
- pass # continue example until 'Q' is entered
- else: # if role was set using CLI args
- # run role once and exit
- if args.node.isdigit():
- master(int(args.node))
- else:
- slave()
+ while set_role():
+ pass # continue example until 'Q' is entered
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Powering down radio.")
radio.powerDown()
+else:
+ print(" Run slave() on the receiver")
+ print(" Run master(node_number) on a transmitter")
+ print(" master()'s parameter, `node_number`, must be in range [0, 5]")
diff --git a/examples_linux/ncurses/scanner_curses.cpp b/examples_linux/ncurses/scanner_curses.cpp
index 282701980..51c05a319 100644
--- a/examples_linux/ncurses/scanner_curses.cpp
+++ b/examples_linux/ncurses/scanner_curses.cpp
@@ -42,7 +42,7 @@ using namespace std;
RF24 radio(CE_PIN, CSN_PIN);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// Channel info
diff --git a/examples_linux/scanner.cpp b/examples_linux/scanner.cpp
index 4f35f4fed..da921fb76 100644
--- a/examples_linux/scanner.cpp
+++ b/examples_linux/scanner.cpp
@@ -67,7 +67,7 @@ using namespace std;
RF24 radio(CE_PIN, CSN_PIN);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// Channel info
diff --git a/examples_linux/scanner.py b/examples_linux/scanner.py
index cd621f90f..bfe60728e 100644
--- a/examples_linux/scanner.py
+++ b/examples_linux/scanner.py
@@ -6,15 +6,19 @@
See documentation at https://nRF24.github.io/RF24
"""
-# pylint: disable=no-member
import curses
import time
from typing import List, Tuple, Any
-from RF24 import RF24, RF24_1MBPS, RF24_2MBPS, RF24_250KBPS
+from RF24 import RF24, RF24_1MBPS, RF24_2MBPS, RF24_250KBPS, RF24_DRIVER
-CSN_PIN = 0 # connected to GPIO8
-CE_PIN = 22 # connected to GPIO22
+CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
+if RF24_DRIVER == "MRAA":
+ CE_PIN = 15 # for GPIO22
+elif RF24_DRIVER == "wiringPi":
+ CE_PIN = 3 # for GPIO22
+else:
+ CE_PIN = 22
radio = RF24(CE_PIN, CSN_PIN)
@@ -224,4 +228,4 @@ def main():
if __name__ == "__main__":
main()
else:
- print("Enter 'main()' to run the program.")
+ print("Run 'main()' to run the program.")
diff --git a/examples_linux/streamingData.cpp b/examples_linux/streamingData.cpp
index f7b1c5432..e1a9b26ca 100644
--- a/examples_linux/streamingData.cpp
+++ b/examples_linux/streamingData.cpp
@@ -37,7 +37,7 @@ using namespace std;
RF24 radio(CE_PIN, CSN_PIN);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
-// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
+// See https://github.com/eclipse/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// For this example, we'll be sending 32 payloads each containing
diff --git a/examples_linux/streaming_data.py b/examples_linux/streaming_data.py
index 0a339dab7..3d85484b5 100644
--- a/examples_linux/streaming_data.py
+++ b/examples_linux/streaming_data.py
@@ -2,30 +2,14 @@
A simple example of streaming data from 1 nRF24L01 transceiver to another.
This example was written to be used on 2 devices acting as 'nodes'.
+
+See documentation at https://nRF24.github.io/RF24
"""
-import sys
-import argparse
+
import time
-from RF24 import RF24, RF24_PA_LOW
+from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER
-
-parser = argparse.ArgumentParser(
- description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
-)
-parser.add_argument(
- "-n",
- "--node",
- type=int,
- choices=range(2),
- help="the identifying radio number (or node ID number)",
-)
-parser.add_argument(
- "-r",
- "--role",
- type=int,
- choices=range(2),
- help="'1' specifies the TX role. '0' specifies the RX role.",
-)
+print(__file__) # print example name
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
@@ -34,19 +18,57 @@
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev.
# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc..
-CSN_PIN = 0 # connected to GPIO8
-CE_PIN = 22 # connected to GPIO22
+CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
+if RF24_DRIVER == "MRAA":
+ CE_PIN = 15 # for GPIO22
+elif RF24_DRIVER == "wiringPi":
+ CE_PIN = 3 # for GPIO22
+else:
+ CE_PIN = 22
radio = RF24(CE_PIN, CSN_PIN)
-################## Linux (BBB,x86,etc) #########################
-# See http://nRF24.github.io/RF24/pages.html for more information on usage
-# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
-# See https://www.kernel.org/doc/Documentation/spi/spidev for more
-# information on SPIDEV
+
+# initialize the nRF24L01 on the spi bus
+if not radio.begin():
+ raise RuntimeError("radio hardware is not responding")
+
+# For this example, we will use different addresses
+# An address need to be a buffer protocol object (bytearray)
+address = [b"1Node", b"2Node"]
+# It is very helpful to think of an address as a path instead of as
+# an identifying device destination
+
+# to use different addresses on a pair of radios, we need a variable to
+# uniquely identify which address this radio will use to transmit
+# 0 uses address[0] to transmit, 1 uses address[1] to transmit
+radio_number = bool(
+ int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
+)
+
+# set the Power Amplifier level to -12 dBm since this test example is
+# usually run with nRF24L01 transceivers in close proximity of each other
+radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
+
+# set the TX address of the RX node into the TX pipe
+radio.openWritingPipe(address[radio_number]) # always uses pipe 0
+
+# set the RX address of the TX node into a RX pipe
+radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
+
# Specify the number of bytes in the payload. This is also used to
# specify the number of payloads in 1 stream of data
SIZE = 32 # this is the default maximum payload size
+# To save time during transmission, we'll set the payload size to be only
+# what we need. For this example, we'll be using the default maximum 32
+radio.payloadSize = SIZE
+
+# for debugging, we have 2 options that print a large block of details
+# (smaller) function that prints raw register values
+# radio.printDetails()
+# (larger) function that prints human readable data
+# radio.printPrettyDetails()
+
def make_buffer(buf_iter: int) -> bytes:
"""Returns a dynamically created payloads
@@ -92,7 +114,7 @@ def master(count: int = 1):
end_timer = time.monotonic_ns() # end timer
print(
f"Time to transmit data = {(end_timer - start_timer) / 1000} us.",
- f"Detected {failures} failures."
+ f"Detected {failures} failures.",
)
@@ -119,7 +141,6 @@ def slave(timeout: int = 6):
radio.stopListening() # put the radio in TX mode
-
def set_role() -> bool:
"""Set the role using stdin stream. Role args can be specified using space
delimiters (e.g. 'R 10' calls `slave(10)` & 'T 3' calls `master(3)`)
@@ -157,60 +178,11 @@ def set_role() -> bool:
if __name__ == "__main__":
-
- args = parser.parse_args() # parse any CLI args
-
- # initialize the nRF24L01 on the spi bus
- if not radio.begin():
- raise RuntimeError("radio hardware is not responding")
-
- # For this example, we will use different addresses
- # An address need to be a buffer protocol object (bytearray)
- address = [b"1Node", b"2Node"]
- # It is very helpful to think of an address as a path instead of as
- # an identifying device destination
-
- print(sys.argv[0]) # print example name
-
- # to use different addresses on a pair of radios, we need a variable to
- # uniquely identify which address this radio will use to transmit
- # 0 uses address[0] to transmit, 1 uses address[1] to transmit
- radio_number = args.node # uses default value from `parser`
- if args.node is None: # if '--node' arg wasn't specified
- radio_number = bool(
- int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
- )
-
- # set the Power Amplifier level to -12 dBm since this test example is
- # usually run with nRF24L01 transceivers in close proximity of each other
- radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
-
- # set the TX address of the RX node into the TX pipe
- radio.openWritingPipe(address[radio_number]) # always uses pipe 0
-
- # set the RX address of the TX node into a RX pipe
- radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
-
- # To save time during transmission, we'll set the payload size to be only
- # what we need. For this example, we'll be using the default maximum 32
- radio.payloadSize = SIZE
-
- # for debugging, we have 2 options that print a large block of details
- # (smaller) function that prints raw register values
- # radio.printDetails()
- # (larger) function that prints human readable data
- # radio.printPrettyDetails()
-
try:
- if args.role is None: # if not specified with CLI arg '-r'
- while set_role():
- pass # continue example until 'Q' is entered
- else: # if role was set using CLI args
- # run role once and exit
- if bool(args.role):
- master()
- else:
- slave()
+ while set_role():
+ pass # continue example until 'Q' is entered
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Powering down radio.")
radio.powerDown()
+else:
+ print(" Run slave() on receiver\n Run master() on transmitter")
diff --git a/pyRF24/pyRF24.cpp b/pyRF24/pyRF24.cpp
index b37f02886..eb6dc6199 100644
--- a/pyRF24/pyRF24.cpp
+++ b/pyRF24/pyRF24.cpp
@@ -151,6 +151,19 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(txStandBy_wrap1, RF24::txStandBy, 0, 2)
BOOST_PYTHON_MODULE(RF24)
{
+ bp::scope().attr("RF24_DRIVER") =
+#ifdef RF24_PIGPIO
+ "pigpio"
+#elif defined(MRAA)
+ "MRAA"
+#elif defined(RF24_RPi)
+ "RPi"
+#elif defined(RF24_WIRINGPI)
+ "wiringPi"
+#else
+ "SPIDEV"
+#endif
+ ;
#ifdef BCM2835_H
bp::enum_("RPiGPIOPin")