However, services for advertising packets that have UUID16 are decoded.
For devices that have UUID128 services list are returned empty.
In the code below first the example payload is generated and decoded correctly.
Then I try to decode payloads that I captured during scanning.
The output is only a empty list.
Is this a bug or am doing something wrong?
Code: Select all
bytearray(b'\x02\x01\x06\x0c\tmicropython\x03\x03\x1a\x18\x11\x07\x9e\xca\xdc$\x0e\xe5\xa9\xe0\x93\xf3\xa3\xb5\x01\x00@n\x03\x19\x00\x00')
micropython
[UUID16(0x181a), UUID128('6e400001-b5a3-f393-e0a9-e50e24dcca9e')]
b'02010613ff4c000c0e083c0e80d244810d6c8dac99bf7e'
[]
b'02010613ff4c000c0e08440ec5aab68919bb7974850b98'
[]
Code: Select all
# Helpers for generating BLE advertising payloads.
from micropython import const
import struct
import bluetooth
import binascii
# 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)
# 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
_append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
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():
#example Payload with UUID16 service
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))
#1 capture payload
payload = bytearray(b'\x02\x01\x06\x13\xffL\x00\x0c\x0e\x08<\x0e\x80\xd2D\x81\rl\x8d\xac\x99\xbf~')
print(binascii.hexlify(payload))
print(decode_name(payload))
print(decode_services(payload))
#2 capture payload
payload = bytearray(b'\x02\x01\x06\x13\xffL\x00\x0c\x0e\x08D\x0e\xc5\xaa\xb6\x89\x19\xbbyt\x85\x0b\x98')
print(binascii.hexlify(payload))
print(decode_name(payload))
print(decode_services(payload))
if __name__ == "__main__":
demo()
EDIT: I am not sure if the UUID length is really causing this behaviour or if it is something else