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