Skip to content

Commit 81f2162

Browse files
committed
extmod/modbluetooth: Change module-owned bytes objects to memoryview.
A read-only memoryview object is a better representation of the data, which is owned by the ubluetooth module and may change between calls to the user's irq callback function. Signed-off-by: Damien George <[email protected]>
1 parent 50e34f9 commit 81f2162

File tree

5 files changed

+31
-27
lines changed

5 files changed

+31
-27
lines changed

docs/library/ubluetooth.rst

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,22 @@ Event Handling
8888
arguments, ``event`` (which will be one of the codes below) and ``data``
8989
(which is an event-specific tuple of values).
9090

91-
**Note:** the ``addr``, ``adv_data``, ``char_data``, ``notify_data``, and
92-
``uuid`` entries in the tuples are references to data managed by the
93-
:mod:`ubluetooth` module (i.e. the same instance will be re-used across
94-
multiple calls to the event handler). If your program wants to use this
95-
data outside of the handler, then it must copy them first, e.g. by using
96-
``bytes(addr)`` or ``bluetooth.UUID(uuid)``.
91+
**Note:** As an optimisation to prevent unnecessary allocations, the ``addr``,
92+
``adv_data``, ``char_data``, ``notify_data``, and ``uuid`` entries in the
93+
tuples are read-only memoryview instances pointing to ubluetooth's internal
94+
ringbuffer, and are only valid during the invocation of the IRQ handler
95+
function. If your program needs to save one of these values to access after
96+
the IRQ handler has returned (e.g. by saving it in a class instance or global
97+
variable), then it needs to take a copy of the data, either by using ``bytes()``
98+
or ``bluetooth.UUID()``, like this::
99+
100+
connected_addr = bytes(addr) # equivalently: adv_data, char_data, or notify_data
101+
matched_uuid = bluetooth.UUID(uuid)
102+
103+
For example, the IRQ handler for a scan result might inspect the ``adv_data``
104+
to decide if it's the correct device, and only then copy the address data to be
105+
used elsewhere in the program. And to print data from within the IRQ handler,
106+
``print(bytes(addr))`` will be needed.
97107

98108
An event handler showing all possible events::
99109

extmod/modbluetooth.c

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#include "py/mphal.h"
3333
#include "py/obj.h"
3434
#include "py/objarray.h"
35-
#include "py/objstr.h"
3635
#include "py/qstr.h"
3736
#include "py/runtime.h"
3837
#include "extmod/modbluetooth.h"
@@ -62,9 +61,8 @@ typedef struct {
6261
mp_obj_t irq_data_tuple;
6362
uint8_t irq_data_addr_bytes[6];
6463
uint16_t irq_data_data_alloc;
65-
uint8_t *irq_data_data_bytes;
66-
mp_obj_str_t irq_data_addr;
67-
mp_obj_str_t irq_data_data;
64+
mp_obj_array_t irq_data_addr;
65+
mp_obj_array_t irq_data_data;
6866
mp_obj_bluetooth_uuid_t irq_data_uuid;
6967
ringbuf_t ringbuf;
7068
#if MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK
@@ -262,11 +260,9 @@ STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args,
262260
#endif
263261

264262
// Pre-allocated buffers for address, payload and uuid.
265-
o->irq_data_addr.base.type = &mp_type_bytes;
266-
o->irq_data_addr.data = o->irq_data_addr_bytes;
263+
mp_obj_memoryview_init(&o->irq_data_addr, 'B', 0, 0, o->irq_data_addr_bytes);
267264
o->irq_data_data_alloc = MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(MICROPY_PY_BLUETOOTH_RINGBUF_SIZE);
268-
o->irq_data_data.base.type = &mp_type_bytes;
269-
o->irq_data_data.data = m_new(uint8_t, o->irq_data_data_alloc);
265+
mp_obj_memoryview_init(&o->irq_data_data, 'B', 0, 0, m_new(uint8_t, o->irq_data_data_alloc));
270266
o->irq_data_uuid.base.type = &bluetooth_uuid_type;
271267

272268
// Allocate the default ringbuf.
@@ -352,7 +348,7 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
352348
// Get old buffer sizes and pointers
353349
uint8_t *old_ringbuf_buf = self->ringbuf.buf;
354350
size_t old_ringbuf_alloc = self->ringbuf.size;
355-
uint8_t *old_irq_data_buf = (uint8_t *)self->irq_data_data.data;
351+
uint8_t *old_irq_data_buf = (uint8_t *)self->irq_data_data.items;
356352
size_t old_irq_data_alloc = self->irq_data_data_alloc;
357353

358354
// Atomically update the ringbuf and irq data
@@ -362,7 +358,7 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
362358
self->ringbuf.iget = 0;
363359
self->ringbuf.iput = 0;
364360
self->irq_data_data_alloc = irq_data_alloc;
365-
self->irq_data_data.data = irq_data;
361+
self->irq_data_data.items = irq_data;
366362
MICROPY_PY_BLUETOOTH_EXIT
367363

368364
// Free old buffers
@@ -850,7 +846,7 @@ const mp_obj_module_t mp_module_ubluetooth = {
850846

851847
#include <stdio.h>
852848

853-
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) {
849+
STATIC void ringbuf_extract(ringbuf_t *ringbuf, mp_obj_tuple_t *data_tuple, size_t n_u16, size_t n_u8, mp_obj_array_t *bytes_addr, size_t n_i8, mp_obj_bluetooth_uuid_t *uuid, mp_obj_array_t *bytes_data) {
854850
assert(ringbuf_avail(ringbuf) >= n_u16 * 2 + n_u8 + (bytes_addr ? 6 : 0) + n_i8 + (uuid ? 1 : 0) + (bytes_data ? 1 : 0));
855851
size_t j = 0;
856852

@@ -863,8 +859,7 @@ STATIC void ringbuf_extract(ringbuf_t *ringbuf, mp_obj_tuple_t *data_tuple, size
863859
if (bytes_addr) {
864860
bytes_addr->len = 6;
865861
for (size_t i = 0; i < bytes_addr->len; ++i) {
866-
// cast away const, this is actually bt->irq_addr_bytes.
867-
((uint8_t *)bytes_addr->data)[i] = ringbuf_get(ringbuf);
862+
((uint8_t *)bytes_addr->items)[i] = ringbuf_get(ringbuf);
868863
}
869864
data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_addr);
870865
}
@@ -880,12 +875,11 @@ STATIC void ringbuf_extract(ringbuf_t *ringbuf, mp_obj_tuple_t *data_tuple, size
880875
#endif
881876
// The code that enqueues into the ringbuf should ensure that it doesn't
882877
// put more than bt->irq_data_data_alloc bytes into the ringbuf, because
883-
// that's what's available here in bt->irq_data_bytes.
878+
// that's what's available here.
884879
if (bytes_data) {
885880
bytes_data->len = ringbuf_get16(ringbuf);
886881
for (size_t i = 0; i < bytes_data->len; ++i) {
887-
// cast away const, this is actually bt->irq_data_bytes.
888-
((uint8_t *)bytes_data->data)[i] = ringbuf_get(ringbuf);
882+
((uint8_t *)bytes_data->items)[i] = ringbuf_get(ringbuf);
889883
}
890884
data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_data);
891885
}

tests/multi_bluetooth/ble_characteristic.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ def irq(event, data):
5454
print("_IRQ_GATTC_CHARACTERISTIC_RESULT", data[-1])
5555
value_handle = data[2]
5656
elif event == _IRQ_GATTC_READ_RESULT:
57-
print("_IRQ_GATTC_READ_RESULT", data[-1])
57+
print("_IRQ_GATTC_READ_RESULT", bytes(data[-1]))
5858
elif event == _IRQ_GATTC_READ_DONE:
5959
print("_IRQ_GATTC_READ_DONE", data[-1])
6060
elif event == _IRQ_GATTC_WRITE_DONE:
6161
print("_IRQ_GATTC_WRITE_DONE", data[-1])
6262
elif event == _IRQ_GATTC_NOTIFY:
63-
print("_IRQ_GATTC_NOTIFY", data[-1])
63+
print("_IRQ_GATTC_NOTIFY", bytes(data[-1]))
6464
elif event == _IRQ_GATTC_INDICATE:
65-
print("_IRQ_GATTC_INDICATE", data[-1])
65+
print("_IRQ_GATTC_INDICATE", bytes(data[-1]))
6666
elif event == _IRQ_GATTS_INDICATE_DONE:
6767
print("_IRQ_GATTS_INDICATE_DONE", data[-1])
6868

tests/multi_bluetooth/ble_gap_device_name.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def irq(event, data):
3636
print("_IRQ_GATTC_CHARACTERISTIC_RESULT", data[-1])
3737
value_handle = data[2]
3838
elif event == _IRQ_GATTC_READ_RESULT:
39-
print("_IRQ_GATTC_READ_RESULT", data[-1])
39+
print("_IRQ_GATTC_READ_RESULT", bytes(data[-1]))
4040

4141
if waiting_event is not None:
4242
if isinstance(waiting_event, int) and event == waiting_event:

tests/multi_bluetooth/ble_gatt_data_transfer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def irq(event, data):
6767
elif event == _IRQ_GATTC_WRITE_DONE:
6868
print("_IRQ_GATTC_WRITE_DONE", data[-1])
6969
elif event == _IRQ_GATTC_NOTIFY:
70-
print("_IRQ_GATTC_NOTIFY", data[-1])
70+
print("_IRQ_GATTC_NOTIFY", bytes(data[-1]))
7171

7272
if waiting_event is not None:
7373
if (isinstance(waiting_event, int) and event == waiting_event) or (

0 commit comments

Comments
 (0)