extmod/modbluetooth: Change scan result's "connectable" to "adv_type".

This commit changes the BLE _IRQ_SCAN_RESULT data from:

    addr_type, addr, connectable, rssi, adv_data

to:

    addr_type, addr, adv_type, rssi, adv_data

This allows _IRQ_SCAN_RESULT to handle all scan result types (not just
connectable and non-connectable passive scans), and to distinguish between
them using adv_type which is an integer taking values 0x00-0x04 per the BT
specification.

This is a breaking change to the API, albeit a very minor one: the existing
connectable value was a boolean and True now becomes 0x00, False becomes
0x02.

Documentation is updated and a test added.

Fixes #5738.
This commit is contained in:
Damien George 2020-03-10 11:45:03 +11:00
parent bd746a4630
commit dd0bc26e65
7 changed files with 55 additions and 42 deletions

View File

@ -93,7 +93,7 @@ Event Handling
conn_handle, attr_handle = data conn_handle, attr_handle = data
elif event == _IRQ_SCAN_RESULT: elif event == _IRQ_SCAN_RESULT:
# A single scan result. # A single scan result.
addr_type, addr, connectable, rssi, adv_data = data addr_type, addr, adv_type, rssi, adv_data = data
elif event == _IRQ_SCAN_COMPLETE: elif event == _IRQ_SCAN_COMPLETE:
# Scan duration finished or manually stopped. # Scan duration finished or manually stopped.
pass pass
@ -185,7 +185,15 @@ Observer Role (Scanner)
interval and window are 1.28 seconds and 11.25 milliseconds respectively interval and window are 1.28 seconds and 11.25 milliseconds respectively
(background scanning). (background scanning).
For each scan result, the ``_IRQ_SCAN_RESULT`` event will be raised. For each scan result the ``_IRQ_SCAN_RESULT`` event will be raised, with event
data ``(addr_type, addr, adv_type, rssi, adv_data)``. ``adv_type`` values correspond
to the Bluetooth Specification:
* 0x00 - ADV_IND - connectable and scannable undirected advertising
* 0x01 - ADV_DIRECT_IND - connectable directed advertising
* 0x02 - ADV_SCAN_IND - scannable undirected advertising
* 0x03 - ADV_NONCONN_IND - non-connectable undirected advertising
* 0x04 - SCAN_RSP - scan response
When scanning is stopped (either due to the duration finishing or when When scanning is stopped (either due to the duration finishing or when
explicitly stopped), the ``_IRQ_SCAN_COMPLETE`` event will be raised. explicitly stopped), the ``_IRQ_SCAN_COMPLETE`` event will be raised.

View File

@ -115,11 +115,9 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint16_t channel, uint8_
int8_t rssi = gap_event_advertising_report_get_rssi(packet); int8_t rssi = gap_event_advertising_report_get_rssi(packet);
uint8_t length = gap_event_advertising_report_get_data_length(packet); uint8_t length = gap_event_advertising_report_get_data_length(packet);
const uint8_t *data = gap_event_advertising_report_get_data(packet); const uint8_t *data = gap_event_advertising_report_get_data(packet);
bool connectable = adv_event_type == 0 || adv_event_type == 1; // Emit an event for all advertising types except SCAN_RSP.
if (adv_event_type <= 2) { if (adv_event_type < 4) {
mp_bluetooth_gap_on_scan_result(address_type, address, connectable, rssi, data, length); mp_bluetooth_gap_on_scan_result(address_type, address, adv_event_type, rssi, data, length);
} else if (adv_event_type == 4) {
// TODO: Scan response.
} }
} else if (event_type == HCI_EVENT_DISCONNECTION_COMPLETE) { } else if (event_type == HCI_EVENT_DISCONNECTION_COMPLETE) {
DEBUG_EVENT_printf(" --> hci disconnect complete\n"); DEBUG_EVENT_printf(" --> hci disconnect complete\n");

View File

@ -774,8 +774,8 @@ const mp_obj_module_t mp_module_ubluetooth = {
#include <stdio.h> #include <stdio.h>
STATIC void ringbuf_extract(ringbuf_t *ringbuf, mp_obj_tuple_t *data_tuple, size_t n_u16, size_t n_u8, mp_obj_str_t *bytes_addr, size_t n_b, size_t n_i8, mp_obj_bluetooth_uuid_t *uuid, mp_obj_str_t *bytes_data) { STATIC void ringbuf_extract(ringbuf_t *ringbuf, mp_obj_tuple_t *data_tuple, size_t n_u16, size_t n_u8, mp_obj_str_t *bytes_addr, size_t n_i8, mp_obj_bluetooth_uuid_t *uuid, mp_obj_str_t *bytes_data) {
assert(ringbuf_avail(ringbuf) >= n_u16 * 2 + n_u8 + (bytes_addr ? 6 : 0) + n_b + n_i8 + (uuid ? 1 : 0) + (bytes_data ? 1 : 0)); assert(ringbuf_avail(ringbuf) >= n_u16 * 2 + n_u8 + (bytes_addr ? 6 : 0) + n_i8 + (uuid ? 1 : 0) + (bytes_data ? 1 : 0));
int j = 0; int j = 0;
for (int i = 0; i < n_u16; ++i) { for (int i = 0; i < n_u16; ++i) {
@ -792,10 +792,7 @@ STATIC void ringbuf_extract(ringbuf_t *ringbuf, mp_obj_tuple_t *data_tuple, size
} }
data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_addr); data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_addr);
} }
if (n_b) { for (int i = 0; i < n_i8; ++i) {
data_tuple->items[j++] = mp_obj_new_bool(ringbuf_get(ringbuf));
}
if (n_i8) {
// Note the int8_t got packed into the ringbuf as a uint8_t. // Note the int8_t got packed into the ringbuf as a uint8_t.
data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT((int8_t)ringbuf_get(ringbuf)); data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT((int8_t)ringbuf_get(ringbuf));
} }
@ -843,32 +840,32 @@ STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) {
if (event == MP_BLUETOOTH_IRQ_CENTRAL_CONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_CONNECT || event == MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT) { if (event == MP_BLUETOOTH_IRQ_CENTRAL_CONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_CONNECT || event == MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT || event == MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT) {
// conn_handle, addr_type, addr // conn_handle, addr_type, addr
ringbuf_extract(&o->ringbuf, data_tuple, 1, 1, &o->irq_data_addr, 0, 0, NULL, NULL); ringbuf_extract(&o->ringbuf, data_tuple, 1, 1, &o->irq_data_addr, 0, NULL, NULL);
} else if (event == MP_BLUETOOTH_IRQ_GATTS_WRITE) { } else if (event == MP_BLUETOOTH_IRQ_GATTS_WRITE) {
// conn_handle, value_handle // conn_handle, value_handle
ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, NULL, NULL); ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, NULL);
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
} else if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT) { } else if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT) {
// addr_type, addr, connectable, rssi, adv_data // addr_type, addr, adv_type, rssi, adv_data
ringbuf_extract(&o->ringbuf, data_tuple, 0, 1, &o->irq_data_addr, 1, 1, NULL, &o->irq_data_data); ringbuf_extract(&o->ringbuf, data_tuple, 0, 1, &o->irq_data_addr, 2, NULL, &o->irq_data_data);
} else if (event == MP_BLUETOOTH_IRQ_SCAN_COMPLETE) { } else if (event == MP_BLUETOOTH_IRQ_SCAN_COMPLETE) {
// No params required. // No params required.
data_tuple->len = 0; data_tuple->len = 0;
} else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT) { } else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT) {
// conn_handle, start_handle, end_handle, uuid // conn_handle, start_handle, end_handle, uuid
ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, 0, &o->irq_data_uuid, NULL); ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, &o->irq_data_uuid, NULL);
} else if (event == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT) { } else if (event == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT) {
// conn_handle, def_handle, value_handle, properties, uuid // conn_handle, def_handle, value_handle, properties, uuid
ringbuf_extract(&o->ringbuf, data_tuple, 3, 1, NULL, 0, 0, &o->irq_data_uuid, NULL); ringbuf_extract(&o->ringbuf, data_tuple, 3, 1, NULL, 0, &o->irq_data_uuid, NULL);
} else if (event == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT) { } else if (event == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT) {
// conn_handle, handle, uuid // conn_handle, handle, uuid
ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, &o->irq_data_uuid, NULL); ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, &o->irq_data_uuid, NULL);
} else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_RESULT || event == MP_BLUETOOTH_IRQ_GATTC_NOTIFY || event == MP_BLUETOOTH_IRQ_GATTC_INDICATE) { } else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_RESULT || event == MP_BLUETOOTH_IRQ_GATTC_NOTIFY || event == MP_BLUETOOTH_IRQ_GATTC_INDICATE) {
// conn_handle, value_handle, data // conn_handle, value_handle, data
ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, 0, NULL, &o->irq_data_data); ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, &o->irq_data_data);
} else if (event == MP_BLUETOOTH_IRQ_GATTC_WRITE_STATUS) { } else if (event == MP_BLUETOOTH_IRQ_GATTC_WRITE_STATUS) {
// conn_handle, value_handle, status // conn_handle, value_handle, status
ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, 0, NULL, NULL); ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, NULL, NULL);
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
} }
@ -903,7 +900,7 @@ STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event) {
// Front of the queue is a scan result, remove it. // Front of the queue is a scan result, remove it.
// event, addr_type, addr, connectable, rssi // event, addr_type, addr, adv_type, rssi
int n = 2 + 1 + 6 + 1 + 1; int n = 2 + 1 + 6 + 1 + 1;
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
ringbuf_get(&o->ringbuf); ringbuf_get(&o->ringbuf);
@ -963,7 +960,7 @@ void mp_bluetooth_gap_on_scan_complete(void) {
MICROPY_PY_BLUETOOTH_EXIT MICROPY_PY_BLUETOOTH_EXIT
} }
void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, bool connectable, const int8_t rssi, const uint8_t *data, size_t data_len) { void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uint8_t adv_type, const int8_t rssi, const uint8_t *data, size_t data_len) {
MICROPY_PY_BLUETOOTH_ENTER MICROPY_PY_BLUETOOTH_ENTER
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
data_len = MIN(o->irq_data_data_alloc, data_len); data_len = MIN(o->irq_data_data_alloc, data_len);
@ -972,7 +969,8 @@ void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, boo
for (int i = 0; i < 6; ++i) { for (int i = 0; i < 6; ++i) {
ringbuf_put(&o->ringbuf, addr[i]); ringbuf_put(&o->ringbuf, addr[i]);
} }
ringbuf_put(&o->ringbuf, connectable ? 1 : 0); // The adv_type will get extracted as an int8_t but that's ok because valid values are 0x00-0x04.
ringbuf_put(&o->ringbuf, adv_type);
// Note conversion of int8_t rssi to uint8_t. Must un-convert on the way out. // Note conversion of int8_t rssi to uint8_t. Must un-convert on the way out.
ringbuf_put(&o->ringbuf, (uint8_t)rssi); ringbuf_put(&o->ringbuf, (uint8_t)rssi);
ringbuf_put(&o->ringbuf, data_len); ringbuf_put(&o->ringbuf, data_len);

View File

@ -248,7 +248,7 @@ bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_han
void mp_bluetooth_gap_on_scan_complete(void); void mp_bluetooth_gap_on_scan_complete(void);
// Notify modbluetooth of a scan result. // Notify modbluetooth of a scan result.
void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, bool connectable, const int8_t rssi, const uint8_t *data, size_t data_len); void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uint8_t adv_type, const int8_t rssi, const uint8_t *data, size_t data_len);
// Notify modbluetooth that a service was found (either by discover-all, or discover-by-uuid). // Notify modbluetooth that a service was found (either by discover-all, or discover-by-uuid).
void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid); void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid);

View File

@ -634,16 +634,9 @@ STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) {
return 0; return 0;
} }
if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND) {
bool connectable = event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND;
uint8_t addr[6]; uint8_t addr[6];
reverse_addr_byte_order(addr, event->disc.addr.val); reverse_addr_byte_order(addr, event->disc.addr.val);
mp_bluetooth_gap_on_scan_result(event->disc.addr.type, addr, connectable, event->disc.rssi, event->disc.data, event->disc.length_data); mp_bluetooth_gap_on_scan_result(event->disc.addr.type, addr, event->disc.event_type, event->disc.rssi, event->disc.data, event->disc.length_data);
} else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
// TODO
} else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND) {
// TODO
}
return 0; return 0;
} }

View File

@ -11,34 +11,48 @@ ADV_TIME_S = 3
def instance0(): def instance0():
multitest.globals(BDADDR=ble.config("mac")) multitest.globals(BDADDR=ble.config("mac"))
print("gap_advertise(20_000)")
ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY")
multitest.next() multitest.next()
print("gap_advertise(100_000, connectable=False)")
ble.gap_advertise(100_000, b"\x02\x01\x06\x04\xffMPY", connectable=False)
time.sleep(ADV_TIME_S) time.sleep(ADV_TIME_S)
print("gap_advertise(20_000, connectable=True)")
ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY", connectable=True)
time.sleep(ADV_TIME_S)
print("gap_advertise(None)") print("gap_advertise(None)")
ble.gap_advertise(None) ble.gap_advertise(None)
ble.active(0) ble.active(0)
def instance1(): def instance1():
multitest.next() multitest.next()
finished = False finished = False
adv_types = set()
adv_data = None adv_data = None
def irq(ev, data): def irq(ev, data):
nonlocal finished, adv_data nonlocal finished, adv_types, adv_data
if ev == _IRQ_SCAN_RESULT: if ev == _IRQ_SCAN_RESULT:
if data[1] == BDADDR: if data[1] == BDADDR:
adv_types.add(data[2])
if adv_data is None:
adv_data = bytes(data[4]) adv_data = bytes(data[4])
else:
if adv_data != data[4]:
adv_data = "MISMATCH"
elif ev == _IRQ_SCAN_COMPLETE: elif ev == _IRQ_SCAN_COMPLETE:
finished = True finished = True
ble.config(rxbuf=2000) ble.config(rxbuf=2000)
ble.irq(irq) ble.irq(irq)
ble.gap_scan(ADV_TIME_S * 1000, 10000, 10000) ble.gap_scan(2 * ADV_TIME_S * 1000, 10000, 10000)
while not finished: while not finished:
machine.idle() machine.idle()
ble.active(0) ble.active(0)
print("adv_types:", sorted(adv_types))
print("adv_data:", adv_data) print("adv_data:", adv_data)

View File

@ -1,5 +1,7 @@
--- instance0 --- --- instance0 ---
gap_advertise(20_000) gap_advertise(100_000, connectable=False)
gap_advertise(20_000, connectable=True)
gap_advertise(None) gap_advertise(None)
--- instance1 --- --- instance1 ---
adv_types: [0, 2]
adv_data: b'\x02\x01\x06\x04\xffMPY' adv_data: b'\x02\x01\x06\x04\xffMPY'