Skip to content

Commit

Permalink
add ble_advertising, link to download
Browse files Browse the repository at this point in the history
  • Loading branch information
jmccand committed Nov 17, 2024
1 parent 374991c commit 973f7fe
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 16 deletions.
102 changes: 102 additions & 0 deletions docs/source/ble_advertising.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Helpers for generating BLE advertising payloads.

# A more fully-featured (and easier to use) version of this is implemented in
# aioble. This code is provided just as a basic example. See
# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble

from micropython import const
import struct
import bluetooth

# Advertising payloads are repeated packets of the following form:
# 1 byte data length (N + 1)
# 1 byte type (see constants below)
# N bytes type-specific data

_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)

_ADV_MAX_PAYLOAD = const(31)


# Generate a payload to be passed to gap_advertise(adv_data=...).
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
payload = bytearray()

def _append(adv_type, value):
nonlocal payload
payload += struct.pack("BB", len(value) + 1, adv_type) + value

_append(
_ADV_TYPE_FLAGS,
struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
)

if name:
_append(_ADV_TYPE_NAME, name)

if services:
for uuid in services:
b = bytes(uuid)
if len(b) == 2:
_append(_ADV_TYPE_UUID16_COMPLETE, b)
elif len(b) == 4:
_append(_ADV_TYPE_UUID32_COMPLETE, b)
elif len(b) == 16:
_append(_ADV_TYPE_UUID128_COMPLETE, b)

# See org.bluetooth.characteristic.gap.appearance.xml
if appearance:
_append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))

if len(payload) > _ADV_MAX_PAYLOAD:
raise ValueError("advertising payload too large")

return payload


def decode_field(payload, adv_type):
i = 0
result = []
while i + 1 < len(payload):
if payload[i + 1] == adv_type:
result.append(payload[i + 2 : i + payload[i] + 1])
i += 1 + payload[i]
return result


def decode_name(payload):
n = decode_field(payload, _ADV_TYPE_NAME)
return str(n[0], "utf-8") if n else ""


def decode_services(payload):
services = []
for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
services.append(bluetooth.UUID(u))
return services


def demo():
payload = advertising_payload(
name="micropython",
services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")],
)
print(payload)
print(decode_name(payload))
print(decode_services(payload))


if __name__ == "__main__":
demo()
17 changes: 1 addition & 16 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,7 @@ Your Arduino Nano RP2040 can run either C++ or MicroPython, but not both at the
`This guide <https://docs.arduino.cc/tutorials/nano-rp2040-connect/rp2040-openmv-setup/>`_ from Arduino will walk you through the process of "bootloading" the Nano RP2040 so that
you can run MicroPython code on it. After you have done this once, you should not need to do it again.

To use the NanoNav supplementary code, either download :download:`nanonav.py </../../nanonav.py>` to your project directory

Or copy the code below into a file called nanonav.py

.. raw:: html

<div style="max-height: 50vh; overflow-y: scroll;">

.. literalinclude:: /../../nanonav.py
:language: python
:linenos:

.. raw:: html

</div>

To use the NanoNav supplementary code, download :download:`nanonav.py </../../nanonav.py>` and :download:`ble_advertising.py </../../ble_advertising.py>` to your project directory. This is highly recommended!

.. _Workflow:

Expand Down

0 comments on commit 973f7fe

Please sign in to comment.