Releases: nRF24/CircuitPython_nRF24L01
Bug fix about connecting mesh nodes
repo updates
Dropped support for MicroPython
This revokes the experimental support for micropython. Going forward, it'd be better to rely on adafruit-blinka
's progress toward micropython support (adafruit/Adafruit_Blinka#480) which is currently hindered for the same reason I'm revoking it here - the utime
lib.
Other various changes include:
- revert all use of f-strings back to
str.format()
. - Complete type hinting. I'm worried this might break compatibility with much older versions of CircuitPython, but v6+ is highly recommended for execution speeds (v7+ is better with mpy compression).
- RF24 class uses allocated
_in
and_out
buffers (instance attributes) for SPI transactions. This is based on some "pro-tips" about using micropython. - various doc updates.
- improved network example to allow receiving while idling during
emit()
- improve setup.py for MacOS installs
- allow saving/loading DHCP as a binary file. This should help people to migrate existing networks that use the C++ RF24Mesh library.
RF24Network, RF24Mesh, and RXing BLE #33
Adds new features
- RF24Network ported from TMRh20 C++ library (not WiFi compatible)
- RF24Mesh ported from TMRh20 C++ library (not BLE/802.11 mesh compatible)
- sniffing/receiving BLE payloads. This is still subject to the limitations of the nRF24L01 as have been outlined in the
fake_ble
module's docs.
See #33 for more details.
Also improved speed in certain aspects of the RF24 class.
patch update
patch and doc updates
This release includes:
- A fix that avoids disabling
auto_ack
on pipe 0 when only pipe 0 hasauto_ack
enabled. - found and fixed several inaccuracies in docs
Retroactive Release
This release is a retrofitting of non-breaking backward compatible features introduced in v2.0.0. However, this also fixes 1 bug that allowed a flood of subsequent errors:
payload_length
returns the setting for only pipe 0. This attribute can still be used to set individual pipes (see docs), but in v1.2.0-v1.2.3 it returned an internal list that prevented properly setting payload lengths for individual pipes. This error would also cause malfunctions inany()
,send()
,resend()
,recv()
, andwrite()
. Use the newget_payload_length()
function to retrieve the current setting for any pipe.
New features
- Huge Speed-up (~10x faster transmissions)!
- Examples retrofitted to be forward compatible not backward compatible. Additionally, all examples (except nrf24l01_context_test.py and nrf24l01_fake_ble_test.py) are compatible with the new examples in TMRh20's RF24 library (I wrote those examples also 😉 ). Conversely, the examples still use
time.monotonic()
to preserve compatibility with CPython v3.4 where v2.0.0 now requires CPython v3.7+ on Linux (because that's whentime.monotonic_ns()
was introduced). - Examples can now also be executed from Linux CLI (no need to keep
from example_name import *
anymore - but you still can). - New scanner example (warning: it runs a bit slower on older RPi). Also replaced nrf24l01_2arduino_handling_data.py with nrf24l01_manual_ack_test.py.
- New
available()
function provided as a convenience instead of usingnrf.update() and nrf.pipe is not None
(a technique introduced in v1.2.3). BecauseFakeBLE
class now inherits fromRF24
class, this new function is overridden in theFakeBLE
class with the existingavailable()
function to prevent breaking backward compatibility. The difference in functionality will really only affect those trying to implement receiving BLE advertisements (officially unsupported at this time) using theFakeBLE
API. - New
set_*()
andget_*()
methods forauto_ack
,dynamic_payloads
payload_length
, andard
/arc
attributes.ard
/arc
attributes are consolidated into*et_auto_retries()
methods (because they live in the same register on the nRF24L01). - Much more underlying optimizations listed in v2.0.0 release description under "Code Changes Include" section... However,
auto_ack
anddynamic_payloads
attributes still return boolean (not integers like in v2.0.0).
Final Release
This will likely be the last release for v1.x. I just couldn't leave users constricted to using v1.x without the huge speed-up implementation and a known bug.
What I learned from TMRh20 and more
Breaking backward compatibility changes
- NEW
available()
function provided as a convenience instead of usingnrf.update() and nrf.pipe is not None
(a technique introduced in the last release). To expose this newavailable()
function in theFakeBLE
API, I had to rename the currentavailable()
function tolen_available()
. - RENAMED
recv()
is nowread()
. The descriptive nameread()
makes more sense because this function isn't actually doing the receiving, rather it is simply reading payload data that was already received and stored in the radio's RX FIFO. - RENAMED
what_happened()
toprint_details()
. The name "what_happened" came from my misunderstanding of the TMRh20 library'sRF24::whatHappened()
(& partly I just liked the name). Now, using "print_details" makes more sense because it is an apt description of what the function actually does. - REMOVED
FakeBLE.to_android
attribute because it was marked for deprecation. - REMOVED
RF24.read_ack()
function because it was marked for deprecation. - All examples now use
time.monotonic_ns()
to measure transmission times. This change requires Python v3.7 in Linux, thus setup.py stipulates this requirement viapython_requires
option. Recommend using latest release of the Raspberry Pi OS which ships with Python v3.7.2 (as of this writing). auto_ack
returns an integer (instead of a boolean) where each bit represent the feature's setting about a pipe.dynamic_payloads
returns an integer (instead of a boolean) where each bit represent the feature's setting about a pipe.payload_length
returns the current setting of pipe 0 instead of a list for all pipes. This actually fixes a bug that allowed a flood of other subsequent bugs.- In v1.2.0 - v1.2.3, if a user called
payload_length[0] = 0
, there was nothing in the code to prevent this mis-configuration (payload length cannot be 0). Furthermore this mis-configuration was not written to the corresponding nRF24L01 registers which would cause errors in every other function that handled payloads and/or payload lengths (namelyany()
,send()
,write()
,recv()
, &what_happened(True)
)
- In v1.2.0 - v1.2.3, if a user called
Code Changes Include
- TRANSMISSIONS THAT PREVIOUSLY TOOK 32 MILLISECONDS NOW TAKE ABOUT 2 OR 3 MILLISECONDS!!! (~10x Speed-up!) I've achieved this huge speed-up by removing the
time.sleep(0.005)
calls in the SPI access functions. To compensate for the inherent CSN pin bouncing instability, I've implemented theextra_clocks=8
parameter to Circuitpython'sSPIDevice
c'tor. Essentially this means that after the CSN pin is set inactive HIGH, theSPIDevice
object writes another dummy byte to let the CSN pin settle. This technique is faster than trying to do a time-based delay usingtime.sleep()
(& also turns the disadvantage of Python's slow execution time into more of a strength). I'm aware that this technique is meant for SD cards and is dependent on the SPI bus' frequency, but if we encounter problems... I'll cross that bridge if we come to it. - Removed any other
time.sleep()
call that waited for less than 100 microseconds. Also, I took an idea from TMRh20'sRF24::write()
and moved thece_pin.value = 0
call to after the resulting status flags are asserted. - REMOVED the
CSN_DELAY
constant since altering its value had no real-time affect on the SPI access functions. Additionally, it isn't needed anymore due to the first point about implementing the huge speed-up. listen
no longer flushes RX FIFO when entering RX mode.listen
now flushes TX FIFO when entering TX mode andack
payloads are enabled.listen
closes pipe 0 if it hasn't been designated for RX when entering RX mode.open_tx_pipe()
does not actually open pipe 0 whenauto_ack
is enabled. Rather,listen
now opens pipe 0 when entering TX mode andauto_ack
is enabled for pipe 0.send()
&resend()
doesn't clear the Status flags when finished anymore. This change will likely have little impact on applications since the status flags are still cleared when enteringwrite()
andresend()
. This was done to speed up execution.auto_ack
now force-enables the automatic acknowledgement feature for pipe 0 when any other RX pipe hasauto_ack
enabled.- NEW
set_*()
&get_*()
publicly exposed functions forauto_ack
,dynamic_payloads
,payload_length
, &ard
/arc
attributes. These should allow faster, easier, & less error-prone interaction when setting or getting the configuration for said attributes on any individual pipe or all pipes at once. I haven't deprecated the attribute's older setter-decorated functions for backward compatibility (the newset_*()
functions still utilize the attribute's setter-decorated functions as helpers). ard
,arc
, &crc
attributes now clamp invalid input values instead throwing aValueError
exception.- NEW
allow_ask_no_ack
attribute for unofficial support of the Si24R1 (a flaw from cloning a typo in the nRF24L01 datasheet) - NEW
last_tx_arc
attribute for getting the number of retry attempts made in previous transmission. This data was previously only available inwhat_happened()
, I found it useful when helping people troubleshhoot TMRh20's RF24 library. FakeBLE
now inherits fromRF24
. Some attributes/functions are overridden to raise aNotImplementedError
exception, so some vital ingredients to the BLE operation isn't compromised via theFakeBLE
API.close_rx_pipe()
now properly prevents thelisten
attribute from overriding the pipe 0 reading addressprint_details()
now prints a more accurate representation of the addresses used on the pipes. Like the TMRh20 RF24 library'sprintDetails()
, the address now prints a "hexlified" string in big endian form.- NEW
address_repr()
function (belonging to the rf24.py module not the RF24 class) is the helper function that returns the address specified as a "hexlified" string in big endian form.
Revised examples + new nrf24l01_manual_ack_test.py & nrf24l01_scanner_test.py
-
NEW scanner_test example that prints a vertical graph of potential RF interference for all applicable frequencies (vertically labeled by channel number).
-
In making a similar contribution to TMRh20's RF24 library, @TMRh20 kindly emphasized the importance of demonstrating "proper addressing" related to pipe usage. To show my appreciation for the discussion (& lessons learned), the examples have all (except the multiceiver example) been revised to use pipe 0 for TX & pipe 1 for RX. This revision adds a preliminary prompt that asks "Which radio is this?" Whereby:
- entering 0 uses
b"1Node"
on pipe 0 andb"2Node"
on pipe 1 - entering 1 uses
b"2Node"
on pipe 0 andb"1Node"
on pipe 1
- entering 0 uses
-
some examples' payloads have also been altered. This has been done to match the new examples I've submitted to TMRh20's RF24 library.
- simple_test uses a incrementing float that persists between calling
master()
&slave()
- ack_payload_test shows data structure usage and C-string's NULL terminating char with a counter that increments on successful transmissions and persists between calling
master()
&slave()
- NEW manual_ack_test mimics the ack_payload_test, but it doesn't use ACK payloads. Rather it uses manually switch between RX/TX modes.
- multiceiver_test uses an 8 byte payload that is properly packed using Python's
struct
library (instead of directly encoding the UTF-8 data into the bytearray)
- simple_test uses a incrementing float that persists between calling
-
REMOVED nrf24l01_2arduino_handling_data.py in favor of the NEW nrf24l01_manual_ack_test.py example (they're practically identical).
-
Compatibility with TMRh20's library now only requires;
dynamic_payloads
has to be disabledpayload_length
has to be set accordingly to match TMRh20's RF24 new examples' configuration
I've left these 2 lines commented out for easy modification (instead of typing it in the python REPL). Because most examples are compatible with TMRh20's new examples, the docs now have a table and hints about making this library compatible with TMRh20's RF24 library (instead of using 1 dedicated example).
-
multiceiver_test doesn't use ACK payloads for
node(1)
anymore. This demonstration was a bit over zealous anyway, and removing it better matches the multiceiverDemo.ino example I submitted to TMRh20's RF24 library. -
all examples can be executed from CLI. This change is really helpful in that it requires less typing and less prone to typos (using terminal's auto-complete mechanism). This really only applies to the Linux platform, and there is no support for CLI args because CircuitPython firmware doesn't use them.
Other changes
- Behold the new project Logo for usage on rtfd.io and social media links
Also changed the favicon to a miniature version of this logo. This should fall under the repo's MIT license, and I'm pretty sure its not as original as I think it is. - changed docs theme to use sphinx-material theme (better display on mobile screens)
- Of course, there are corresponding doc changes to suit all code changes.
- Docs now contain retroactive changes related to different versions of the library using Sphinx's admonitions
.. versionadded::
and.. versionchanged::
. - I've added a feature to the Github action build.yml workflow: Archiving built assets (namely the mpy files for Circuitpython firmware) as workflow artifacts that can be downloaded (for up to a maximum of 90 days).
- The PyPi upload process now uses an API key because my PyPi account has 2FA enabled.
Better utility for write() & update(); stream test revised
Library changes (rf24.py and rf24_lite.py)
update()
now always returns True- this allows for calling the
update()
function in a conditional statement.
e.g.if nrf.update() and nrf.pipe is not None:
(which is a bit faster than usingif nrf.any():
as some of the examples used prior to this change)
- this allows for calling the
write()
returns a boolean describing if the payload was written to the TX FIFO- new
master_fifo()
function in the stream example to compare with originalmaster()
function.master_fifo()
uses thewrite()
function to utilize all 3 levels of the TX FIFO. This function can provide some additional incite as to how many failed transmissions get retried when usingsend(buf, force_retry=2)
in the originalmaster()
function.master()
still uses thesend()
function, but only manages 1 level of the TX FIFO (as it always has).
- I got tired of changing the addresses in the
2arduino_handling_data.py
example, so I mirrored the use of theradioNumber
boolean variable from the TMRh20 library'sGettingStarted_HandlingData.ino
example. I also adjusted some function calls in this example script to show how this library behaves a little differently internally (as compared to the TMRh20 library); these adjustments now closely match the behavior of the TMRh20 library's behavior. - As always, I found more errors in the docs; this time it was about what
fifo()
returned when thecheck_empty
parameter isn't specified. There were some insignificant typos too.
This release's revised stream test seems to have most significant performance differences on the Raspberry Pi. The following is my test result on the RPi2:
>>> from nrf24l01_stream_test import *
nRF24L01 Stream test
Run slave() on receiver
Run master() on transmitter to use 1 level of the TX FIFO
Run master_fifo() on transmitter to use all 3 levels of the TX FIFO.
>>> master()
Transmission took 1630.3276280164719 ms
successfully sent 100.0% (32/32)
>>> master_fifo()
Transmission took 1002.7778159976006 ms with 20 failures detected.
HINT: Try playing with the 'ard' and 'arc' attributes to reduce the number of
failures detected. Tests were better with these attributes at higher values, but
notice the transmission time differences.
>>> # max out the auto-retransmit feature's attributes
>>> nrf.arc = 15
>>> nrf.ard = 4000
>>> master_fifo()
Transmission took 990.8866219520569 ms with 0 failures detected. You Win!
>>> master()
Transmission took 1595.034959077835 ms
successfully sent 100.0% (32/32)
correcting confusion about BLE advertisement's PDU type
Thanks to generous testing done by @jerryneedell, This release clears up some confusion/misconception I had about what PDU type to use in the BLE advertisements.
original misconception
PDU type 0x40
only worked for iPhone, and PDU type 0x42
only worked for Android. Thus the FakeBLE.to_iphone
attribute would act in accordance with this misconception.
correct implementation
PDU type 0x40
does not work for Android, but it does work for iPhone. PDU type 0x42
works for both iPhone and Android smartphones.
Changes
- The
FakeBLE.to_iphone
attribute is nowFakeBLE.to_android
. - The default value for the
FakeBLE.to_android
attribute isTrue
. This means BLE advertisements use PDU type0x42
by default which targets both iPhone & Android smartphones. - removed any use of the old
FakeBLE.to_iphone
attribute from thenrf24l01_fake_ble_test.py
example. - Updated the docs accordingly
- Marked the new
FakeBLE.to_android
attribute for deprecation (on next major release) as it is no longer necessary to specify which BLE advertising PDU type to use.