BLE Limitations

This module uses the RF24 class to make the nRF24L01 imitate a Bluetooth-Low-Emissions (BLE) beacon. A BLE beacon can send data (referred to as advertisements) to any BLE compatible device (ie smart devices with Bluetooth 4.0 or later) that is listening.

Original research was done by Dmitry Grinberg and his write-up (including C source code) can be found here As this technique can prove invaluable in certain project designs, the code here has been adapted to work with CircuitPython.

Important

Because the nRF24L01 wasn’t designed for BLE advertising, it has some limitations that helps to be aware of.

  1. The maximum payload length is shortened to 18 bytes (when not broadcasting a device name nor the nRF24L01 show_pa_level). This is calculated as:

    32 (nRF24L01 maximum) - 6 (MAC address) - 5 (required flags) - 3 (CRC checksum) = 18

    Use the helper function available() to detirmine if your payload can be transmit.

  2. the channels that BLE use are limited to the following three: 2.402 GHz, 2.426 GHz, and 2.480 GHz. We have provided a tuple of these specific channels for convenience (See BLE_FREQ and hop_channel()).

  3. crc is disabled in the nRF24L01 firmware because BLE specifications require 3 bytes (crc24_ble()), and the nRF24L01 firmware can only handle a maximum of 2. Thus, we have appended the required 3 bytes of CRC24 into the payload.

  4. address_length of BLE packet only uses 4 bytes, so we have set that accordingly.

  5. The auto_ack (automatic acknowledgment) feature of the nRF24L01 is useless when tranmitting to BLE devices, thus it is disabled as well as automatic re-transmit (arc) and custom ACK payloads (ack) features which both depend on the automatic acknowledgments feature.

  6. The dynamic_payloads feature of the nRF24L01 isn’t compatible with BLE specifications. Thus, we have disabled it.

  7. BLE specifications only allow using 1 Mbps RF data_rate, so that too has been hard coded.

  8. Only the “on data sent” (irq_ds) & “on data ready” (irq_dr) events will have an effect on the interrupt (IRQ) pin. The “on data fail” (irq_df) is never triggered because arc attribute is disabled.

helpers

swap_bits()

circuitpython_nrf24l01.fake_ble.swap_bits(original)[source]

This function reverses the bit order for a single byte.

Returns:An int containing the byte whose bits are reversed compared to the value passed to the original parameter.
Parameters:original (int) – This should be a single unsigned byte, meaning the parameters value can only range from 0 to 255.

reverse_bits()

circuitpython_nrf24l01.fake_ble.reverse_bits(original)[source]

This function reverses the bit order for an entire buffer protocol object.

Returns:A bytearray whose byte order remains the same, but each byte’s bit order is reversed.
Parameters:original (bytearray,bytes) – The original buffer whose bits are to be reversed.

chunk()

circuitpython_nrf24l01.fake_ble.chunk(buf, data_type=22)[source]

This function is used to pack data values into a block of data that make up part of the BLE payload per Bluetooth Core Specifications.

Parameters:
  • buf (bytearray,bytes) – The actual data contained in the block.
  • data_type (int) – The type of data contained in the chunk. This is a predefined number according to BLE specifications. The default value 0x16 describes all service data. 0xFF describes manufacturer information. Any other values are not applicable to BLE advertisements.

Important

This function is called internally by advertise(). To pack multiple data values into a single payload, use this function for each data value and pass a list or tuple of the returned results to advertise() (see example code in documentation about advertise() for more detail). Remember that broadcasting multiple data values may require the name be set to None and/or the show_pa_level be set to False for reasons about the payload size with BLE Limitations.

crc24_ble()

circuitpython_nrf24l01.fake_ble.crc24_ble(data, deg_poly=1627, init_val=5592405)[source]

This function calculates a checksum of various sized buffers.

This is exposed for convenience but should not be used for other buffer protocols that require big endian CRC24 format.

Parameters:
  • data (bytearray,bytes) – The buffer of data to be uncorrupted.
  • deg_poly (int) – A preset “degree polynomial” in which each bit represents a degree who’s coefficient is 1. BLE specfications require 0x00065b (default value).
  • init_val (int) – This will be the initial value that the checksum will use while shifting in the buffer data. BLE specfications require 0x555555 (default value).
Returns:

A 24-bit bytearray representing the checksum of the data (in proper little endian).

BLE_FREQ

circuitpython_nrf24l01.fake_ble.BLE_FREQ = (2, 26, 80)

The BLE channel number is different from the nRF channel number. This tuple contains the relative predefined channels used:

  • nRF channel 2 == BLE channel 37
  • nRF channel 26 == BLE channel 38
  • nRF channel 80 == BLE channel 39

FakeBLE class

class circuitpython_nrf24l01.fake_ble.FakeBLE(spi, csn, ce, spi_frequency=10000000)[source]

A class to implement BLE advertisements using the nRF24L01.

Per the limitations of this technique, only some of underlying RF24 functionality is available for configuration when implementing BLE transmissions. See the Available RF24 functionality for more details.

Parameters:
  • spi (SPI) –

    The object for the SPI bus that the nRF24L01 is connected to.

    Tip

    This object is meant to be shared amongst other driver classes (like adafruit_mcp3xxx.mcp3008 for example) that use the same SPI bus. Otherwise, multiple devices on the same SPI bus with different spi objects may produce errors or undesirable behavior.

  • csn (DigitalInOut) – The digital output pin that is connected to the nRF24L01’s CSN (Chip Select Not) pin. This is required.
  • ce (DigitalInOut) – The digital output pin that is connected to the nRF24L01’s CE (Chip Enable) pin. This is required.
  • spi_frequency (int) – Specify which SPI frequency (in Hz) to use on the SPI bus. This parameter only applies to the instantiated object and is made persistent via SPIDevice.

to_iphone

FakeBLE.to_iphone

A bool to specify if advertisements should be compatible with the iPhone. A value of False should still be compatible with other Apple devices. Testing with this attribute as False showed compatibility with a Mac desktop.

mac

FakeBLE.mac

This attribute returns a 6-byte buffer that is used as the arbitrary mac address of the BLE device being emulated. You can set this attribute using a 6-byte int or bytearray. If this is set to None, then a random 6-byte address is generated.

name

FakeBLE.name

The broadcasted BLE name of the nRF24L01. This is not required. In fact setting this attribute will subtract from the available payload length (in bytes). Set this attribute to None to disable advertising the device name.

Note

This information occupies (in the TX FIFO) an extra 2 bytes plus the length of the name set by this attribute.

show_pa_level

FakeBLE.show_pa_level

If this attribute is True, the payload will automatically include the nRF24L01’s pa_level in the advertisement. The default value of False will exclude this optional information.

Note

This information occupies (in the TX FIFO) an extra 3 bytes, and is really only useful for some applications to calculate proximity to the nRF24L01 transceiver.

hop_channel()

FakeBLE.hop_channel()[source]

Trigger an automatic change of BLE compliant channels.

whiten()

FakeBLE.whiten(data)[source]

Whitening the BLE packet data ensures there’s no long repeatition of bits.

This is done according to BLE specifications.

Parameters:data (bytearray,bytes) – The packet to whiten.
Returns:A bytearray of the data with the whitening algorythm applied.

Warning

This function uses the currently set BLE channel as a base case for the whitening coefficient. Do not call hop_channel() before using this function to de-whiten received payloads (which isn’t officially supported yet). Note that advertise() uses this function internally to prevent such improper usage.

available()

FakeBLE.available(hypothetical=b'')[source]

This function will calculates how much length (in bytes) is available in the next payload.

This is detirmined from the current state of name and show_pa_level attributes.

Parameters:hypothetical (bytearray,bytes) – Pass a potential chunk() of data to this parameter to calculate the resulting left over length in bytes. This parameter is optional.
Returns:An int representing the length of available bytes for the a single payload.

Available RF24 functionality

pa_level

FakeBLE.pa_level

See pa_level for more details.

channel

FakeBLE.channel

The only allowed channels are those contained in the BLE_FREQ tuple.

payload_length

FakeBLE.payload_length

This attribute is best left at 32 bytes for all BLE operations.

power

FakeBLE.power

See power for more details.

is_lna_enabled

FakeBLE.is_lna_enabled

See is_lna_enabled for more details.

is_plus_variant

FakeBLE.is_plus_variant

See is_plus_variant for more details.

interrupt_config()

FakeBLE.interrupt_config()[source]

See interrupt_config() for more details.

Warning

The irq_df attribute (and also this function’s data_fail parameter) is not implemented for BLE operations.

irq_ds

FakeBLE.irq_ds

See irq_ds for more details.

irq_dr

FakeBLE.irq_dr

See irq_dr for more details.

clear_status_flags()

FakeBLE.clear_status_flags()[source]

See clear_status_flags() for more details.

update()

FakeBLE.update()[source]

See update() for more details.

what_happened()

FakeBLE.what_happened()[source]

See what_happened() for more details.