1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2018 Ayke van Laethem
7  * Copyright (c) 2019-2020 Jim Mussared
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27 
28 #include "py/binary.h"
29 #include "py/gc.h"
30 #include "py/misc.h"
31 #include "py/mperrno.h"
32 #include "py/mphal.h"
33 #include "py/obj.h"
34 #include "py/objarray.h"
35 #include "py/qstr.h"
36 #include "py/runtime.h"
37 #include "extmod/modbluetooth.h"
38 #include <string.h>
39 
40 #if MICROPY_PY_BLUETOOTH
41 
42 #if !MICROPY_ENABLE_SCHEDULER
43 #error modbluetooth requires MICROPY_ENABLE_SCHEDULER
44 #endif
45 
46 #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS && !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
47 #error l2cap channels require synchronous modbluetooth events
48 #endif
49 
50 #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING && !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
51 #error pairing and bonding require synchronous modbluetooth events
52 #endif
53 
54 #define MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS 2000
55 
56 #define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN 5
57 
58 #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
59 // This formula is intended to allow queuing the data of a large characteristic
60 // while still leaving room for a couple of normal (small, fixed size) events.
61 #define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(ringbuf_size) (MAX((int)((ringbuf_size) / 2), (int)(ringbuf_size) - 64))
62 #endif
63 
64 // bluetooth.BLE type. This is currently a singleton, however in the future
65 // this could allow having multiple BLE interfaces on different UARTs.
66 typedef struct {
67     mp_obj_base_t base;
68     mp_obj_t irq_handler;
69     #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
70     bool irq_scheduled;
71     mp_obj_t irq_data_tuple;
72     uint8_t irq_data_addr_bytes[6];
73     uint16_t irq_data_data_alloc;
74     mp_obj_array_t irq_data_addr;
75     mp_obj_array_t irq_data_data;
76     mp_obj_bluetooth_uuid_t irq_data_uuid;
77     ringbuf_t ringbuf;
78     #endif
79 } mp_obj_bluetooth_ble_t;
80 
81 STATIC const mp_obj_type_t mp_type_bluetooth_ble;
82 
83 // TODO: this seems like it could be generic?
bluetooth_handle_errno(int err)84 STATIC mp_obj_t bluetooth_handle_errno(int err) {
85     if (err != 0) {
86         mp_raise_OSError(err);
87     }
88     return mp_const_none;
89 }
90 
91 // ----------------------------------------------------------------------------
92 // UUID object
93 // ----------------------------------------------------------------------------
94 
bluetooth_uuid_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * all_args)95 STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
96     (void)type;
97 
98     mp_arg_check_num(n_args, n_kw, 1, 1, false);
99 
100     mp_obj_bluetooth_uuid_t *self = m_new_obj(mp_obj_bluetooth_uuid_t);
101     self->base.type = &mp_type_bluetooth_uuid;
102 
103     if (mp_obj_is_int(all_args[0])) {
104         self->type = MP_BLUETOOTH_UUID_TYPE_16;
105         mp_int_t value = mp_obj_get_int(all_args[0]);
106         if (value > 65535) {
107             mp_raise_ValueError(MP_ERROR_TEXT("invalid UUID"));
108         }
109         self->data[0] = value & 0xff;
110         self->data[1] = (value >> 8) & 0xff;
111     } else {
112         mp_buffer_info_t uuid_bufinfo = {0};
113         mp_get_buffer_raise(all_args[0], &uuid_bufinfo, MP_BUFFER_READ);
114         if (uuid_bufinfo.len == 2 || uuid_bufinfo.len == 4 || uuid_bufinfo.len == 16) {
115             // Bytes data -- infer UUID type from length and copy data.
116             self->type = uuid_bufinfo.len;
117             memcpy(self->data, uuid_bufinfo.buf, self->type);
118         } else {
119             // Assume UUID string (e.g. '6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
120             self->type = MP_BLUETOOTH_UUID_TYPE_128;
121             int uuid_i = 32;
122             for (size_t i = 0; i < uuid_bufinfo.len; i++) {
123                 char c = ((char *)uuid_bufinfo.buf)[i];
124                 if (c == '-') {
125                     continue;
126                 }
127                 if (!unichar_isxdigit(c)) {
128                     mp_raise_ValueError(MP_ERROR_TEXT("invalid char in UUID"));
129                 }
130                 c = unichar_xdigit_value(c);
131                 uuid_i--;
132                 if (uuid_i < 0) {
133                     mp_raise_ValueError(MP_ERROR_TEXT("UUID too long"));
134                 }
135                 if (uuid_i % 2 == 0) {
136                     // lower nibble
137                     self->data[uuid_i / 2] |= c;
138                 } else {
139                     // upper nibble
140                     self->data[uuid_i / 2] = c << 4;
141                 }
142             }
143             if (uuid_i > 0) {
144                 mp_raise_ValueError(MP_ERROR_TEXT("UUID too short"));
145             }
146         }
147     }
148 
149     return MP_OBJ_FROM_PTR(self);
150 }
151 
bluetooth_uuid_unary_op(mp_unary_op_t op,mp_obj_t self_in)152 STATIC mp_obj_t bluetooth_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
153     mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in);
154     switch (op) {
155         case MP_UNARY_OP_HASH: {
156             // Use the QSTR hash function.
157             return MP_OBJ_NEW_SMALL_INT(qstr_compute_hash(self->data, self->type));
158         }
159         default:
160             return MP_OBJ_NULL;      // op not supported
161     }
162 }
163 
bluetooth_uuid_binary_op(mp_binary_op_t op,mp_obj_t lhs_in,mp_obj_t rhs_in)164 STATIC mp_obj_t bluetooth_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
165     if (!mp_obj_is_type(rhs_in, &mp_type_bluetooth_uuid)) {
166         return MP_OBJ_NULL;
167     }
168 
169     mp_obj_bluetooth_uuid_t *lhs = MP_OBJ_TO_PTR(lhs_in);
170     mp_obj_bluetooth_uuid_t *rhs = MP_OBJ_TO_PTR(rhs_in);
171     switch (op) {
172         case MP_BINARY_OP_EQUAL:
173         case MP_BINARY_OP_LESS:
174         case MP_BINARY_OP_LESS_EQUAL:
175         case MP_BINARY_OP_MORE:
176         case MP_BINARY_OP_MORE_EQUAL:
177             if (lhs->type == rhs->type) {
178                 return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs->data, lhs->type, rhs->data, rhs->type));
179             } else {
180                 return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(lhs->type), MP_OBJ_NEW_SMALL_INT(rhs->type));
181             }
182 
183         default:
184             return MP_OBJ_NULL; // op not supported
185     }
186 }
187 
bluetooth_uuid_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)188 STATIC void bluetooth_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
189     (void)kind;
190 
191     mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in);
192     mp_printf(print, "UUID(%s", self->type <= 4 ? "0x" : "'");
193     for (int i = 0; i < self->type; ++i) {
194         if (i == 4 || i == 6 || i == 8 || i == 10) {
195             mp_printf(print, "-");
196         }
197         mp_printf(print, "%02x", self->data[self->type - 1 - i]);
198     }
199     if (self->type == MP_BLUETOOTH_UUID_TYPE_128) {
200         mp_printf(print, "'");
201     }
202     mp_printf(print, ")");
203 }
204 
bluetooth_uuid_get_buffer(mp_obj_t self_in,mp_buffer_info_t * bufinfo,mp_uint_t flags)205 STATIC mp_int_t bluetooth_uuid_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
206     mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in);
207 
208     if (flags != MP_BUFFER_READ) {
209         return 1;
210     }
211 
212     bufinfo->buf = self->data;
213     bufinfo->len = self->type;
214     bufinfo->typecode = 'B';
215     return 0;
216 }
217 
218 #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS && MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
ringbuf_put_uuid(ringbuf_t * ringbuf,mp_obj_bluetooth_uuid_t * uuid)219 STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
220     assert(ringbuf_free(ringbuf) >= (size_t)uuid->type + 1);
221     ringbuf_put(ringbuf, uuid->type);
222     for (int i = 0; i < uuid->type; ++i) {
223         ringbuf_put(ringbuf, uuid->data[i]);
224     }
225 }
226 
ringbuf_get_uuid(ringbuf_t * ringbuf,mp_obj_bluetooth_uuid_t * uuid)227 STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
228     assert(ringbuf_avail(ringbuf) >= 1);
229     uuid->type = ringbuf_get(ringbuf);
230     assert(ringbuf_avail(ringbuf) >= uuid->type);
231     for (int i = 0; i < uuid->type; ++i) {
232         uuid->data[i] = ringbuf_get(ringbuf);
233     }
234 }
235 #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
236 
237 const mp_obj_type_t mp_type_bluetooth_uuid = {
238     { &mp_type_type },
239     .name = MP_QSTR_UUID,
240     .make_new = bluetooth_uuid_make_new,
241     .unary_op = bluetooth_uuid_unary_op,
242     .binary_op = bluetooth_uuid_binary_op,
243     .locals_dict = NULL,
244     .print = bluetooth_uuid_print,
245     .buffer_p = { .get_buffer = bluetooth_uuid_get_buffer },
246 };
247 
248 // ----------------------------------------------------------------------------
249 // Bluetooth object: General
250 // ----------------------------------------------------------------------------
251 
bluetooth_ble_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * all_args)252 STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
253     (void)type;
254     (void)n_args;
255     (void)n_kw;
256     (void)all_args;
257     if (MP_STATE_VM(bluetooth) == MP_OBJ_NULL) {
258         mp_obj_bluetooth_ble_t *o = m_new0(mp_obj_bluetooth_ble_t, 1);
259         o->base.type = &mp_type_bluetooth_ble;
260 
261         o->irq_handler = mp_const_none;
262 
263         #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
264         // Pre-allocate the event data tuple to prevent needing to allocate in the IRQ handler.
265         o->irq_data_tuple = mp_obj_new_tuple(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN, NULL);
266 
267         // Pre-allocated buffers for address, payload and uuid.
268         mp_obj_memoryview_init(&o->irq_data_addr, 'B', 0, 0, o->irq_data_addr_bytes);
269         o->irq_data_data_alloc = MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(MICROPY_PY_BLUETOOTH_RINGBUF_SIZE);
270         mp_obj_memoryview_init(&o->irq_data_data, 'B', 0, 0, m_new(uint8_t, o->irq_data_data_alloc));
271         o->irq_data_uuid.base.type = &mp_type_bluetooth_uuid;
272 
273         // Allocate the default ringbuf.
274         ringbuf_alloc(&o->ringbuf, MICROPY_PY_BLUETOOTH_RINGBUF_SIZE);
275         #endif
276 
277         MP_STATE_VM(bluetooth) = MP_OBJ_FROM_PTR(o);
278     }
279     return MP_STATE_VM(bluetooth);
280 }
281 
bluetooth_ble_active(size_t n_args,const mp_obj_t * args)282 STATIC mp_obj_t bluetooth_ble_active(size_t n_args, const mp_obj_t *args) {
283     if (n_args == 2) {
284         // Boolean enable/disable argument supplied, set current state.
285         if (mp_obj_is_true(args[1])) {
286             int err = mp_bluetooth_init();
287             bluetooth_handle_errno(err);
288         } else {
289             mp_bluetooth_deinit();
290         }
291     }
292     // Return current state.
293     return mp_obj_new_bool(mp_bluetooth_is_active());
294 }
295 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_active_obj, 1, 2, bluetooth_ble_active);
296 
bluetooth_ble_config(size_t n_args,const mp_obj_t * args,mp_map_t * kwargs)297 STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
298     if (kwargs->used == 0) {
299         // Get config value
300         if (n_args != 2) {
301             mp_raise_TypeError(MP_ERROR_TEXT("must query one param"));
302         }
303 
304         switch (mp_obj_str_get_qstr(args[1])) {
305             case MP_QSTR_gap_name: {
306                 const uint8_t *buf;
307                 size_t len = mp_bluetooth_gap_get_device_name(&buf);
308                 return mp_obj_new_bytes(buf, len);
309             }
310             case MP_QSTR_mac: {
311                 uint8_t addr_type;
312                 uint8_t addr[6];
313                 mp_bluetooth_get_current_address(&addr_type, addr);
314                 mp_obj_t items[] = { MP_OBJ_NEW_SMALL_INT(addr_type), mp_obj_new_bytes(addr, MP_ARRAY_SIZE(addr)) };
315                 return mp_obj_new_tuple(2, items);
316             }
317             #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
318             case MP_QSTR_rxbuf: {
319                 mp_obj_bluetooth_ble_t *self = MP_OBJ_TO_PTR(args[0]);
320                 return mp_obj_new_int(self->ringbuf.size);
321             }
322             #endif
323             case MP_QSTR_mtu:
324                 return mp_obj_new_int(mp_bluetooth_get_preferred_mtu());
325             default:
326                 mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
327         }
328     } else {
329         // Set config value(s)
330         if (n_args != 1) {
331             mp_raise_TypeError(MP_ERROR_TEXT("can't specify pos and kw args"));
332         }
333 
334         for (size_t i = 0; i < kwargs->alloc; ++i) {
335             if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
336                 mp_map_elem_t *e = &kwargs->table[i];
337                 switch (mp_obj_str_get_qstr(e->key)) {
338                     case MP_QSTR_gap_name: {
339                         mp_buffer_info_t bufinfo;
340                         mp_get_buffer_raise(e->value, &bufinfo, MP_BUFFER_READ);
341                         bluetooth_handle_errno(mp_bluetooth_gap_set_device_name(bufinfo.buf, bufinfo.len));
342                         break;
343                     }
344                     #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
345                     case MP_QSTR_rxbuf: {
346                         // Determine new buffer sizes
347                         mp_int_t ringbuf_alloc = mp_obj_get_int(e->value);
348                         if (ringbuf_alloc < 16 || ringbuf_alloc > 0xffff) {
349                             mp_raise_ValueError(NULL);
350                         }
351                         size_t irq_data_alloc = MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(ringbuf_alloc);
352 
353                         // Allocate new buffers
354                         uint8_t *ringbuf = m_new(uint8_t, ringbuf_alloc);
355                         uint8_t *irq_data = m_new(uint8_t, irq_data_alloc);
356 
357                         // Get old buffer sizes and pointers
358                         mp_obj_bluetooth_ble_t *self = MP_OBJ_TO_PTR(args[0]);
359                         uint8_t *old_ringbuf_buf = self->ringbuf.buf;
360                         size_t old_ringbuf_alloc = self->ringbuf.size;
361                         uint8_t *old_irq_data_buf = (uint8_t *)self->irq_data_data.items;
362                         size_t old_irq_data_alloc = self->irq_data_data_alloc;
363 
364                         // Atomically update the ringbuf and irq data
365                         MICROPY_PY_BLUETOOTH_ENTER
366                         self->ringbuf.size = ringbuf_alloc;
367                         self->ringbuf.buf = ringbuf;
368                         self->ringbuf.iget = 0;
369                         self->ringbuf.iput = 0;
370                         self->irq_data_data_alloc = irq_data_alloc;
371                         self->irq_data_data.items = irq_data;
372                         MICROPY_PY_BLUETOOTH_EXIT
373 
374                         // Free old buffers
375                         m_del(uint8_t, old_ringbuf_buf, old_ringbuf_alloc);
376                         m_del(uint8_t, old_irq_data_buf, old_irq_data_alloc);
377                         break;
378                     }
379                     #endif
380                     case MP_QSTR_mtu: {
381                         mp_int_t mtu = mp_obj_get_int(e->value);
382                         bluetooth_handle_errno(mp_bluetooth_set_preferred_mtu(mtu));
383                         break;
384                     }
385                     case MP_QSTR_addr_mode: {
386                         mp_int_t addr_mode = mp_obj_get_int(e->value);
387                         mp_bluetooth_set_address_mode(addr_mode);
388                         break;
389                     }
390                     #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
391                     case MP_QSTR_bond: {
392                         bool bonding_enabled = mp_obj_is_true(e->value);
393                         mp_bluetooth_set_bonding(bonding_enabled);
394                         break;
395                     }
396                     case MP_QSTR_mitm: {
397                         bool mitm_protection = mp_obj_is_true(e->value);
398                         mp_bluetooth_set_mitm_protection(mitm_protection);
399                         break;
400                     }
401                     case MP_QSTR_io: {
402                         mp_int_t io_capability = mp_obj_get_int(e->value);
403                         mp_bluetooth_set_io_capability(io_capability);
404                         break;
405                     }
406                     case MP_QSTR_le_secure: {
407                         bool le_secure_required = mp_obj_is_true(e->value);
408                         mp_bluetooth_set_le_secure(le_secure_required);
409                         break;
410                     }
411                     #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
412                     default:
413                         mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
414                 }
415             }
416         }
417 
418         return mp_const_none;
419     }
420 }
421 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_config_obj, 1, bluetooth_ble_config);
422 
bluetooth_ble_irq(mp_obj_t self_in,mp_obj_t handler_in)423 STATIC mp_obj_t bluetooth_ble_irq(mp_obj_t self_in, mp_obj_t handler_in) {
424     (void)self_in;
425     if (handler_in != mp_const_none && !mp_obj_is_callable(handler_in)) {
426         mp_raise_ValueError(MP_ERROR_TEXT("invalid handler"));
427     }
428 
429     // Update the callback.
430     MICROPY_PY_BLUETOOTH_ENTER
431     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
432     o->irq_handler = handler_in;
433     MICROPY_PY_BLUETOOTH_EXIT
434 
435     return mp_const_none;
436 }
437 STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_irq_obj, bluetooth_ble_irq);
438 
439 // ----------------------------------------------------------------------------
440 // Bluetooth object: GAP
441 // ----------------------------------------------------------------------------
442 
bluetooth_ble_gap_advertise(size_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)443 STATIC mp_obj_t bluetooth_ble_gap_advertise(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
444     enum { ARG_interval_us, ARG_adv_data, ARG_resp_data, ARG_connectable };
445     static const mp_arg_t allowed_args[] = {
446         { MP_QSTR_interval_us, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(500000)} },
447         { MP_QSTR_adv_data, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
448         { MP_QSTR_resp_data, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
449         { MP_QSTR_connectable, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_TRUE} },
450     };
451     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
452     mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
453 
454     if (args[ARG_interval_us].u_obj == mp_const_none) {
455         mp_bluetooth_gap_advertise_stop();
456         return mp_const_none;
457     }
458 
459     mp_int_t interval_us = mp_obj_get_int(args[ARG_interval_us].u_obj);
460     bool connectable = mp_obj_is_true(args[ARG_connectable].u_obj);
461 
462     mp_buffer_info_t adv_bufinfo = {0};
463     if (args[ARG_adv_data].u_obj != mp_const_none) {
464         mp_get_buffer_raise(args[ARG_adv_data].u_obj, &adv_bufinfo, MP_BUFFER_READ);
465     }
466 
467     mp_buffer_info_t resp_bufinfo = {0};
468     if (args[ARG_resp_data].u_obj != mp_const_none) {
469         mp_get_buffer_raise(args[ARG_resp_data].u_obj, &resp_bufinfo, MP_BUFFER_READ);
470     }
471 
472     return bluetooth_handle_errno(mp_bluetooth_gap_advertise_start(connectable, interval_us, adv_bufinfo.buf, adv_bufinfo.len, resp_bufinfo.buf, resp_bufinfo.len));
473 }
474 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_gap_advertise_obj, 1, bluetooth_ble_gap_advertise);
475 
bluetooth_gatts_register_service(mp_obj_t uuid_in,mp_obj_t characteristics_in,uint16_t ** handles,size_t * num_handles)476 STATIC int bluetooth_gatts_register_service(mp_obj_t uuid_in, mp_obj_t characteristics_in, uint16_t **handles, size_t *num_handles) {
477     if (!mp_obj_is_type(uuid_in, &mp_type_bluetooth_uuid)) {
478         mp_raise_ValueError(MP_ERROR_TEXT("invalid service UUID"));
479     }
480     mp_obj_bluetooth_uuid_t *service_uuid = MP_OBJ_TO_PTR(uuid_in);
481 
482     mp_obj_t len_in = mp_obj_len(characteristics_in);
483     size_t len = mp_obj_get_int(len_in);
484     mp_obj_iter_buf_t iter_buf;
485     mp_obj_t iterable = mp_getiter(characteristics_in, &iter_buf);
486     mp_obj_t characteristic_obj;
487 
488     // Lists of characteristic uuids and flags.
489     mp_obj_bluetooth_uuid_t **characteristic_uuids = m_new(mp_obj_bluetooth_uuid_t *, len);
490     uint16_t *characteristic_flags = m_new(uint16_t, len);
491 
492     // Flattened list of descriptor uuids and flags. Grows (realloc) as more descriptors are encountered.
493     mp_obj_bluetooth_uuid_t **descriptor_uuids = NULL;
494     uint16_t *descriptor_flags = NULL;
495     // How many descriptors in the flattened list per characteristic.
496     uint8_t *num_descriptors = m_new(uint8_t, len);
497 
498     // Inititally allocate enough room for the number of characteristics.
499     // Will be grown to accommodate descriptors as necessary.
500     *num_handles = len;
501     *handles = m_new(uint16_t, *num_handles);
502 
503     // Extract out characteristic uuids & flags.
504 
505     int characteristic_index = 0; // characteristic index.
506     int handle_index = 0; // handle index.
507     int descriptor_index = 0; // descriptor index.
508     while ((characteristic_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
509         // (uuid, flags, (optional descriptors),)
510         size_t characteristic_len;
511         mp_obj_t *characteristic_items;
512         mp_obj_get_array(characteristic_obj, &characteristic_len, &characteristic_items);
513 
514         if (characteristic_len < 2 || characteristic_len > 3) {
515             mp_raise_ValueError(MP_ERROR_TEXT("invalid characteristic tuple"));
516         }
517         mp_obj_t uuid_obj = characteristic_items[0];
518         if (!mp_obj_is_type(uuid_obj, &mp_type_bluetooth_uuid)) {
519             mp_raise_ValueError(MP_ERROR_TEXT("invalid characteristic UUID"));
520         }
521 
522         (*handles)[handle_index++] = 0xffff;
523 
524         // Optional third element, iterable of descriptors.
525         if (characteristic_len >= 3) {
526             mp_obj_t descriptors_len_in = mp_obj_len(characteristic_items[2]);
527             num_descriptors[characteristic_index] = mp_obj_get_int(descriptors_len_in);
528 
529             if (num_descriptors[characteristic_index] == 0) {
530                 continue;
531             }
532 
533             // Grow the flattened uuids and flags arrays with this many more descriptors.
534             descriptor_uuids = m_renew(mp_obj_bluetooth_uuid_t *, descriptor_uuids, descriptor_index, descriptor_index + num_descriptors[characteristic_index]);
535             descriptor_flags = m_renew(uint16_t, descriptor_flags, descriptor_index, descriptor_index + num_descriptors[characteristic_index]);
536 
537             // Also grow the handles array.
538             *handles = m_renew(uint16_t, *handles, *num_handles, *num_handles + num_descriptors[characteristic_index]);
539 
540             mp_obj_iter_buf_t iter_buf_desc;
541             mp_obj_t iterable_desc = mp_getiter(characteristic_items[2], &iter_buf_desc);
542             mp_obj_t descriptor_obj;
543 
544             // Extract out descriptors for this characteristic.
545             while ((descriptor_obj = mp_iternext(iterable_desc)) != MP_OBJ_STOP_ITERATION) {
546                 // (uuid, flags,)
547                 mp_obj_t *descriptor_items;
548                 mp_obj_get_array_fixed_n(descriptor_obj, 2, &descriptor_items);
549                 mp_obj_t desc_uuid_obj = descriptor_items[0];
550                 if (!mp_obj_is_type(desc_uuid_obj, &mp_type_bluetooth_uuid)) {
551                     mp_raise_ValueError(MP_ERROR_TEXT("invalid descriptor UUID"));
552                 }
553 
554                 descriptor_uuids[descriptor_index] = MP_OBJ_TO_PTR(desc_uuid_obj);
555                 descriptor_flags[descriptor_index] = mp_obj_get_int(descriptor_items[1]);
556                 ++descriptor_index;
557 
558                 (*handles)[handle_index++] = 0xffff;
559             }
560 
561             // Reflect that we've grown the handles array.
562             *num_handles += num_descriptors[characteristic_index];
563         }
564 
565         characteristic_uuids[characteristic_index] = MP_OBJ_TO_PTR(uuid_obj);
566         characteristic_flags[characteristic_index] = mp_obj_get_int(characteristic_items[1]);
567         ++characteristic_index;
568     }
569 
570     // Add service.
571     return mp_bluetooth_gatts_register_service(service_uuid, characteristic_uuids, characteristic_flags, descriptor_uuids, descriptor_flags, num_descriptors, *handles, len);
572 }
573 
bluetooth_ble_gatts_register_services(mp_obj_t self_in,mp_obj_t services_in)574 STATIC mp_obj_t bluetooth_ble_gatts_register_services(mp_obj_t self_in, mp_obj_t services_in) {
575     (void)self_in;
576     mp_obj_t len_in = mp_obj_len(services_in);
577     size_t len = mp_obj_get_int(len_in);
578     mp_obj_iter_buf_t iter_buf;
579     mp_obj_t iterable = mp_getiter(services_in, &iter_buf);
580     mp_obj_t service_tuple_obj;
581 
582     mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL));
583 
584     uint16_t **handles = m_new0(uint16_t *, len);
585     size_t *num_handles = m_new0(size_t, len);
586 
587     // TODO: Add a `append` kwarg (defaulting to False) to make this behavior optional.
588     bool append = false;
589     int err = mp_bluetooth_gatts_register_service_begin(append);
590     if (err != 0) {
591         return bluetooth_handle_errno(err);
592     }
593 
594     size_t i = 0;
595     while ((service_tuple_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
596         // (uuid, chars)
597         mp_obj_t *service_items;
598         mp_obj_get_array_fixed_n(service_tuple_obj, 2, &service_items);
599         err = bluetooth_gatts_register_service(service_items[0], service_items[1], &handles[i], &num_handles[i]);
600         if (err != 0) {
601             return bluetooth_handle_errno(err);
602         }
603 
604         ++i;
605     }
606 
607     // On Nimble, this will actually perform the registration, making the handles valid.
608     err = mp_bluetooth_gatts_register_service_end();
609     if (err != 0) {
610         return bluetooth_handle_errno(err);
611     }
612 
613     // Return tuple of tuple of value handles.
614     // TODO: Also the Generic Access service characteristics?
615     for (i = 0; i < len; ++i) {
616         mp_obj_tuple_t *service_handles = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_handles[i], NULL));
617         for (size_t j = 0; j < num_handles[i]; ++j) {
618             service_handles->items[j] = MP_OBJ_NEW_SMALL_INT(handles[i][j]);
619         }
620         result->items[i] = MP_OBJ_FROM_PTR(service_handles);
621     }
622 
623     // Free temporary arrays.
624     m_del(uint16_t *, handles, len);
625     m_del(size_t, num_handles, len);
626 
627     return MP_OBJ_FROM_PTR(result);
628 }
629 STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_register_services_obj, bluetooth_ble_gatts_register_services);
630 
631 #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
bluetooth_ble_gap_connect(size_t n_args,const mp_obj_t * args)632 STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) {
633     uint8_t addr_type = mp_obj_get_int(args[1]);
634     mp_buffer_info_t bufinfo = {0};
635     mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
636     if (bufinfo.len != 6) {
637         mp_raise_ValueError(MP_ERROR_TEXT("invalid addr"));
638     }
639     mp_int_t scan_duration_ms = MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS;
640     if (n_args == 4) {
641         scan_duration_ms = mp_obj_get_int(args[3]);
642     }
643 
644     int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms);
645     return bluetooth_handle_errno(err);
646 }
647 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 3, 4, bluetooth_ble_gap_connect);
648 
bluetooth_ble_gap_scan(size_t n_args,const mp_obj_t * args)649 STATIC mp_obj_t bluetooth_ble_gap_scan(size_t n_args, const mp_obj_t *args) {
650     // Default is indefinite scan, with the NimBLE "background scan" interval and window.
651     mp_int_t duration_ms = 0;
652     mp_int_t interval_us = 1280000;
653     mp_int_t window_us = 11250;
654     bool active_scan = false;
655     if (n_args > 1) {
656         if (args[1] == mp_const_none) {
657             // scan(None) --> stop scan.
658             return bluetooth_handle_errno(mp_bluetooth_gap_scan_stop());
659         }
660         duration_ms = mp_obj_get_int(args[1]);
661         if (n_args > 2) {
662             interval_us = mp_obj_get_int(args[2]);
663             if (n_args > 3) {
664                 window_us = mp_obj_get_int(args[3]);
665                 if (n_args > 4) {
666                     active_scan = mp_obj_is_true(args[4]);
667                 }
668             }
669         }
670     }
671     return bluetooth_handle_errno(mp_bluetooth_gap_scan_start(duration_ms, interval_us, window_us, active_scan));
672 }
673 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_scan_obj, 1, 5, bluetooth_ble_gap_scan);
674 #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
675 
bluetooth_ble_gap_disconnect(mp_obj_t self_in,mp_obj_t conn_handle_in)676 STATIC mp_obj_t bluetooth_ble_gap_disconnect(mp_obj_t self_in, mp_obj_t conn_handle_in) {
677     (void)self_in;
678     uint16_t conn_handle = mp_obj_get_int(conn_handle_in);
679     int err = mp_bluetooth_gap_disconnect(conn_handle);
680     if (err == 0) {
681         return mp_const_true;
682     } else if (err == MP_ENOTCONN) {
683         return mp_const_false;
684     } else {
685         return bluetooth_handle_errno(err);
686     }
687 }
688 STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gap_disconnect_obj, bluetooth_ble_gap_disconnect);
689 
690 #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
bluetooth_ble_gap_pair(mp_obj_t self_in,mp_obj_t conn_handle_in)691 STATIC mp_obj_t bluetooth_ble_gap_pair(mp_obj_t self_in, mp_obj_t conn_handle_in) {
692     (void)self_in;
693     uint16_t conn_handle = mp_obj_get_int(conn_handle_in);
694     return bluetooth_handle_errno(mp_bluetooth_gap_pair(conn_handle));
695 }
696 STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gap_pair_obj, bluetooth_ble_gap_pair);
697 
bluetooth_ble_gap_passkey(size_t n_args,const mp_obj_t * args)698 STATIC mp_obj_t bluetooth_ble_gap_passkey(size_t n_args, const mp_obj_t *args) {
699     uint16_t conn_handle = mp_obj_get_int(args[1]);
700     uint8_t action = mp_obj_get_int(args[2]);
701     mp_int_t passkey = mp_obj_get_int(args[3]);
702     return bluetooth_handle_errno(mp_bluetooth_gap_passkey(conn_handle, action, passkey));
703 }
704 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_passkey_obj, 4, 4, bluetooth_ble_gap_passkey);
705 #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
706 
707 // ----------------------------------------------------------------------------
708 // Bluetooth object: GATTS (Peripheral/Advertiser role)
709 // ----------------------------------------------------------------------------
710 
bluetooth_ble_gatts_read(mp_obj_t self_in,mp_obj_t value_handle_in)711 STATIC mp_obj_t bluetooth_ble_gatts_read(mp_obj_t self_in, mp_obj_t value_handle_in) {
712     (void)self_in;
713     size_t len = 0;
714     uint8_t *buf;
715     mp_bluetooth_gatts_read(mp_obj_get_int(value_handle_in), &buf, &len);
716     return mp_obj_new_bytes(buf, len);
717 }
718 STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_read_obj, bluetooth_ble_gatts_read);
719 
bluetooth_ble_gatts_write(size_t n_args,const mp_obj_t * args)720 STATIC mp_obj_t bluetooth_ble_gatts_write(size_t n_args, const mp_obj_t *args) {
721     mp_buffer_info_t bufinfo = {0};
722     mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
723     bool send_update = false;
724     if (n_args > 3) {
725         send_update = mp_obj_is_true(args[3]);
726     }
727     bluetooth_handle_errno(mp_bluetooth_gatts_write(mp_obj_get_int(args[1]), bufinfo.buf, bufinfo.len, send_update));
728     return MP_OBJ_NEW_SMALL_INT(bufinfo.len);
729 }
730 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_write_obj, 3, 4, bluetooth_ble_gatts_write);
731 
bluetooth_ble_gatts_notify(size_t n_args,const mp_obj_t * args)732 STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) {
733     mp_int_t conn_handle = mp_obj_get_int(args[1]);
734     mp_int_t value_handle = mp_obj_get_int(args[2]);
735 
736     if (n_args == 4 && args[3] != mp_const_none) {
737         mp_buffer_info_t bufinfo = {0};
738         mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
739         int err = mp_bluetooth_gatts_notify_send(conn_handle, value_handle, bufinfo.buf, bufinfo.len);
740         bluetooth_handle_errno(err);
741         return mp_const_none;
742     } else {
743         int err = mp_bluetooth_gatts_notify(conn_handle, value_handle);
744         return bluetooth_handle_errno(err);
745     }
746 }
747 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_notify_obj, 3, 4, bluetooth_ble_gatts_notify);
748 
bluetooth_ble_gatts_indicate(mp_obj_t self_in,mp_obj_t conn_handle_in,mp_obj_t value_handle_in)749 STATIC mp_obj_t bluetooth_ble_gatts_indicate(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t value_handle_in) {
750     (void)self_in;
751     mp_int_t conn_handle = mp_obj_get_int(conn_handle_in);
752     mp_int_t value_handle = mp_obj_get_int(value_handle_in);
753 
754     int err = mp_bluetooth_gatts_indicate(conn_handle, value_handle);
755     return bluetooth_handle_errno(err);
756 }
757 STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gatts_indicate_obj, bluetooth_ble_gatts_indicate);
758 
bluetooth_ble_gatts_set_buffer(size_t n_args,const mp_obj_t * args)759 STATIC mp_obj_t bluetooth_ble_gatts_set_buffer(size_t n_args, const mp_obj_t *args) {
760     mp_int_t value_handle = mp_obj_get_int(args[1]);
761     mp_int_t len = mp_obj_get_int(args[2]);
762     bool append = n_args >= 4 && mp_obj_is_true(args[3]);
763     return bluetooth_handle_errno(mp_bluetooth_gatts_set_buffer(value_handle, len, append));
764 }
765 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_set_buffer_obj, 3, 4, bluetooth_ble_gatts_set_buffer);
766 
767 // ----------------------------------------------------------------------------
768 // Bluetooth object: GATTC (Central/Scanner role)
769 // ----------------------------------------------------------------------------
770 
771 #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
772 
bluetooth_ble_gattc_discover_services(size_t n_args,const mp_obj_t * args)773 STATIC mp_obj_t bluetooth_ble_gattc_discover_services(size_t n_args, const mp_obj_t *args) {
774     mp_int_t conn_handle = mp_obj_get_int(args[1]);
775     mp_obj_bluetooth_uuid_t *uuid = NULL;
776     if (n_args == 3 && args[2] != mp_const_none) {
777         if (!mp_obj_is_type(args[2], &mp_type_bluetooth_uuid)) {
778             mp_raise_TypeError(MP_ERROR_TEXT("UUID"));
779         }
780         uuid = MP_OBJ_TO_PTR(args[2]);
781     }
782     return bluetooth_handle_errno(mp_bluetooth_gattc_discover_primary_services(conn_handle, uuid));
783 }
784 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_discover_services_obj, 2, 3, bluetooth_ble_gattc_discover_services);
785 
bluetooth_ble_gattc_discover_characteristics(size_t n_args,const mp_obj_t * args)786 STATIC mp_obj_t bluetooth_ble_gattc_discover_characteristics(size_t n_args, const mp_obj_t *args) {
787     mp_int_t conn_handle = mp_obj_get_int(args[1]);
788     mp_int_t start_handle = mp_obj_get_int(args[2]);
789     mp_int_t end_handle = mp_obj_get_int(args[3]);
790     mp_obj_bluetooth_uuid_t *uuid = NULL;
791     if (n_args == 5 && args[4] != mp_const_none) {
792         if (!mp_obj_is_type(args[4], &mp_type_bluetooth_uuid)) {
793             mp_raise_TypeError(MP_ERROR_TEXT("UUID"));
794         }
795         uuid = MP_OBJ_TO_PTR(args[4]);
796     }
797     return bluetooth_handle_errno(mp_bluetooth_gattc_discover_characteristics(conn_handle, start_handle, end_handle, uuid));
798 }
799 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_discover_characteristics_obj, 4, 5, bluetooth_ble_gattc_discover_characteristics);
800 
bluetooth_ble_gattc_discover_descriptors(size_t n_args,const mp_obj_t * args)801 STATIC mp_obj_t bluetooth_ble_gattc_discover_descriptors(size_t n_args, const mp_obj_t *args) {
802     (void)n_args;
803     mp_int_t conn_handle = mp_obj_get_int(args[1]);
804     mp_int_t start_handle = mp_obj_get_int(args[2]);
805     mp_int_t end_handle = mp_obj_get_int(args[3]);
806     return bluetooth_handle_errno(mp_bluetooth_gattc_discover_descriptors(conn_handle, start_handle, end_handle));
807 }
808 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_discover_descriptors_obj, 4, 4, bluetooth_ble_gattc_discover_descriptors);
809 
bluetooth_ble_gattc_read(mp_obj_t self_in,mp_obj_t conn_handle_in,mp_obj_t value_handle_in)810 STATIC mp_obj_t bluetooth_ble_gattc_read(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t value_handle_in) {
811     (void)self_in;
812     mp_int_t conn_handle = mp_obj_get_int(conn_handle_in);
813     mp_int_t value_handle = mp_obj_get_int(value_handle_in);
814     return bluetooth_handle_errno(mp_bluetooth_gattc_read(conn_handle, value_handle));
815 }
816 STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gattc_read_obj, bluetooth_ble_gattc_read);
817 
bluetooth_ble_gattc_write(size_t n_args,const mp_obj_t * args)818 STATIC mp_obj_t bluetooth_ble_gattc_write(size_t n_args, const mp_obj_t *args) {
819     mp_int_t conn_handle = mp_obj_get_int(args[1]);
820     mp_int_t value_handle = mp_obj_get_int(args[2]);
821     mp_obj_t data = args[3];
822     mp_buffer_info_t bufinfo = {0};
823     mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
824     size_t len = bufinfo.len;
825     unsigned int mode = MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE;
826     if (n_args == 5) {
827         mode = mp_obj_get_int(args[4]);
828     }
829     return bluetooth_handle_errno(mp_bluetooth_gattc_write(conn_handle, value_handle, bufinfo.buf, &len, mode));
830 }
831 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_write_obj, 4, 5, bluetooth_ble_gattc_write);
832 
bluetooth_ble_gattc_exchange_mtu(mp_obj_t self_in,mp_obj_t conn_handle_in)833 STATIC mp_obj_t bluetooth_ble_gattc_exchange_mtu(mp_obj_t self_in, mp_obj_t conn_handle_in) {
834     (void)self_in;
835     uint16_t conn_handle = mp_obj_get_int(conn_handle_in);
836     return bluetooth_handle_errno(mp_bluetooth_gattc_exchange_mtu(conn_handle));
837 }
838 STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gattc_exchange_mtu_obj, bluetooth_ble_gattc_exchange_mtu);
839 
840 #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
841 
842 #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
843 
bluetooth_ble_l2cap_listen(mp_obj_t self_in,mp_obj_t psm_in,mp_obj_t mtu_in)844 STATIC mp_obj_t bluetooth_ble_l2cap_listen(mp_obj_t self_in, mp_obj_t psm_in, mp_obj_t mtu_in) {
845     (void)self_in;
846     mp_int_t psm = mp_obj_get_int(psm_in);
847     mp_int_t mtu = MAX(32, MIN(UINT16_MAX, mp_obj_get_int(mtu_in)));
848     return bluetooth_handle_errno(mp_bluetooth_l2cap_listen(psm, mtu));
849 }
850 STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_l2cap_listen_obj, bluetooth_ble_l2cap_listen);
851 
bluetooth_ble_l2cap_connect(size_t n_args,const mp_obj_t * args)852 STATIC mp_obj_t bluetooth_ble_l2cap_connect(size_t n_args, const mp_obj_t *args) {
853     mp_int_t conn_handle = mp_obj_get_int(args[1]);
854     mp_int_t psm = mp_obj_get_int(args[2]);
855     mp_int_t mtu = MAX(32, MIN(UINT16_MAX, mp_obj_get_int(args[3])));
856     return bluetooth_handle_errno(mp_bluetooth_l2cap_connect(conn_handle, psm, mtu));
857 }
858 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_l2cap_connect_obj, 4, 4, bluetooth_ble_l2cap_connect);
859 
bluetooth_ble_l2cap_disconnect(mp_obj_t self_in,mp_obj_t conn_handle_in,mp_obj_t cid_in)860 STATIC mp_obj_t bluetooth_ble_l2cap_disconnect(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t cid_in) {
861     (void)self_in;
862     mp_int_t conn_handle = mp_obj_get_int(conn_handle_in);
863     mp_int_t cid = mp_obj_get_int(cid_in);
864     return bluetooth_handle_errno(mp_bluetooth_l2cap_disconnect(conn_handle, cid));
865 }
866 STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_l2cap_disconnect_obj, bluetooth_ble_l2cap_disconnect);
867 
bluetooth_ble_l2cap_send(size_t n_args,const mp_obj_t * args)868 STATIC mp_obj_t bluetooth_ble_l2cap_send(size_t n_args, const mp_obj_t *args) {
869     mp_int_t conn_handle = mp_obj_get_int(args[1]);
870     mp_int_t cid = mp_obj_get_int(args[2]);
871     mp_buffer_info_t bufinfo;
872     mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
873     bool stalled = false;
874     bluetooth_handle_errno(mp_bluetooth_l2cap_send(conn_handle, cid, bufinfo.buf, bufinfo.len, &stalled));
875     // Return True if the channel is still ready to send.
876     return mp_obj_new_bool(!stalled);
877 }
878 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_l2cap_send_obj, 4, 4, bluetooth_ble_l2cap_send);
879 
bluetooth_ble_l2cap_recvinto(size_t n_args,const mp_obj_t * args)880 STATIC mp_obj_t bluetooth_ble_l2cap_recvinto(size_t n_args, const mp_obj_t *args) {
881     mp_int_t conn_handle = mp_obj_get_int(args[1]);
882     mp_int_t cid = mp_obj_get_int(args[2]);
883     mp_buffer_info_t bufinfo = {0};
884     if (args[3] != mp_const_none) {
885         mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_WRITE);
886     }
887     bluetooth_handle_errno(mp_bluetooth_l2cap_recvinto(conn_handle, cid, bufinfo.buf, &bufinfo.len));
888     return MP_OBJ_NEW_SMALL_INT(bufinfo.len);
889 }
890 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_l2cap_recvinto_obj, 4, 4, bluetooth_ble_l2cap_recvinto);
891 
892 #endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
893 
894 #if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
895 
bluetooth_ble_hci_cmd(size_t n_args,const mp_obj_t * args)896 STATIC mp_obj_t bluetooth_ble_hci_cmd(size_t n_args, const mp_obj_t *args) {
897     mp_int_t ogf = mp_obj_get_int(args[1]);
898     mp_int_t ocf = mp_obj_get_int(args[2]);
899     mp_buffer_info_t bufinfo_request = {0};
900     mp_buffer_info_t bufinfo_response = {0};
901     mp_get_buffer_raise(args[3], &bufinfo_request, MP_BUFFER_READ);
902     mp_get_buffer_raise(args[4], &bufinfo_response, MP_BUFFER_WRITE);
903     uint8_t status = 0;
904     bluetooth_handle_errno(mp_bluetooth_hci_cmd(ogf, ocf, bufinfo_request.buf, bufinfo_request.len, bufinfo_response.buf, bufinfo_response.len, &status));
905     return MP_OBJ_NEW_SMALL_INT(status);
906 }
907 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_hci_cmd_obj, 5, 5, bluetooth_ble_hci_cmd);
908 
909 #endif // MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
910 
911 // ----------------------------------------------------------------------------
912 // Bluetooth object: Definition
913 // ----------------------------------------------------------------------------
914 
915 STATIC const mp_rom_map_elem_t bluetooth_ble_locals_dict_table[] = {
916     // General
917     { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&bluetooth_ble_active_obj) },
918     { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&bluetooth_ble_config_obj) },
919     { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&bluetooth_ble_irq_obj) },
920     // GAP
921     { MP_ROM_QSTR(MP_QSTR_gap_advertise), MP_ROM_PTR(&bluetooth_ble_gap_advertise_obj) },
922     #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
923     { MP_ROM_QSTR(MP_QSTR_gap_connect), MP_ROM_PTR(&bluetooth_ble_gap_connect_obj) },
924     { MP_ROM_QSTR(MP_QSTR_gap_scan), MP_ROM_PTR(&bluetooth_ble_gap_scan_obj) },
925     #endif
926     { MP_ROM_QSTR(MP_QSTR_gap_disconnect), MP_ROM_PTR(&bluetooth_ble_gap_disconnect_obj) },
927     #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
928     { MP_ROM_QSTR(MP_QSTR_gap_pair), MP_ROM_PTR(&bluetooth_ble_gap_pair_obj) },
929     { MP_ROM_QSTR(MP_QSTR_gap_passkey), MP_ROM_PTR(&bluetooth_ble_gap_passkey_obj) },
930     #endif
931     // GATT Server
932     { MP_ROM_QSTR(MP_QSTR_gatts_register_services), MP_ROM_PTR(&bluetooth_ble_gatts_register_services_obj) },
933     { MP_ROM_QSTR(MP_QSTR_gatts_read), MP_ROM_PTR(&bluetooth_ble_gatts_read_obj) },
934     { MP_ROM_QSTR(MP_QSTR_gatts_write), MP_ROM_PTR(&bluetooth_ble_gatts_write_obj) },
935     { MP_ROM_QSTR(MP_QSTR_gatts_notify), MP_ROM_PTR(&bluetooth_ble_gatts_notify_obj) },
936     { MP_ROM_QSTR(MP_QSTR_gatts_indicate), MP_ROM_PTR(&bluetooth_ble_gatts_indicate_obj) },
937     { MP_ROM_QSTR(MP_QSTR_gatts_set_buffer), MP_ROM_PTR(&bluetooth_ble_gatts_set_buffer_obj) },
938     #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
939     // GATT Client
940     { MP_ROM_QSTR(MP_QSTR_gattc_discover_services), MP_ROM_PTR(&bluetooth_ble_gattc_discover_services_obj) },
941     { MP_ROM_QSTR(MP_QSTR_gattc_discover_characteristics), MP_ROM_PTR(&bluetooth_ble_gattc_discover_characteristics_obj) },
942     { MP_ROM_QSTR(MP_QSTR_gattc_discover_descriptors), MP_ROM_PTR(&bluetooth_ble_gattc_discover_descriptors_obj) },
943     { MP_ROM_QSTR(MP_QSTR_gattc_read), MP_ROM_PTR(&bluetooth_ble_gattc_read_obj) },
944     { MP_ROM_QSTR(MP_QSTR_gattc_write), MP_ROM_PTR(&bluetooth_ble_gattc_write_obj) },
945     { MP_ROM_QSTR(MP_QSTR_gattc_exchange_mtu), MP_ROM_PTR(&bluetooth_ble_gattc_exchange_mtu_obj) },
946     #endif
947     #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
948     { MP_ROM_QSTR(MP_QSTR_l2cap_listen), MP_ROM_PTR(&bluetooth_ble_l2cap_listen_obj) },
949     { MP_ROM_QSTR(MP_QSTR_l2cap_connect), MP_ROM_PTR(&bluetooth_ble_l2cap_connect_obj) },
950     { MP_ROM_QSTR(MP_QSTR_l2cap_disconnect), MP_ROM_PTR(&bluetooth_ble_l2cap_disconnect_obj) },
951     { MP_ROM_QSTR(MP_QSTR_l2cap_send), MP_ROM_PTR(&bluetooth_ble_l2cap_send_obj) },
952     { MP_ROM_QSTR(MP_QSTR_l2cap_recvinto), MP_ROM_PTR(&bluetooth_ble_l2cap_recvinto_obj) },
953     #endif
954     #if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
955     { MP_ROM_QSTR(MP_QSTR_hci_cmd), MP_ROM_PTR(&bluetooth_ble_hci_cmd_obj) },
956     #endif
957 };
958 STATIC MP_DEFINE_CONST_DICT(bluetooth_ble_locals_dict, bluetooth_ble_locals_dict_table);
959 
960 STATIC const mp_obj_type_t mp_type_bluetooth_ble = {
961     { &mp_type_type },
962     .name = MP_QSTR_BLE,
963     .make_new = bluetooth_ble_make_new,
964     .locals_dict = (void *)&bluetooth_ble_locals_dict,
965 };
966 
967 STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = {
968     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluetooth) },
969     { MP_ROM_QSTR(MP_QSTR_BLE), MP_ROM_PTR(&mp_type_bluetooth_ble) },
970     { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&mp_type_bluetooth_uuid) },
971 
972     // TODO: Deprecate these flags (recommend copying the constants from modbluetooth.h instead).
973     { MP_ROM_QSTR(MP_QSTR_FLAG_READ), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ) },
974     { MP_ROM_QSTR(MP_QSTR_FLAG_WRITE), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE) },
975     { MP_ROM_QSTR(MP_QSTR_FLAG_NOTIFY), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY) },
976     { MP_ROM_QSTR(MP_QSTR_FLAG_INDICATE), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_INDICATE) },
977     { MP_ROM_QSTR(MP_QSTR_FLAG_WRITE_NO_RESPONSE), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_NO_RESPONSE) },
978 };
979 
980 STATIC MP_DEFINE_CONST_DICT(mp_module_bluetooth_globals, mp_module_bluetooth_globals_table);
981 
982 const mp_obj_module_t mp_module_ubluetooth = {
983     .base = { &mp_type_module },
984     .globals = (mp_obj_dict_t *)&mp_module_bluetooth_globals,
985 };
986 
987 // Helpers
988 
989 #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
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)990 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) {
991     assert(ringbuf_avail(ringbuf) >= n_u16 * 2 + n_u8 + (bytes_addr ? 6 : 0) + n_i8 + (uuid ? 1 : 0) + (bytes_data ? 1 : 0));
992     size_t j = 0;
993 
994     for (size_t i = 0; i < n_u16; ++i) {
995         data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT(ringbuf_get16(ringbuf));
996     }
997     for (size_t i = 0; i < n_u8; ++i) {
998         data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT(ringbuf_get(ringbuf));
999     }
1000     if (bytes_addr) {
1001         bytes_addr->len = 6;
1002         for (size_t i = 0; i < bytes_addr->len; ++i) {
1003             ((uint8_t *)bytes_addr->items)[i] = ringbuf_get(ringbuf);
1004         }
1005         data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_addr);
1006     }
1007     for (size_t i = 0; i < n_i8; ++i) {
1008         // Note the int8_t got packed into the ringbuf as a uint8_t.
1009         data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT((int8_t)ringbuf_get(ringbuf));
1010     }
1011     #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1012     if (uuid) {
1013         ringbuf_get_uuid(ringbuf, uuid);
1014         data_tuple->items[j++] = MP_OBJ_FROM_PTR(uuid);
1015     }
1016     #endif
1017     // The code that enqueues into the ringbuf should ensure that it doesn't
1018     // put more than bt->irq_data_data_alloc bytes into the ringbuf, because
1019     // that's what's available here.
1020     if (bytes_data) {
1021         bytes_data->len = ringbuf_get16(ringbuf);
1022         for (size_t i = 0; i < bytes_data->len; ++i) {
1023             ((uint8_t *)bytes_data->items)[i] = ringbuf_get(ringbuf);
1024         }
1025         data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_data);
1026     }
1027 
1028     data_tuple->len = j;
1029 }
1030 
bluetooth_ble_invoke_irq(mp_obj_t none_in)1031 STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) {
1032     (void)none_in;
1033     // This is always executing in schedule context.
1034 
1035     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1036     o->irq_scheduled = false;
1037 
1038     for (;;) {
1039         MICROPY_PY_BLUETOOTH_ENTER
1040 
1041         mp_int_t event = ringbuf_get(&o->ringbuf);
1042         if (event < 0) {
1043             // Nothing available in ringbuf.
1044             MICROPY_PY_BLUETOOTH_EXIT
1045             break;
1046         }
1047 
1048         // Although we're in schedule context, this code still avoids using any allocations:
1049         //  - IRQs are disabled (to protect the ringbuf), and we need to avoid triggering GC
1050         //  - The user's handler might not alloc, so we shouldn't either.
1051 
1052         mp_obj_t handler = handler = o->irq_handler;
1053         mp_obj_tuple_t *data_tuple = MP_OBJ_TO_PTR(o->irq_data_tuple);
1054 
1055         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) {
1056             // conn_handle, addr_type, addr
1057             ringbuf_extract(&o->ringbuf, data_tuple, 1, 1, &o->irq_data_addr, 0, NULL, NULL);
1058         } else if (event == MP_BLUETOOTH_IRQ_CONNECTION_UPDATE) {
1059             // conn_handle, conn_interval, conn_latency, supervision_timeout, status
1060             ringbuf_extract(&o->ringbuf, data_tuple, 5, 0, NULL, 0, NULL, NULL);
1061         } else if (event == MP_BLUETOOTH_IRQ_GATTS_WRITE) {
1062             // conn_handle, value_handle
1063             ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, NULL);
1064         } else if (event == MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE) {
1065             // conn_handle, value_handle, status
1066             ringbuf_extract(&o->ringbuf, data_tuple, 2, 1, NULL, 0, NULL, NULL);
1067         } else if (event == MP_BLUETOOTH_IRQ_MTU_EXCHANGED) {
1068             // conn_handle, mtu
1069             ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, NULL);
1070         #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1071         } else if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT) {
1072             // addr_type, addr, adv_type, rssi, adv_data
1073             ringbuf_extract(&o->ringbuf, data_tuple, 0, 1, &o->irq_data_addr, 2, NULL, &o->irq_data_data);
1074         } else if (event == MP_BLUETOOTH_IRQ_SCAN_DONE) {
1075             // No params required.
1076             data_tuple->len = 0;
1077         #endif
1078         #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1079         } else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT) {
1080             // conn_handle, start_handle, end_handle, uuid
1081             ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, &o->irq_data_uuid, NULL);
1082         } else if (event == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT) {
1083             // conn_handle, def_handle, value_handle, properties, uuid
1084             ringbuf_extract(&o->ringbuf, data_tuple, 3, 1, NULL, 0, &o->irq_data_uuid, NULL);
1085         } else if (event == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT) {
1086             // conn_handle, handle, uuid
1087             ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, &o->irq_data_uuid, NULL);
1088         } else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_DONE || event == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE || event == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_DONE) {
1089             // conn_handle, status
1090             ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, NULL);
1091         } else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_RESULT || event == MP_BLUETOOTH_IRQ_GATTC_NOTIFY || event == MP_BLUETOOTH_IRQ_GATTC_INDICATE) {
1092             // conn_handle, value_handle, data
1093             ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, &o->irq_data_data);
1094         } else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_DONE || event == MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE) {
1095             // conn_handle, value_handle, status
1096             ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, NULL, NULL);
1097         #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1098         }
1099 
1100         MICROPY_PY_BLUETOOTH_EXIT
1101 
1102         mp_call_function_2(handler, MP_OBJ_NEW_SMALL_INT(event), MP_OBJ_FROM_PTR(data_tuple));
1103     }
1104 
1105     return mp_const_none;
1106 }
1107 STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_invoke_irq);
1108 #endif // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
1109 
1110 // ----------------------------------------------------------------------------
1111 // Port API
1112 // ----------------------------------------------------------------------------
1113 
1114 #if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
1115 
invoke_irq_handler(uint16_t event,const mp_int_t * numeric,size_t n_unsigned,size_t n_signed,const uint8_t * addr,const mp_obj_bluetooth_uuid_t * uuid,const uint8_t ** data,size_t * data_len,size_t n_data)1116 STATIC mp_obj_t invoke_irq_handler(uint16_t event,
1117     const mp_int_t *numeric, size_t n_unsigned, size_t n_signed,
1118     const uint8_t *addr,
1119     const mp_obj_bluetooth_uuid_t *uuid,
1120     const uint8_t **data, size_t *data_len, size_t n_data) {
1121     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1122     if (o->irq_handler == mp_const_none) {
1123         return mp_const_none;
1124     }
1125 
1126     mp_obj_array_t mv_addr;
1127     mp_obj_array_t mv_data[2];
1128     assert(n_data <= 2);
1129 
1130     mp_obj_tuple_t *data_tuple = mp_local_alloc(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t) * MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN);
1131     data_tuple->base.type = &mp_type_tuple;
1132     data_tuple->len = 0;
1133 
1134     for (size_t i = 0; i < n_unsigned; ++i) {
1135         data_tuple->items[data_tuple->len++] = MP_OBJ_NEW_SMALL_INT(numeric[i]);
1136     }
1137     if (addr) {
1138         mp_obj_memoryview_init(&mv_addr, 'B', 0, 6, (void *)addr);
1139         data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_addr);
1140     }
1141     for (size_t i = 0; i < n_signed; ++i) {
1142         data_tuple->items[data_tuple->len++] = MP_OBJ_NEW_SMALL_INT(numeric[i + n_unsigned]);
1143     }
1144     #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1145     if (uuid) {
1146         data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(uuid);
1147     }
1148     #endif
1149     for (size_t i = 0; i < n_data; ++i) {
1150         if (data[i]) {
1151             mp_obj_memoryview_init(&mv_data[i], 'B', 0, data_len[i], (void *)data[i]);
1152             data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_data[i]);
1153         } else {
1154             data_tuple->items[data_tuple->len++] = mp_const_none;
1155         }
1156     }
1157     assert(data_tuple->len <= MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN);
1158 
1159     mp_obj_t result = mp_call_function_2(o->irq_handler, MP_OBJ_NEW_SMALL_INT(event), MP_OBJ_FROM_PTR(data_tuple));
1160 
1161     mp_local_free(data_tuple);
1162 
1163     return result;
1164 }
1165 
1166 #define NULL_NUMERIC NULL
1167 #define NULL_ADDR NULL
1168 #define NULL_UUID NULL
1169 #define NULL_DATA NULL
1170 #define NULL_DATA_LEN NULL
1171 
mp_bluetooth_gap_on_connected_disconnected(uint8_t event,uint16_t conn_handle,uint8_t addr_type,const uint8_t * addr)1172 void mp_bluetooth_gap_on_connected_disconnected(uint8_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr) {
1173     mp_int_t args[] = {conn_handle, addr_type};
1174     invoke_irq_handler(event, args, 2, 0, addr, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1175 }
1176 
mp_bluetooth_gap_on_connection_update(uint16_t conn_handle,uint16_t conn_interval,uint16_t conn_latency,uint16_t supervision_timeout,uint16_t status)1177 void mp_bluetooth_gap_on_connection_update(uint16_t conn_handle, uint16_t conn_interval, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t status) {
1178     mp_int_t args[] = {conn_handle, conn_interval, conn_latency, supervision_timeout, status};
1179     invoke_irq_handler(MP_BLUETOOTH_IRQ_CONNECTION_UPDATE, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1180 }
1181 
1182 #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
mp_bluetooth_gatts_on_encryption_update(uint16_t conn_handle,bool encrypted,bool authenticated,bool bonded,uint8_t key_size)1183 void mp_bluetooth_gatts_on_encryption_update(uint16_t conn_handle, bool encrypted, bool authenticated, bool bonded, uint8_t key_size) {
1184     mp_int_t args[] = {conn_handle, encrypted, authenticated, bonded, key_size};
1185     invoke_irq_handler(MP_BLUETOOTH_IRQ_ENCRYPTION_UPDATE, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1186 }
1187 
mp_bluetooth_gap_on_get_secret(uint8_t type,uint8_t index,const uint8_t * key,size_t key_len,const uint8_t ** value,size_t * value_len)1188 bool mp_bluetooth_gap_on_get_secret(uint8_t type, uint8_t index, const uint8_t *key, size_t key_len, const uint8_t **value, size_t *value_len) {
1189     mp_int_t args[] = {type, index};
1190     mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_GET_SECRET, args, 2, 0, NULL_ADDR, NULL_UUID, &key, &key_len, 1);
1191     if (result == mp_const_none) {
1192         return false;
1193     }
1194     mp_buffer_info_t bufinfo;
1195     mp_get_buffer_raise(result, &bufinfo, MP_BUFFER_READ);
1196     *value = bufinfo.buf;
1197     *value_len = bufinfo.len;
1198     return true;
1199 }
1200 
mp_bluetooth_gap_on_set_secret(uint8_t type,const uint8_t * key,size_t key_len,const uint8_t * value,size_t value_len)1201 bool mp_bluetooth_gap_on_set_secret(uint8_t type, const uint8_t *key, size_t key_len, const uint8_t *value, size_t value_len) {
1202     mp_int_t args[] = { type };
1203     const uint8_t *data[] = {key, value};
1204     size_t data_len[] = {key_len, value_len};
1205     mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_SET_SECRET, args, 1, 0, NULL_ADDR, NULL_UUID, data, data_len, 2);
1206     return mp_obj_is_true(result);
1207 }
1208 
mp_bluetooth_gap_on_passkey_action(uint16_t conn_handle,uint8_t action,mp_int_t passkey)1209 void mp_bluetooth_gap_on_passkey_action(uint16_t conn_handle, uint8_t action, mp_int_t passkey) {
1210     mp_int_t args[] = { conn_handle, action, passkey };
1211     invoke_irq_handler(MP_BLUETOOTH_IRQ_PASSKEY_ACTION, args, 2, 1, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1212 }
1213 #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
1214 
mp_bluetooth_gatts_on_write(uint16_t conn_handle,uint16_t value_handle)1215 void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
1216     mp_int_t args[] = {conn_handle, value_handle};
1217     invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_WRITE, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1218 }
1219 
mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle,uint16_t value_handle,uint8_t status)1220 void mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle, uint16_t value_handle, uint8_t status) {
1221     mp_int_t args[] = {conn_handle, value_handle, status};
1222     invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE, args, 3, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1223 }
1224 
mp_bluetooth_gatts_on_read_request(uint16_t conn_handle,uint16_t value_handle)1225 mp_int_t mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) {
1226     mp_int_t args[] = {conn_handle, value_handle};
1227     mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1228     // Return non-zero from IRQ handler to fail the read.
1229     mp_int_t ret = 0;
1230     mp_obj_get_int_maybe(result, &ret);
1231     return ret;
1232 }
1233 
mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle,uint16_t value)1234 void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
1235     mp_int_t args[] = {conn_handle, value};
1236     invoke_irq_handler(MP_BLUETOOTH_IRQ_MTU_EXCHANGED, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1237 }
1238 
1239 #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
mp_bluetooth_on_l2cap_accept(uint16_t conn_handle,uint16_t cid,uint16_t psm,uint16_t our_mtu,uint16_t peer_mtu)1240 mp_int_t mp_bluetooth_on_l2cap_accept(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) {
1241     mp_int_t args[] = {conn_handle, cid, psm, our_mtu, peer_mtu};
1242     mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_ACCEPT, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1243     // Return non-zero from IRQ handler to fail the accept.
1244     mp_int_t ret = 0;
1245     mp_obj_get_int_maybe(result, &ret);
1246     return ret;
1247 }
1248 
mp_bluetooth_on_l2cap_connect(uint16_t conn_handle,uint16_t cid,uint16_t psm,uint16_t our_mtu,uint16_t peer_mtu)1249 void mp_bluetooth_on_l2cap_connect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) {
1250     mp_int_t args[] = {conn_handle, cid, psm, our_mtu, peer_mtu};
1251     invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_CONNECT, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1252 }
1253 
mp_bluetooth_on_l2cap_disconnect(uint16_t conn_handle,uint16_t cid,uint16_t psm,uint16_t status)1254 void mp_bluetooth_on_l2cap_disconnect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t status) {
1255     mp_int_t args[] = {conn_handle, cid, psm, status};
1256     invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_DISCONNECT, args, 4, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1257 }
1258 
mp_bluetooth_on_l2cap_send_ready(uint16_t conn_handle,uint16_t cid,uint8_t status)1259 void mp_bluetooth_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status) {
1260     mp_int_t args[] = {conn_handle, cid, status};
1261     invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_SEND_READY, args, 3, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1262 }
1263 
mp_bluetooth_on_l2cap_recv(uint16_t conn_handle,uint16_t cid)1264 void mp_bluetooth_on_l2cap_recv(uint16_t conn_handle, uint16_t cid) {
1265     mp_int_t args[] = {conn_handle, cid};
1266     invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_RECV, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1267 }
1268 #endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
1269 
1270 #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
mp_bluetooth_gap_on_scan_complete(void)1271 void mp_bluetooth_gap_on_scan_complete(void) {
1272     invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_DONE, NULL_NUMERIC, 0, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1273 }
1274 
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)1275 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) {
1276     mp_int_t args[] = {addr_type, adv_type, rssi};
1277     invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_RESULT, args, 1, 2, addr, NULL_UUID, &data, &data_len, 1);
1278 }
1279 #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1280 
1281 #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
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)1282 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) {
1283     mp_int_t args[] = {conn_handle, start_handle, end_handle};
1284     invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT, args, 3, 0, NULL_ADDR, service_uuid, NULL_DATA, NULL_DATA_LEN, 0);
1285 }
1286 
mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle,uint16_t def_handle,uint16_t value_handle,uint8_t properties,mp_obj_bluetooth_uuid_t * characteristic_uuid)1287 void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid) {
1288     mp_int_t args[] = {conn_handle, def_handle, value_handle, properties};
1289     invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT, args, 4, 0, NULL_ADDR, characteristic_uuid, NULL_DATA, NULL_DATA_LEN, 0);
1290 }
1291 
mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle,uint16_t handle,mp_obj_bluetooth_uuid_t * descriptor_uuid)1292 void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) {
1293     mp_int_t args[] = {conn_handle, handle};
1294     invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT, args, 2, 0, NULL_ADDR, descriptor_uuid, NULL_DATA, NULL_DATA_LEN, 0);
1295 }
1296 
mp_bluetooth_gattc_on_discover_complete(uint8_t event,uint16_t conn_handle,uint16_t status)1297 void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status) {
1298     mp_int_t args[] = {conn_handle, status};
1299     invoke_irq_handler(event, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1300 }
1301 
mp_bluetooth_gattc_on_data_available(uint8_t event,uint16_t conn_handle,uint16_t value_handle,const uint8_t ** data,uint16_t * data_len,size_t num)1302 void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t **data, uint16_t *data_len, size_t num) {
1303     const uint8_t *combined_data;
1304     size_t total_len;
1305 
1306     if (num > 1) {
1307         // Fragmented buffer, need to combine into a new heap-allocated buffer
1308         // in order to pass to Python.
1309         total_len = 0;
1310         for (size_t i = 0; i < num; ++i) {
1311             total_len += data_len[i];
1312         }
1313         uint8_t *buf = m_new(uint8_t, total_len);
1314         uint8_t *p = buf;
1315         for (size_t i = 0; i < num; ++i) {
1316             memcpy(p, data[i], data_len[i]);
1317             p += data_len[i];
1318         }
1319         combined_data = buf;
1320     } else {
1321         // Single buffer, use directly.
1322         combined_data = *data;
1323         total_len = *data_len;
1324     }
1325 
1326     mp_int_t args[] = {conn_handle, value_handle};
1327     invoke_irq_handler(event, args, 2, 0, NULL_ADDR, NULL_UUID, &combined_data, &total_len, 1);
1328 
1329     if (num > 1) {
1330         m_del(uint8_t, (uint8_t *)combined_data, total_len);
1331     }
1332 }
1333 
mp_bluetooth_gattc_on_read_write_status(uint8_t event,uint16_t conn_handle,uint16_t value_handle,uint16_t status)1334 void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status) {
1335     mp_int_t args[] = {conn_handle, value_handle, status};
1336     invoke_irq_handler(event, args, 3, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1337 }
1338 
1339 #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1340 
1341 #else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
1342 // Callbacks are called in interrupt context (i.e. can't allocate), so we need to push the data
1343 // into the ringbuf and schedule the callback via mp_sched_schedule.
1344 
enqueue_irq(mp_obj_bluetooth_ble_t * o,size_t len,uint8_t event)1345 STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint8_t event) {
1346     if (!o || o->irq_handler == mp_const_none) {
1347         return false;
1348     }
1349 
1350     // Check if there is enough room for <event-type><payload>.
1351     if (ringbuf_free(&o->ringbuf) < len + 1) {
1352         // Ringbuffer doesn't have room (and is therefore non-empty).
1353 
1354         // If this is another scan result, or the front of the ringbuffer isn't a scan result, then nothing to do.
1355         if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT || ringbuf_peek(&o->ringbuf) != MP_BLUETOOTH_IRQ_SCAN_RESULT) {
1356             return false;
1357         }
1358 
1359         // Front of the queue is a scan result, remove it.
1360 
1361         // event, addr_type, addr, adv_type, rssi
1362         int n = 1 + 1 + 6 + 1 + 1;
1363         for (int i = 0; i < n; ++i) {
1364             ringbuf_get(&o->ringbuf);
1365         }
1366         // adv_data
1367         n = ringbuf_get(&o->ringbuf);
1368         for (int i = 0; i < n; ++i) {
1369             ringbuf_get(&o->ringbuf);
1370         }
1371     }
1372 
1373     // Append this event, the caller will then append the arguments.
1374     ringbuf_put(&o->ringbuf, event);
1375     return true;
1376 }
1377 
1378 // Must hold the atomic section before calling this (MICROPY_PY_BLUETOOTH_ENTER).
schedule_ringbuf(mp_uint_t atomic_state)1379 STATIC void schedule_ringbuf(mp_uint_t atomic_state) {
1380     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1381     if (!o->irq_scheduled) {
1382         o->irq_scheduled = true;
1383         MICROPY_PY_BLUETOOTH_EXIT
1384         mp_sched_schedule(MP_OBJ_FROM_PTR(&bluetooth_ble_invoke_irq_obj), mp_const_none);
1385     } else {
1386         MICROPY_PY_BLUETOOTH_EXIT
1387     }
1388 }
1389 
mp_bluetooth_gap_on_connected_disconnected(uint8_t event,uint16_t conn_handle,uint8_t addr_type,const uint8_t * addr)1390 void mp_bluetooth_gap_on_connected_disconnected(uint8_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr) {
1391     MICROPY_PY_BLUETOOTH_ENTER
1392     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1393     if (enqueue_irq(o, 2 + 1 + 6, event)) {
1394         ringbuf_put16(&o->ringbuf, conn_handle);
1395         ringbuf_put(&o->ringbuf, addr_type);
1396         for (int i = 0; i < 6; ++i) {
1397             ringbuf_put(&o->ringbuf, addr[i]);
1398         }
1399     }
1400     schedule_ringbuf(atomic_state);
1401 }
1402 
mp_bluetooth_gap_on_connection_update(uint16_t conn_handle,uint16_t conn_interval,uint16_t conn_latency,uint16_t supervision_timeout,uint16_t status)1403 void mp_bluetooth_gap_on_connection_update(uint16_t conn_handle, uint16_t conn_interval, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t status) {
1404     MICROPY_PY_BLUETOOTH_ENTER
1405     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1406     if (enqueue_irq(o, 2 + 2 + 2 + 2 + 2, MP_BLUETOOTH_IRQ_CONNECTION_UPDATE)) {
1407         ringbuf_put16(&o->ringbuf, conn_handle);
1408         ringbuf_put16(&o->ringbuf, conn_interval);
1409         ringbuf_put16(&o->ringbuf, conn_latency);
1410         ringbuf_put16(&o->ringbuf, supervision_timeout);
1411         ringbuf_put16(&o->ringbuf, status);
1412     }
1413     schedule_ringbuf(atomic_state);
1414 }
1415 
mp_bluetooth_gatts_on_write(uint16_t conn_handle,uint16_t value_handle)1416 void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
1417     MICROPY_PY_BLUETOOTH_ENTER
1418     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1419     if (enqueue_irq(o, 2 + 2, MP_BLUETOOTH_IRQ_GATTS_WRITE)) {
1420         ringbuf_put16(&o->ringbuf, conn_handle);
1421         ringbuf_put16(&o->ringbuf, value_handle);
1422     }
1423     schedule_ringbuf(atomic_state);
1424 }
1425 
mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle,uint16_t value_handle,uint8_t status)1426 void mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle, uint16_t value_handle, uint8_t status) {
1427     MICROPY_PY_BLUETOOTH_ENTER
1428     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1429     if (enqueue_irq(o, 2 + 2 + 1, MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE)) {
1430         ringbuf_put16(&o->ringbuf, conn_handle);
1431         ringbuf_put16(&o->ringbuf, value_handle);
1432         ringbuf_put(&o->ringbuf, status);
1433     }
1434     schedule_ringbuf(atomic_state);
1435 }
1436 
mp_bluetooth_gatts_on_read_request(uint16_t conn_handle,uint16_t value_handle)1437 mp_int_t mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) {
1438     (void)conn_handle;
1439     (void)value_handle;
1440     // This must be handled synchronously and therefore cannot implemented with the ringbuffer.
1441     return MP_BLUETOOTH_GATTS_NO_ERROR;
1442 }
1443 
mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle,uint16_t value)1444 void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
1445     MICROPY_PY_BLUETOOTH_ENTER
1446     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1447     if (enqueue_irq(o, 2 + 2, MP_BLUETOOTH_IRQ_MTU_EXCHANGED)) {
1448         ringbuf_put16(&o->ringbuf, conn_handle);
1449         ringbuf_put16(&o->ringbuf, value);
1450     }
1451     schedule_ringbuf(atomic_state);
1452 }
1453 
1454 #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
mp_bluetooth_gap_on_scan_complete(void)1455 void mp_bluetooth_gap_on_scan_complete(void) {
1456     MICROPY_PY_BLUETOOTH_ENTER
1457     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1458     if (enqueue_irq(o, 0, MP_BLUETOOTH_IRQ_SCAN_DONE)) {
1459     }
1460     schedule_ringbuf(atomic_state);
1461 }
1462 
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)1463 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) {
1464     MICROPY_PY_BLUETOOTH_ENTER
1465     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1466     data_len = MIN(o->irq_data_data_alloc, data_len);
1467     if (enqueue_irq(o, 1 + 6 + 1 + 1 + 2 + data_len, MP_BLUETOOTH_IRQ_SCAN_RESULT)) {
1468         ringbuf_put(&o->ringbuf, addr_type);
1469         for (int i = 0; i < 6; ++i) {
1470             ringbuf_put(&o->ringbuf, addr[i]);
1471         }
1472         // The adv_type will get extracted as an int8_t but that's ok because valid values are 0x00-0x04.
1473         ringbuf_put(&o->ringbuf, adv_type);
1474         // Note conversion of int8_t rssi to uint8_t. Must un-convert on the way out.
1475         ringbuf_put(&o->ringbuf, (uint8_t)rssi);
1476         // Length field is 16-bit.
1477         data_len = MIN(UINT16_MAX, data_len);
1478         ringbuf_put16(&o->ringbuf, data_len);
1479         for (size_t i = 0; i < data_len; ++i) {
1480             ringbuf_put(&o->ringbuf, data[i]);
1481         }
1482     }
1483     schedule_ringbuf(atomic_state);
1484 }
1485 #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1486 
1487 #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
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)1488 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) {
1489     MICROPY_PY_BLUETOOTH_ENTER
1490     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1491     if (enqueue_irq(o, 2 + 2 + 2 + 1 + service_uuid->type, MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT)) {
1492         ringbuf_put16(&o->ringbuf, conn_handle);
1493         ringbuf_put16(&o->ringbuf, start_handle);
1494         ringbuf_put16(&o->ringbuf, end_handle);
1495         ringbuf_put_uuid(&o->ringbuf, service_uuid);
1496     }
1497     schedule_ringbuf(atomic_state);
1498 }
1499 
mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle,uint16_t def_handle,uint16_t value_handle,uint8_t properties,mp_obj_bluetooth_uuid_t * characteristic_uuid)1500 void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid) {
1501     MICROPY_PY_BLUETOOTH_ENTER
1502     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1503     if (enqueue_irq(o, 2 + 2 + 2 + 1 + characteristic_uuid->type, MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT)) {
1504         ringbuf_put16(&o->ringbuf, conn_handle);
1505         ringbuf_put16(&o->ringbuf, def_handle);
1506         ringbuf_put16(&o->ringbuf, value_handle);
1507         ringbuf_put(&o->ringbuf, properties);
1508         ringbuf_put_uuid(&o->ringbuf, characteristic_uuid);
1509     }
1510     schedule_ringbuf(atomic_state);
1511 }
1512 
mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle,uint16_t handle,mp_obj_bluetooth_uuid_t * descriptor_uuid)1513 void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) {
1514     MICROPY_PY_BLUETOOTH_ENTER
1515     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1516     if (enqueue_irq(o, 2 + 2 + 1 + descriptor_uuid->type, MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT)) {
1517         ringbuf_put16(&o->ringbuf, conn_handle);
1518         ringbuf_put16(&o->ringbuf, handle);
1519         ringbuf_put_uuid(&o->ringbuf, descriptor_uuid);
1520     }
1521     schedule_ringbuf(atomic_state);
1522 }
1523 
mp_bluetooth_gattc_on_discover_complete(uint8_t event,uint16_t conn_handle,uint16_t status)1524 void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status) {
1525     MICROPY_PY_BLUETOOTH_ENTER
1526     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1527     if (enqueue_irq(o, 2 + 2, event)) {
1528         ringbuf_put16(&o->ringbuf, conn_handle);
1529         ringbuf_put16(&o->ringbuf, status);
1530     }
1531     schedule_ringbuf(atomic_state);
1532 }
1533 
mp_bluetooth_gattc_on_data_available(uint8_t event,uint16_t conn_handle,uint16_t value_handle,const uint8_t ** data,uint16_t * data_len,size_t num)1534 void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t **data, uint16_t *data_len, size_t num) {
1535     MICROPY_PY_BLUETOOTH_ENTER
1536     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1537 
1538     // Get the total length of the fragmented buffers.
1539     uint16_t total_len = 0;
1540     for (size_t i = 0; i < num; ++i) {
1541         total_len += data_len[i];
1542     }
1543 
1544     // Truncate the data at what we'll be able to pass to Python.
1545     total_len = MIN(o->irq_data_data_alloc, total_len);
1546 
1547     if (enqueue_irq(o, 2 + 2 + 2 + total_len, event)) {
1548         ringbuf_put16(&o->ringbuf, conn_handle);
1549         ringbuf_put16(&o->ringbuf, value_handle);
1550 
1551         ringbuf_put16(&o->ringbuf, total_len);
1552 
1553         // Copy total_len from the fragments to the ringbuffer.
1554         uint16_t copied_bytes = 0;
1555         for (size_t i = 0; i < num; ++i) {
1556             for (size_t j = 0; i < data_len[i] && copied_bytes < total_len; ++j) {
1557                 ringbuf_put(&o->ringbuf, data[i][j]);
1558                 ++copied_bytes;
1559             }
1560         }
1561     }
1562     schedule_ringbuf(atomic_state);
1563 }
1564 
mp_bluetooth_gattc_on_read_write_status(uint8_t event,uint16_t conn_handle,uint16_t value_handle,uint16_t status)1565 void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status) {
1566     MICROPY_PY_BLUETOOTH_ENTER
1567     mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1568     if (enqueue_irq(o, 2 + 2 + 2, event)) {
1569         ringbuf_put16(&o->ringbuf, conn_handle);
1570         ringbuf_put16(&o->ringbuf, value_handle);
1571         ringbuf_put16(&o->ringbuf, status);
1572     }
1573     schedule_ringbuf(atomic_state);
1574 }
1575 #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1576 
1577 #endif // MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
1578 
1579 // ----------------------------------------------------------------------------
1580 // GATTS DB
1581 // ----------------------------------------------------------------------------
1582 
mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db,uint16_t handle,size_t len)1583 void mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db, uint16_t handle, size_t len) {
1584     mp_map_elem_t *elem = mp_map_lookup(db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
1585     mp_bluetooth_gatts_db_entry_t *entry = m_new(mp_bluetooth_gatts_db_entry_t, 1);
1586     entry->data = m_new(uint8_t, len);
1587     entry->data_alloc = len;
1588     entry->data_len = 0;
1589     entry->append = false;
1590     elem->value = MP_OBJ_FROM_PTR(entry);
1591 }
1592 
mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db,uint16_t handle)1593 mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, uint16_t handle) {
1594     mp_map_elem_t *elem = mp_map_lookup(db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP);
1595     if (!elem) {
1596         return NULL;
1597     }
1598     return MP_OBJ_TO_PTR(elem->value);
1599 }
1600 
mp_bluetooth_gatts_db_read(mp_gatts_db_t db,uint16_t handle,uint8_t ** value,size_t * value_len)1601 int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len) {
1602     MICROPY_PY_BLUETOOTH_ENTER
1603     mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle);
1604     if (entry) {
1605         *value = entry->data;
1606         *value_len = entry->data_len;
1607         if (entry->append) {
1608             entry->data_len = 0;
1609         }
1610     }
1611     MICROPY_PY_BLUETOOTH_EXIT
1612     return entry ? 0 : MP_EINVAL;
1613 }
1614 
mp_bluetooth_gatts_db_write(mp_gatts_db_t db,uint16_t handle,const uint8_t * value,size_t value_len)1615 int mp_bluetooth_gatts_db_write(mp_gatts_db_t db, uint16_t handle, const uint8_t *value, size_t value_len) {
1616     MICROPY_PY_BLUETOOTH_ENTER
1617     mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle);
1618     if (entry) {
1619         if (value_len > entry->data_alloc) {
1620             uint8_t *data = m_new_maybe(uint8_t, value_len);
1621             if (data) {
1622                 entry->data = data;
1623                 entry->data_alloc = value_len;
1624             } else {
1625                 MICROPY_PY_BLUETOOTH_EXIT
1626                 return MP_ENOMEM;
1627             }
1628         }
1629 
1630         memcpy(entry->data, value, value_len);
1631         entry->data_len = value_len;
1632     }
1633     MICROPY_PY_BLUETOOTH_EXIT
1634     return entry ? 0 : MP_EINVAL;
1635 }
1636 
mp_bluetooth_gatts_db_resize(mp_gatts_db_t db,uint16_t handle,size_t len,bool append)1637 int mp_bluetooth_gatts_db_resize(mp_gatts_db_t db, uint16_t handle, size_t len, bool append) {
1638     MICROPY_PY_BLUETOOTH_ENTER
1639     mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle);
1640     if (entry) {
1641         uint8_t *data = m_renew_maybe(uint8_t, entry->data, entry->data_alloc, len, true);
1642         if (data) {
1643             entry->data = data;
1644             entry->data_alloc = len;
1645             entry->data_len = 0;
1646             entry->append = append;
1647         } else {
1648             MICROPY_PY_BLUETOOTH_EXIT
1649             return MP_ENOMEM;
1650         }
1651     }
1652     MICROPY_PY_BLUETOOTH_EXIT
1653     return entry ? 0 : MP_EINVAL;
1654 }
1655 
1656 #endif // MICROPY_PY_BLUETOOTH
1657