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.
66typedef 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
81STATIC const mp_obj_type_t mp_type_bluetooth_ble;
82
83// TODO: this seems like it could be generic?
84STATIC 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
95STATIC 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
152STATIC 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
164STATIC 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
188STATIC 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
205STATIC 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
219STATIC 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
227STATIC 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
237const 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
252STATIC 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
282STATIC 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}
295STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_active_obj, 1, 2, bluetooth_ble_active);
296
297STATIC 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}
421STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_config_obj, 1, bluetooth_ble_config);
422
423STATIC 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}
437STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_irq_obj, bluetooth_ble_irq);
438
439// ----------------------------------------------------------------------------
440// Bluetooth object: GAP
441// ----------------------------------------------------------------------------
442
443STATIC 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}
474STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_ble_gap_advertise_obj, 1, bluetooth_ble_gap_advertise);
475
476STATIC 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
574STATIC 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}
629STATIC 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
632STATIC 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}
647STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 3, 4, bluetooth_ble_gap_connect);
648
649STATIC 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}
673STATIC 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
676STATIC 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}
688STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gap_disconnect_obj, bluetooth_ble_gap_disconnect);
689
690#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
691STATIC 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}
696STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gap_pair_obj, bluetooth_ble_gap_pair);
697
698STATIC 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}
704STATIC 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
711STATIC 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}
718STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_read_obj, bluetooth_ble_gatts_read);
719
720STATIC mp_obj_t bluetooth_ble_gatts_write(mp_obj_t self_in, mp_obj_t value_handle_in, mp_obj_t data) {
721 (void)self_in;
722 mp_buffer_info_t bufinfo = {0};
723 mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
724 int err = mp_bluetooth_gatts_write(mp_obj_get_int(value_handle_in), bufinfo.buf, bufinfo.len);
725 bluetooth_handle_errno(err);
726 return MP_OBJ_NEW_SMALL_INT(bufinfo.len);
727}
728STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gatts_write_obj, bluetooth_ble_gatts_write);
729
730STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) {
731 mp_int_t conn_handle = mp_obj_get_int(args[1]);
732 mp_int_t value_handle = mp_obj_get_int(args[2]);
733
734 if (n_args == 4 && args[3] != mp_const_none) {
735 mp_buffer_info_t bufinfo = {0};
736 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
737 int err = mp_bluetooth_gatts_notify_send(conn_handle, value_handle, bufinfo.buf, bufinfo.len);
738 bluetooth_handle_errno(err);
739 return mp_const_none;
740 } else {
741 int err = mp_bluetooth_gatts_notify(conn_handle, value_handle);
742 return bluetooth_handle_errno(err);
743 }
744}
745STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_notify_obj, 3, 4, bluetooth_ble_gatts_notify);
746
747STATIC mp_obj_t bluetooth_ble_gatts_indicate(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t value_handle_in) {
748 (void)self_in;
749 mp_int_t conn_handle = mp_obj_get_int(conn_handle_in);
750 mp_int_t value_handle = mp_obj_get_int(value_handle_in);
751
752 int err = mp_bluetooth_gatts_indicate(conn_handle, value_handle);
753 return bluetooth_handle_errno(err);
754}
755STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gatts_indicate_obj, bluetooth_ble_gatts_indicate);
756
757STATIC mp_obj_t bluetooth_ble_gatts_set_buffer(size_t n_args, const mp_obj_t *args) {
758 mp_int_t value_handle = mp_obj_get_int(args[1]);
759 mp_int_t len = mp_obj_get_int(args[2]);
760 bool append = n_args >= 4 && mp_obj_is_true(args[3]);
761 return bluetooth_handle_errno(mp_bluetooth_gatts_set_buffer(value_handle, len, append));
762}
763STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_set_buffer_obj, 3, 4, bluetooth_ble_gatts_set_buffer);
764
765// ----------------------------------------------------------------------------
766// Bluetooth object: GATTC (Central/Scanner role)
767// ----------------------------------------------------------------------------
768
769#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
770
771STATIC mp_obj_t bluetooth_ble_gattc_discover_services(size_t n_args, const mp_obj_t *args) {
772 mp_int_t conn_handle = mp_obj_get_int(args[1]);
773 mp_obj_bluetooth_uuid_t *uuid = NULL;
774 if (n_args == 3 && args[2] != mp_const_none) {
775 if (!mp_obj_is_type(args[2], &mp_type_bluetooth_uuid)) {
776 mp_raise_TypeError(MP_ERROR_TEXT("UUID"));
777 }
778 uuid = MP_OBJ_TO_PTR(args[2]);
779 }
780 return bluetooth_handle_errno(mp_bluetooth_gattc_discover_primary_services(conn_handle, uuid));
781}
782STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_discover_services_obj, 2, 3, bluetooth_ble_gattc_discover_services);
783
784STATIC mp_obj_t bluetooth_ble_gattc_discover_characteristics(size_t n_args, const mp_obj_t *args) {
785 mp_int_t conn_handle = mp_obj_get_int(args[1]);
786 mp_int_t start_handle = mp_obj_get_int(args[2]);
787 mp_int_t end_handle = mp_obj_get_int(args[3]);
788 mp_obj_bluetooth_uuid_t *uuid = NULL;
789 if (n_args == 5 && args[4] != mp_const_none) {
790 if (!mp_obj_is_type(args[4], &mp_type_bluetooth_uuid)) {
791 mp_raise_TypeError(MP_ERROR_TEXT("UUID"));
792 }
793 uuid = MP_OBJ_TO_PTR(args[4]);
794 }
795 return bluetooth_handle_errno(mp_bluetooth_gattc_discover_characteristics(conn_handle, start_handle, end_handle, uuid));
796}
797STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_discover_characteristics_obj, 4, 5, bluetooth_ble_gattc_discover_characteristics);
798
799STATIC mp_obj_t bluetooth_ble_gattc_discover_descriptors(size_t n_args, const mp_obj_t *args) {
800 (void)n_args;
801 mp_int_t conn_handle = mp_obj_get_int(args[1]);
802 mp_int_t start_handle = mp_obj_get_int(args[2]);
803 mp_int_t end_handle = mp_obj_get_int(args[3]);
804 return bluetooth_handle_errno(mp_bluetooth_gattc_discover_descriptors(conn_handle, start_handle, end_handle));
805}
806STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_discover_descriptors_obj, 4, 4, bluetooth_ble_gattc_discover_descriptors);
807
808STATIC mp_obj_t bluetooth_ble_gattc_read(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t value_handle_in) {
809 (void)self_in;
810 mp_int_t conn_handle = mp_obj_get_int(conn_handle_in);
811 mp_int_t value_handle = mp_obj_get_int(value_handle_in);
812 return bluetooth_handle_errno(mp_bluetooth_gattc_read(conn_handle, value_handle));
813}
814STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gattc_read_obj, bluetooth_ble_gattc_read);
815
816STATIC mp_obj_t bluetooth_ble_gattc_write(size_t n_args, const mp_obj_t *args) {
817 mp_int_t conn_handle = mp_obj_get_int(args[1]);
818 mp_int_t value_handle = mp_obj_get_int(args[2]);
819 mp_obj_t data = args[3];
820 mp_buffer_info_t bufinfo = {0};
821 mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
822 size_t len = bufinfo.len;
823 unsigned int mode = MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE;
824 if (n_args == 5) {
825 mode = mp_obj_get_int(args[4]);
826 }
827 return bluetooth_handle_errno(mp_bluetooth_gattc_write(conn_handle, value_handle, bufinfo.buf, &len, mode));
828}
829STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_write_obj, 4, 5, bluetooth_ble_gattc_write);
830
831STATIC mp_obj_t bluetooth_ble_gattc_exchange_mtu(mp_obj_t self_in, mp_obj_t conn_handle_in) {
832 (void)self_in;
833 uint16_t conn_handle = mp_obj_get_int(conn_handle_in);
834 return bluetooth_handle_errno(mp_bluetooth_gattc_exchange_mtu(conn_handle));
835}
836STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gattc_exchange_mtu_obj, bluetooth_ble_gattc_exchange_mtu);
837
838#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
839
840#if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
841
842STATIC mp_obj_t bluetooth_ble_l2cap_listen(mp_obj_t self_in, mp_obj_t psm_in, mp_obj_t mtu_in) {
843 (void)self_in;
844 mp_int_t psm = mp_obj_get_int(psm_in);
845 mp_int_t mtu = mp_obj_get_int(mtu_in);
846 return bluetooth_handle_errno(mp_bluetooth_l2cap_listen(psm, mtu));
847}
848STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_l2cap_listen_obj, bluetooth_ble_l2cap_listen);
849
850STATIC mp_obj_t bluetooth_ble_l2cap_connect(size_t n_args, const mp_obj_t *args) {
851 mp_int_t conn_handle = mp_obj_get_int(args[1]);
852 mp_int_t psm = mp_obj_get_int(args[2]);
853 mp_int_t mtu = mp_obj_get_int(args[3]);
854 return bluetooth_handle_errno(mp_bluetooth_l2cap_connect(conn_handle, psm, mtu));
855}
856STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_l2cap_connect_obj, 4, 4, bluetooth_ble_l2cap_connect);
857
858STATIC mp_obj_t bluetooth_ble_l2cap_disconnect(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t cid_in) {
859 (void)self_in;
860 mp_int_t conn_handle = mp_obj_get_int(conn_handle_in);
861 mp_int_t cid = mp_obj_get_int(cid_in);
862 return bluetooth_handle_errno(mp_bluetooth_l2cap_disconnect(conn_handle, cid));
863}
864STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_l2cap_disconnect_obj, bluetooth_ble_l2cap_disconnect);
865
866STATIC mp_obj_t bluetooth_ble_l2cap_send(size_t n_args, const mp_obj_t *args) {
867 mp_int_t conn_handle = mp_obj_get_int(args[1]);
868 mp_int_t cid = mp_obj_get_int(args[2]);
869 mp_buffer_info_t bufinfo;
870 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
871 bool stalled = false;
872 bluetooth_handle_errno(mp_bluetooth_l2cap_send(conn_handle, cid, bufinfo.buf, bufinfo.len, &stalled));
873 // Return True if the channel is still ready to send.
874 return mp_obj_new_bool(!stalled);
875}
876STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_l2cap_send_obj, 4, 4, bluetooth_ble_l2cap_send);
877
878STATIC mp_obj_t bluetooth_ble_l2cap_recvinto(size_t n_args, const mp_obj_t *args) {
879 mp_int_t conn_handle = mp_obj_get_int(args[1]);
880 mp_int_t cid = mp_obj_get_int(args[2]);
881 mp_buffer_info_t bufinfo = {0};
882 if (args[3] != mp_const_none) {
883 mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_WRITE);
884 }
885 bluetooth_handle_errno(mp_bluetooth_l2cap_recvinto(conn_handle, cid, bufinfo.buf, &bufinfo.len));
886 return MP_OBJ_NEW_SMALL_INT(bufinfo.len);
887}
888STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_l2cap_recvinto_obj, 4, 4, bluetooth_ble_l2cap_recvinto);
889
890#endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
891
892#if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
893
894STATIC mp_obj_t bluetooth_ble_hci_cmd(size_t n_args, const mp_obj_t *args) {
895 mp_int_t ogf = mp_obj_get_int(args[1]);
896 mp_int_t ocf = mp_obj_get_int(args[2]);
897 mp_buffer_info_t bufinfo_request = {0};
898 mp_buffer_info_t bufinfo_response = {0};
899 mp_get_buffer_raise(args[3], &bufinfo_request, MP_BUFFER_READ);
900 mp_get_buffer_raise(args[4], &bufinfo_response, MP_BUFFER_WRITE);
901 uint8_t status = 0;
902 bluetooth_handle_errno(mp_bluetooth_hci_cmd(ogf, ocf, bufinfo_request.buf, bufinfo_request.len, bufinfo_response.buf, bufinfo_response.len, &status));
903 return MP_OBJ_NEW_SMALL_INT(status);
904}
905STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_hci_cmd_obj, 5, 5, bluetooth_ble_hci_cmd);
906
907#endif // MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
908
909// ----------------------------------------------------------------------------
910// Bluetooth object: Definition
911// ----------------------------------------------------------------------------
912
913STATIC const mp_rom_map_elem_t bluetooth_ble_locals_dict_table[] = {
914 // General
915 { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&bluetooth_ble_active_obj) },
916 { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&bluetooth_ble_config_obj) },
917 { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&bluetooth_ble_irq_obj) },
918 // GAP
919 { MP_ROM_QSTR(MP_QSTR_gap_advertise), MP_ROM_PTR(&bluetooth_ble_gap_advertise_obj) },
920 #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
921 { MP_ROM_QSTR(MP_QSTR_gap_connect), MP_ROM_PTR(&bluetooth_ble_gap_connect_obj) },
922 { MP_ROM_QSTR(MP_QSTR_gap_scan), MP_ROM_PTR(&bluetooth_ble_gap_scan_obj) },
923 #endif
924 { MP_ROM_QSTR(MP_QSTR_gap_disconnect), MP_ROM_PTR(&bluetooth_ble_gap_disconnect_obj) },
925 #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
926 { MP_ROM_QSTR(MP_QSTR_gap_pair), MP_ROM_PTR(&bluetooth_ble_gap_pair_obj) },
927 { MP_ROM_QSTR(MP_QSTR_gap_passkey), MP_ROM_PTR(&bluetooth_ble_gap_passkey_obj) },
928 #endif
929 // GATT Server
930 { MP_ROM_QSTR(MP_QSTR_gatts_register_services), MP_ROM_PTR(&bluetooth_ble_gatts_register_services_obj) },
931 { MP_ROM_QSTR(MP_QSTR_gatts_read), MP_ROM_PTR(&bluetooth_ble_gatts_read_obj) },
932 { MP_ROM_QSTR(MP_QSTR_gatts_write), MP_ROM_PTR(&bluetooth_ble_gatts_write_obj) },
933 { MP_ROM_QSTR(MP_QSTR_gatts_notify), MP_ROM_PTR(&bluetooth_ble_gatts_notify_obj) },
934 { MP_ROM_QSTR(MP_QSTR_gatts_indicate), MP_ROM_PTR(&bluetooth_ble_gatts_indicate_obj) },
935 { MP_ROM_QSTR(MP_QSTR_gatts_set_buffer), MP_ROM_PTR(&bluetooth_ble_gatts_set_buffer_obj) },
936 #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
937 // GATT Client
938 { MP_ROM_QSTR(MP_QSTR_gattc_discover_services), MP_ROM_PTR(&bluetooth_ble_gattc_discover_services_obj) },
939 { MP_ROM_QSTR(MP_QSTR_gattc_discover_characteristics), MP_ROM_PTR(&bluetooth_ble_gattc_discover_characteristics_obj) },
940 { MP_ROM_QSTR(MP_QSTR_gattc_discover_descriptors), MP_ROM_PTR(&bluetooth_ble_gattc_discover_descriptors_obj) },
941 { MP_ROM_QSTR(MP_QSTR_gattc_read), MP_ROM_PTR(&bluetooth_ble_gattc_read_obj) },
942 { MP_ROM_QSTR(MP_QSTR_gattc_write), MP_ROM_PTR(&bluetooth_ble_gattc_write_obj) },
943 { MP_ROM_QSTR(MP_QSTR_gattc_exchange_mtu), MP_ROM_PTR(&bluetooth_ble_gattc_exchange_mtu_obj) },
944 #endif
945 #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
946 { MP_ROM_QSTR(MP_QSTR_l2cap_listen), MP_ROM_PTR(&bluetooth_ble_l2cap_listen_obj) },
947 { MP_ROM_QSTR(MP_QSTR_l2cap_connect), MP_ROM_PTR(&bluetooth_ble_l2cap_connect_obj) },
948 { MP_ROM_QSTR(MP_QSTR_l2cap_disconnect), MP_ROM_PTR(&bluetooth_ble_l2cap_disconnect_obj) },
949 { MP_ROM_QSTR(MP_QSTR_l2cap_send), MP_ROM_PTR(&bluetooth_ble_l2cap_send_obj) },
950 { MP_ROM_QSTR(MP_QSTR_l2cap_recvinto), MP_ROM_PTR(&bluetooth_ble_l2cap_recvinto_obj) },
951 #endif
952 #if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
953 { MP_ROM_QSTR(MP_QSTR_hci_cmd), MP_ROM_PTR(&bluetooth_ble_hci_cmd_obj) },
954 #endif
955};
956STATIC MP_DEFINE_CONST_DICT(bluetooth_ble_locals_dict, bluetooth_ble_locals_dict_table);
957
958STATIC const mp_obj_type_t mp_type_bluetooth_ble = {
959 { &mp_type_type },
960 .name = MP_QSTR_BLE,
961 .make_new = bluetooth_ble_make_new,
962 .locals_dict = (void *)&bluetooth_ble_locals_dict,
963};
964
965STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = {
966 { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluetooth) },
967 { MP_ROM_QSTR(MP_QSTR_BLE), MP_ROM_PTR(&mp_type_bluetooth_ble) },
968 { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&mp_type_bluetooth_uuid) },
969
970 // TODO: Deprecate these flags (recommend copying the constants from modbluetooth.h instead).
971 { MP_ROM_QSTR(MP_QSTR_FLAG_READ), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ) },
972 { MP_ROM_QSTR(MP_QSTR_FLAG_WRITE), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE) },
973 { MP_ROM_QSTR(MP_QSTR_FLAG_NOTIFY), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY) },
974 { MP_ROM_QSTR(MP_QSTR_FLAG_INDICATE), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_INDICATE) },
975 { MP_ROM_QSTR(MP_QSTR_FLAG_WRITE_NO_RESPONSE), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_NO_RESPONSE) },
976};
977
978STATIC MP_DEFINE_CONST_DICT(mp_module_bluetooth_globals, mp_module_bluetooth_globals_table);
979
980const mp_obj_module_t mp_module_ubluetooth = {
981 .base = { &mp_type_module },
982 .globals = (mp_obj_dict_t *)&mp_module_bluetooth_globals,
983};
984
985// Helpers
986
987#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
988STATIC 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) {
989 assert(ringbuf_avail(ringbuf) >= n_u16 * 2 + n_u8 + (bytes_addr ? 6 : 0) + n_i8 + (uuid ? 1 : 0) + (bytes_data ? 1 : 0));
990 size_t j = 0;
991
992 for (size_t i = 0; i < n_u16; ++i) {
993 data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT(ringbuf_get16(ringbuf));
994 }
995 for (size_t i = 0; i < n_u8; ++i) {
996 data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT(ringbuf_get(ringbuf));
997 }
998 if (bytes_addr) {
999 bytes_addr->len = 6;
1000 for (size_t i = 0; i < bytes_addr->len; ++i) {
1001 ((uint8_t *)bytes_addr->items)[i] = ringbuf_get(ringbuf);
1002 }
1003 data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_addr);
1004 }
1005 for (size_t i = 0; i < n_i8; ++i) {
1006 // Note the int8_t got packed into the ringbuf as a uint8_t.
1007 data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT((int8_t)ringbuf_get(ringbuf));
1008 }
1009 #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1010 if (uuid) {
1011 ringbuf_get_uuid(ringbuf, uuid);
1012 data_tuple->items[j++] = MP_OBJ_FROM_PTR(uuid);
1013 }
1014 #endif
1015 // The code that enqueues into the ringbuf should ensure that it doesn't
1016 // put more than bt->irq_data_data_alloc bytes into the ringbuf, because
1017 // that's what's available here.
1018 if (bytes_data) {
1019 bytes_data->len = ringbuf_get16(ringbuf);
1020 for (size_t i = 0; i < bytes_data->len; ++i) {
1021 ((uint8_t *)bytes_data->items)[i] = ringbuf_get(ringbuf);
1022 }
1023 data_tuple->items[j++] = MP_OBJ_FROM_PTR(bytes_data);
1024 }
1025
1026 data_tuple->len = j;
1027}
1028
1029STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) {
1030 (void)none_in;
1031 // This is always executing in schedule context.
1032
1033 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1034 o->irq_scheduled = false;
1035
1036 for (;;) {
1037 MICROPY_PY_BLUETOOTH_ENTER
1038
1039 mp_int_t event = ringbuf_get(&o->ringbuf);
1040 if (event < 0) {
1041 // Nothing available in ringbuf.
1042 MICROPY_PY_BLUETOOTH_EXIT
1043 break;
1044 }
1045
1046 // Although we're in schedule context, this code still avoids using any allocations:
1047 // - IRQs are disabled (to protect the ringbuf), and we need to avoid triggering GC
1048 // - The user's handler might not alloc, so we shouldn't either.
1049
1050 mp_obj_t handler = handler = o->irq_handler;
1051 mp_obj_tuple_t *data_tuple = MP_OBJ_TO_PTR(o->irq_data_tuple);
1052
1053 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) {
1054 // conn_handle, addr_type, addr
1055 ringbuf_extract(&o->ringbuf, data_tuple, 1, 1, &o->irq_data_addr, 0, NULL, NULL);
1056 } else if (event == MP_BLUETOOTH_IRQ_CONNECTION_UPDATE) {
1057 // conn_handle, conn_interval, conn_latency, supervision_timeout, status
1058 ringbuf_extract(&o->ringbuf, data_tuple, 5, 0, NULL, 0, NULL, NULL);
1059 } else if (event == MP_BLUETOOTH_IRQ_GATTS_WRITE) {
1060 // conn_handle, value_handle
1061 ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, NULL);
1062 } else if (event == MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE) {
1063 // conn_handle, value_handle, status
1064 ringbuf_extract(&o->ringbuf, data_tuple, 2, 1, NULL, 0, NULL, NULL);
1065 } else if (event == MP_BLUETOOTH_IRQ_MTU_EXCHANGED) {
1066 // conn_handle, mtu
1067 ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, NULL);
1068 #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1069 } else if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT) {
1070 // addr_type, addr, adv_type, rssi, adv_data
1071 ringbuf_extract(&o->ringbuf, data_tuple, 0, 1, &o->irq_data_addr, 2, NULL, &o->irq_data_data);
1072 } else if (event == MP_BLUETOOTH_IRQ_SCAN_DONE) {
1073 // No params required.
1074 data_tuple->len = 0;
1075 #endif
1076 #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1077 } else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT) {
1078 // conn_handle, start_handle, end_handle, uuid
1079 ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, &o->irq_data_uuid, NULL);
1080 } else if (event == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT) {
1081 // conn_handle, def_handle, value_handle, properties, uuid
1082 ringbuf_extract(&o->ringbuf, data_tuple, 3, 1, NULL, 0, &o->irq_data_uuid, NULL);
1083 } else if (event == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT) {
1084 // conn_handle, handle, uuid
1085 ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, &o->irq_data_uuid, NULL);
1086 } else if (event == MP_BLUETOOTH_IRQ_GATTC_SERVICE_DONE || event == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE || event == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_DONE) {
1087 // conn_handle, status
1088 ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, NULL);
1089 } else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_RESULT || event == MP_BLUETOOTH_IRQ_GATTC_NOTIFY || event == MP_BLUETOOTH_IRQ_GATTC_INDICATE) {
1090 // conn_handle, value_handle, data
1091 ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, &o->irq_data_data);
1092 } else if (event == MP_BLUETOOTH_IRQ_GATTC_READ_DONE || event == MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE) {
1093 // conn_handle, value_handle, status
1094 ringbuf_extract(&o->ringbuf, data_tuple, 3, 0, NULL, 0, NULL, NULL);
1095 #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1096 }
1097
1098 MICROPY_PY_BLUETOOTH_EXIT
1099
1100 mp_call_function_2(handler, MP_OBJ_NEW_SMALL_INT(event), MP_OBJ_FROM_PTR(data_tuple));
1101 }
1102
1103 return mp_const_none;
1104}
1105STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_invoke_irq);
1106#endif // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
1107
1108// ----------------------------------------------------------------------------
1109// Port API
1110// ----------------------------------------------------------------------------
1111
1112#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
1113
1114STATIC mp_obj_t invoke_irq_handler(uint16_t event,
1115 const mp_int_t *numeric, size_t n_unsigned, size_t n_signed,
1116 const uint8_t *addr,
1117 const mp_obj_bluetooth_uuid_t *uuid,
1118 const uint8_t **data, size_t *data_len, size_t n_data) {
1119 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1120 if (o->irq_handler == mp_const_none) {
1121 return mp_const_none;
1122 }
1123
1124 mp_obj_array_t mv_addr;
1125 mp_obj_array_t mv_data[2];
1126 assert(n_data <= 2);
1127
1128 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);
1129 data_tuple->base.type = &mp_type_tuple;
1130 data_tuple->len = 0;
1131
1132 for (size_t i = 0; i < n_unsigned; ++i) {
1133 data_tuple->items[data_tuple->len++] = MP_OBJ_NEW_SMALL_INT(numeric[i]);
1134 }
1135 if (addr) {
1136 mp_obj_memoryview_init(&mv_addr, 'B', 0, 6, (void *)addr);
1137 data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_addr);
1138 }
1139 for (size_t i = 0; i < n_signed; ++i) {
1140 data_tuple->items[data_tuple->len++] = MP_OBJ_NEW_SMALL_INT(numeric[i + n_unsigned]);
1141 }
1142 #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1143 if (uuid) {
1144 data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(uuid);
1145 }
1146 #endif
1147 for (size_t i = 0; i < n_data; ++i) {
1148 if (data[i]) {
1149 mp_obj_memoryview_init(&mv_data[i], 'B', 0, data_len[i], (void *)data[i]);
1150 data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_data[i]);
1151 } else {
1152 data_tuple->items[data_tuple->len++] = mp_const_none;
1153 }
1154 }
1155 assert(data_tuple->len <= MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN);
1156
1157 mp_obj_t result = mp_call_function_2(o->irq_handler, MP_OBJ_NEW_SMALL_INT(event), MP_OBJ_FROM_PTR(data_tuple));
1158
1159 mp_local_free(data_tuple);
1160
1161 return result;
1162}
1163
1164#define NULL_NUMERIC NULL
1165#define NULL_ADDR NULL
1166#define NULL_UUID NULL
1167#define NULL_DATA NULL
1168#define NULL_DATA_LEN NULL
1169
1170void mp_bluetooth_gap_on_connected_disconnected(uint8_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr) {
1171 mp_int_t args[] = {conn_handle, addr_type};
1172 invoke_irq_handler(event, args, 2, 0, addr, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1173}
1174
1175void 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) {
1176 mp_int_t args[] = {conn_handle, conn_interval, conn_latency, supervision_timeout, status};
1177 invoke_irq_handler(MP_BLUETOOTH_IRQ_CONNECTION_UPDATE, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1178}
1179
1180#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
1181void mp_bluetooth_gatts_on_encryption_update(uint16_t conn_handle, bool encrypted, bool authenticated, bool bonded, uint8_t key_size) {
1182 mp_int_t args[] = {conn_handle, encrypted, authenticated, bonded, key_size};
1183 invoke_irq_handler(MP_BLUETOOTH_IRQ_ENCRYPTION_UPDATE, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1184}
1185
1186bool 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) {
1187 mp_int_t args[] = {type, index};
1188 mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_GET_SECRET, args, 2, 0, NULL_ADDR, NULL_UUID, &key, &key_len, 1);
1189 if (result == mp_const_none) {
1190 return false;
1191 }
1192 mp_buffer_info_t bufinfo;
1193 mp_get_buffer_raise(result, &bufinfo, MP_BUFFER_READ);
1194 *value = bufinfo.buf;
1195 *value_len = bufinfo.len;
1196 return true;
1197}
1198
1199bool 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) {
1200 mp_int_t args[] = { type };
1201 const uint8_t *data[] = {key, value};
1202 size_t data_len[] = {key_len, value_len};
1203 mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_SET_SECRET, args, 1, 0, NULL_ADDR, NULL_UUID, data, data_len, 2);
1204 return mp_obj_is_true(result);
1205}
1206
1207void mp_bluetooth_gap_on_passkey_action(uint16_t conn_handle, uint8_t action, mp_int_t passkey) {
1208 mp_int_t args[] = { conn_handle, action, passkey };
1209 invoke_irq_handler(MP_BLUETOOTH_IRQ_PASSKEY_ACTION, args, 2, 1, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1210}
1211#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
1212
1213void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
1214 mp_int_t args[] = {conn_handle, value_handle};
1215 invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_WRITE, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1216}
1217
1218void mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle, uint16_t value_handle, uint8_t status) {
1219 mp_int_t args[] = {conn_handle, value_handle, status};
1220 invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE, args, 3, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1221}
1222
1223mp_int_t mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) {
1224 mp_int_t args[] = {conn_handle, value_handle};
1225 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);
1226 // Return non-zero from IRQ handler to fail the read.
1227 mp_int_t ret = 0;
1228 mp_obj_get_int_maybe(result, &ret);
1229 return ret;
1230}
1231
1232void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
1233 mp_int_t args[] = {conn_handle, value};
1234 invoke_irq_handler(MP_BLUETOOTH_IRQ_MTU_EXCHANGED, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1235}
1236
1237#if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
1238mp_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) {
1239 mp_int_t args[] = {conn_handle, cid, psm, our_mtu, peer_mtu};
1240 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);
1241 // Return non-zero from IRQ handler to fail the accept.
1242 mp_int_t ret = 0;
1243 mp_obj_get_int_maybe(result, &ret);
1244 return ret;
1245}
1246
1247void mp_bluetooth_on_l2cap_connect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) {
1248 mp_int_t args[] = {conn_handle, cid, psm, our_mtu, peer_mtu};
1249 invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_CONNECT, args, 5, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1250}
1251
1252void mp_bluetooth_on_l2cap_disconnect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t status) {
1253 mp_int_t args[] = {conn_handle, cid, psm, status};
1254 invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_DISCONNECT, args, 4, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1255}
1256
1257void mp_bluetooth_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status) {
1258 mp_int_t args[] = {conn_handle, cid, status};
1259 invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_SEND_READY, args, 3, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1260}
1261
1262void mp_bluetooth_on_l2cap_recv(uint16_t conn_handle, uint16_t cid) {
1263 mp_int_t args[] = {conn_handle, cid};
1264 invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_RECV, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1265}
1266#endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
1267
1268#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1269void mp_bluetooth_gap_on_scan_complete(void) {
1270 invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_DONE, NULL_NUMERIC, 0, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1271}
1272
1273void 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) {
1274 mp_int_t args[] = {addr_type, adv_type, rssi};
1275 invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_RESULT, args, 1, 2, addr, NULL_UUID, &data, &data_len, 1);
1276}
1277#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1278
1279#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1280void 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) {
1281 mp_int_t args[] = {conn_handle, start_handle, end_handle};
1282 invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT, args, 3, 0, NULL_ADDR, service_uuid, NULL_DATA, NULL_DATA_LEN, 0);
1283}
1284
1285void 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) {
1286 mp_int_t args[] = {conn_handle, def_handle, value_handle, properties};
1287 invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT, args, 4, 0, NULL_ADDR, characteristic_uuid, NULL_DATA, NULL_DATA_LEN, 0);
1288}
1289
1290void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) {
1291 mp_int_t args[] = {conn_handle, handle};
1292 invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT, args, 2, 0, NULL_ADDR, descriptor_uuid, NULL_DATA, NULL_DATA_LEN, 0);
1293}
1294
1295void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status) {
1296 mp_int_t args[] = {conn_handle, status};
1297 invoke_irq_handler(event, args, 2, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1298}
1299
1300void 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) {
1301 const uint8_t *combined_data;
1302 size_t total_len;
1303
1304 if (num > 1) {
1305 // Fragmented buffer, need to combine into a new heap-allocated buffer
1306 // in order to pass to Python.
1307 total_len = 0;
1308 for (size_t i = 0; i < num; ++i) {
1309 total_len += data_len[i];
1310 }
1311 uint8_t *buf = m_new(uint8_t, total_len);
1312 uint8_t *p = buf;
1313 for (size_t i = 0; i < num; ++i) {
1314 memcpy(p, data[i], data_len[i]);
1315 p += data_len[i];
1316 }
1317 combined_data = buf;
1318 } else {
1319 // Single buffer, use directly.
1320 combined_data = *data;
1321 total_len = *data_len;
1322 }
1323
1324 mp_int_t args[] = {conn_handle, value_handle};
1325 invoke_irq_handler(event, args, 2, 0, NULL_ADDR, NULL_UUID, &combined_data, &total_len, 1);
1326
1327 if (num > 1) {
1328 m_del(uint8_t, (uint8_t *)combined_data, total_len);
1329 }
1330}
1331
1332void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status) {
1333 mp_int_t args[] = {conn_handle, value_handle, status};
1334 invoke_irq_handler(event, args, 3, 0, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
1335}
1336
1337#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1338
1339#else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
1340// Callbacks are called in interrupt context (i.e. can't allocate), so we need to push the data
1341// into the ringbuf and schedule the callback via mp_sched_schedule.
1342
1343STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint8_t event) {
1344 if (!o || o->irq_handler == mp_const_none) {
1345 return false;
1346 }
1347
1348 // Check if there is enough room for <event-type><payload>.
1349 if (ringbuf_free(&o->ringbuf) < len + 1) {
1350 // Ringbuffer doesn't have room (and is therefore non-empty).
1351
1352 // If this is another scan result, or the front of the ringbuffer isn't a scan result, then nothing to do.
1353 if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT || ringbuf_peek(&o->ringbuf) != MP_BLUETOOTH_IRQ_SCAN_RESULT) {
1354 return false;
1355 }
1356
1357 // Front of the queue is a scan result, remove it.
1358
1359 // event, addr_type, addr, adv_type, rssi
1360 int n = 1 + 1 + 6 + 1 + 1;
1361 for (int i = 0; i < n; ++i) {
1362 ringbuf_get(&o->ringbuf);
1363 }
1364 // adv_data
1365 n = ringbuf_get(&o->ringbuf);
1366 for (int i = 0; i < n; ++i) {
1367 ringbuf_get(&o->ringbuf);
1368 }
1369 }
1370
1371 // Append this event, the caller will then append the arguments.
1372 ringbuf_put(&o->ringbuf, event);
1373 return true;
1374}
1375
1376// Must hold the atomic section before calling this (MICROPY_PY_BLUETOOTH_ENTER).
1377STATIC void schedule_ringbuf(mp_uint_t atomic_state) {
1378 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1379 if (!o->irq_scheduled) {
1380 o->irq_scheduled = true;
1381 MICROPY_PY_BLUETOOTH_EXIT
1382 mp_sched_schedule(MP_OBJ_FROM_PTR(&bluetooth_ble_invoke_irq_obj), mp_const_none);
1383 } else {
1384 MICROPY_PY_BLUETOOTH_EXIT
1385 }
1386}
1387
1388void mp_bluetooth_gap_on_connected_disconnected(uint8_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr) {
1389 MICROPY_PY_BLUETOOTH_ENTER
1390 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1391 if (enqueue_irq(o, 2 + 1 + 6, event)) {
1392 ringbuf_put16(&o->ringbuf, conn_handle);
1393 ringbuf_put(&o->ringbuf, addr_type);
1394 for (int i = 0; i < 6; ++i) {
1395 ringbuf_put(&o->ringbuf, addr[i]);
1396 }
1397 }
1398 schedule_ringbuf(atomic_state);
1399}
1400
1401void 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) {
1402 MICROPY_PY_BLUETOOTH_ENTER
1403 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1404 if (enqueue_irq(o, 2 + 2 + 2 + 2 + 2, MP_BLUETOOTH_IRQ_CONNECTION_UPDATE)) {
1405 ringbuf_put16(&o->ringbuf, conn_handle);
1406 ringbuf_put16(&o->ringbuf, conn_interval);
1407 ringbuf_put16(&o->ringbuf, conn_latency);
1408 ringbuf_put16(&o->ringbuf, supervision_timeout);
1409 ringbuf_put16(&o->ringbuf, status);
1410 }
1411 schedule_ringbuf(atomic_state);
1412}
1413
1414void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
1415 MICROPY_PY_BLUETOOTH_ENTER
1416 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1417 if (enqueue_irq(o, 2 + 2, MP_BLUETOOTH_IRQ_GATTS_WRITE)) {
1418 ringbuf_put16(&o->ringbuf, conn_handle);
1419 ringbuf_put16(&o->ringbuf, value_handle);
1420 }
1421 schedule_ringbuf(atomic_state);
1422}
1423
1424void mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle, uint16_t value_handle, uint8_t status) {
1425 MICROPY_PY_BLUETOOTH_ENTER
1426 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1427 if (enqueue_irq(o, 2 + 2 + 1, MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE)) {
1428 ringbuf_put16(&o->ringbuf, conn_handle);
1429 ringbuf_put16(&o->ringbuf, value_handle);
1430 ringbuf_put(&o->ringbuf, status);
1431 }
1432 schedule_ringbuf(atomic_state);
1433}
1434
1435mp_int_t mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) {
1436 (void)conn_handle;
1437 (void)value_handle;
1438 // This must be handled synchronously and therefore cannot implemented with the ringbuffer.
1439 return MP_BLUETOOTH_GATTS_NO_ERROR;
1440}
1441
1442void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
1443 MICROPY_PY_BLUETOOTH_ENTER
1444 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1445 if (enqueue_irq(o, 2 + 2, MP_BLUETOOTH_IRQ_MTU_EXCHANGED)) {
1446 ringbuf_put16(&o->ringbuf, conn_handle);
1447 ringbuf_put16(&o->ringbuf, value);
1448 }
1449 schedule_ringbuf(atomic_state);
1450}
1451
1452#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1453void mp_bluetooth_gap_on_scan_complete(void) {
1454 MICROPY_PY_BLUETOOTH_ENTER
1455 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1456 if (enqueue_irq(o, 0, MP_BLUETOOTH_IRQ_SCAN_DONE)) {
1457 }
1458 schedule_ringbuf(atomic_state);
1459}
1460
1461void 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) {
1462 MICROPY_PY_BLUETOOTH_ENTER
1463 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1464 data_len = MIN(o->irq_data_data_alloc, data_len);
1465 if (enqueue_irq(o, 1 + 6 + 1 + 1 + 2 + data_len, MP_BLUETOOTH_IRQ_SCAN_RESULT)) {
1466 ringbuf_put(&o->ringbuf, addr_type);
1467 for (int i = 0; i < 6; ++i) {
1468 ringbuf_put(&o->ringbuf, addr[i]);
1469 }
1470 // The adv_type will get extracted as an int8_t but that's ok because valid values are 0x00-0x04.
1471 ringbuf_put(&o->ringbuf, adv_type);
1472 // Note conversion of int8_t rssi to uint8_t. Must un-convert on the way out.
1473 ringbuf_put(&o->ringbuf, (uint8_t)rssi);
1474 // Length field is 16-bit.
1475 data_len = MIN(UINT16_MAX, data_len);
1476 ringbuf_put16(&o->ringbuf, data_len);
1477 for (size_t i = 0; i < data_len; ++i) {
1478 ringbuf_put(&o->ringbuf, data[i]);
1479 }
1480 }
1481 schedule_ringbuf(atomic_state);
1482}
1483#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
1484
1485#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1486void 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) {
1487 MICROPY_PY_BLUETOOTH_ENTER
1488 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1489 if (enqueue_irq(o, 2 + 2 + 2 + 1 + service_uuid->type, MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT)) {
1490 ringbuf_put16(&o->ringbuf, conn_handle);
1491 ringbuf_put16(&o->ringbuf, start_handle);
1492 ringbuf_put16(&o->ringbuf, end_handle);
1493 ringbuf_put_uuid(&o->ringbuf, service_uuid);
1494 }
1495 schedule_ringbuf(atomic_state);
1496}
1497
1498void 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) {
1499 MICROPY_PY_BLUETOOTH_ENTER
1500 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1501 if (enqueue_irq(o, 2 + 2 + 2 + 1 + characteristic_uuid->type, MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT)) {
1502 ringbuf_put16(&o->ringbuf, conn_handle);
1503 ringbuf_put16(&o->ringbuf, def_handle);
1504 ringbuf_put16(&o->ringbuf, value_handle);
1505 ringbuf_put(&o->ringbuf, properties);
1506 ringbuf_put_uuid(&o->ringbuf, characteristic_uuid);
1507 }
1508 schedule_ringbuf(atomic_state);
1509}
1510
1511void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) {
1512 MICROPY_PY_BLUETOOTH_ENTER
1513 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1514 if (enqueue_irq(o, 2 + 2 + 1 + descriptor_uuid->type, MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT)) {
1515 ringbuf_put16(&o->ringbuf, conn_handle);
1516 ringbuf_put16(&o->ringbuf, handle);
1517 ringbuf_put_uuid(&o->ringbuf, descriptor_uuid);
1518 }
1519 schedule_ringbuf(atomic_state);
1520}
1521
1522void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status) {
1523 MICROPY_PY_BLUETOOTH_ENTER
1524 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1525 if (enqueue_irq(o, 2 + 2, event)) {
1526 ringbuf_put16(&o->ringbuf, conn_handle);
1527 ringbuf_put16(&o->ringbuf, status);
1528 }
1529 schedule_ringbuf(atomic_state);
1530}
1531
1532void 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) {
1533 MICROPY_PY_BLUETOOTH_ENTER
1534 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1535
1536 // Get the total length of the fragmented buffers.
1537 uint16_t total_len = 0;
1538 for (size_t i = 0; i < num; ++i) {
1539 total_len += data_len[i];
1540 }
1541
1542 // Truncate the data at what we'll be able to pass to Python.
1543 total_len = MIN(o->irq_data_data_alloc, total_len);
1544
1545 if (enqueue_irq(o, 2 + 2 + 2 + total_len, event)) {
1546 ringbuf_put16(&o->ringbuf, conn_handle);
1547 ringbuf_put16(&o->ringbuf, value_handle);
1548
1549 ringbuf_put16(&o->ringbuf, total_len);
1550
1551 // Copy total_len from the fragments to the ringbuffer.
1552 uint16_t copied_bytes = 0;
1553 for (size_t i = 0; i < num; ++i) {
1554 for (size_t j = 0; i < data_len[i] && copied_bytes < total_len; ++j) {
1555 ringbuf_put(&o->ringbuf, data[i][j]);
1556 ++copied_bytes;
1557 }
1558 }
1559 }
1560 schedule_ringbuf(atomic_state);
1561}
1562
1563void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status) {
1564 MICROPY_PY_BLUETOOTH_ENTER
1565 mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1566 if (enqueue_irq(o, 2 + 2 + 2, event)) {
1567 ringbuf_put16(&o->ringbuf, conn_handle);
1568 ringbuf_put16(&o->ringbuf, value_handle);
1569 ringbuf_put16(&o->ringbuf, status);
1570 }
1571 schedule_ringbuf(atomic_state);
1572}
1573#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
1574
1575#endif // MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
1576
1577// ----------------------------------------------------------------------------
1578// GATTS DB
1579// ----------------------------------------------------------------------------
1580
1581void mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db, uint16_t handle, size_t len) {
1582 mp_map_elem_t *elem = mp_map_lookup(db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
1583 mp_bluetooth_gatts_db_entry_t *entry = m_new(mp_bluetooth_gatts_db_entry_t, 1);
1584 entry->data = m_new(uint8_t, len);
1585 entry->data_alloc = len;
1586 entry->data_len = 0;
1587 entry->append = false;
1588 elem->value = MP_OBJ_FROM_PTR(entry);
1589}
1590
1591mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, uint16_t handle) {
1592 mp_map_elem_t *elem = mp_map_lookup(db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP);
1593 if (!elem) {
1594 return NULL;
1595 }
1596 return MP_OBJ_TO_PTR(elem->value);
1597}
1598
1599int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len) {
1600 MICROPY_PY_BLUETOOTH_ENTER
1601 mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle);
1602 if (entry) {
1603 *value = entry->data;
1604 *value_len = entry->data_len;
1605 if (entry->append) {
1606 entry->data_len = 0;
1607 }
1608 }
1609 MICROPY_PY_BLUETOOTH_EXIT
1610 return entry ? 0 : MP_EINVAL;
1611}
1612
1613int mp_bluetooth_gatts_db_write(mp_gatts_db_t db, uint16_t handle, const uint8_t *value, size_t value_len) {
1614 MICROPY_PY_BLUETOOTH_ENTER
1615 mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle);
1616 if (entry) {
1617 if (value_len > entry->data_alloc) {
1618 uint8_t *data = m_new_maybe(uint8_t, value_len);
1619 if (data) {
1620 entry->data = data;
1621 entry->data_alloc = value_len;
1622 } else {
1623 MICROPY_PY_BLUETOOTH_EXIT
1624 return MP_ENOMEM;
1625 }
1626 }
1627
1628 memcpy(entry->data, value, value_len);
1629 entry->data_len = value_len;
1630 }
1631 MICROPY_PY_BLUETOOTH_EXIT
1632 return entry ? 0 : MP_EINVAL;
1633}
1634
1635int mp_bluetooth_gatts_db_resize(mp_gatts_db_t db, uint16_t handle, size_t len, bool append) {
1636 MICROPY_PY_BLUETOOTH_ENTER
1637 mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle);
1638 if (entry) {
1639 uint8_t *data = m_renew_maybe(uint8_t, entry->data, entry->data_alloc, len, true);
1640 if (data) {
1641 entry->data = data;
1642 entry->data_alloc = len;
1643 entry->data_len = 0;
1644 entry->append = append;
1645 } else {
1646 MICROPY_PY_BLUETOOTH_EXIT
1647 return MP_ENOMEM;
1648 }
1649 }
1650 MICROPY_PY_BLUETOOTH_EXIT
1651 return entry ? 0 : MP_EINVAL;
1652}
1653
1654#endif // MICROPY_PY_BLUETOOTH
1655