· 6 years ago · Feb 04, 2020, 01:06 PM
1/*
2 * Copyright (c) 2019, Pycom Limited.
3 *
4 * This software is licensed under the GNU GPL version 3 or any
5 * later version, with permitted additional terms. For more information
6 * see the Pycom Licence v1.0 document supplied with this file, or
7 * available at https://www.pycom.io/opensource/licensing
8 */
9
10#include <stdint.h>
11#include <stdio.h>
12#include <stdbool.h>
13#include <string.h>
14#include <ctype.h>
15
16#include "controller.h"
17
18#include "py/mpstate.h"
19#include "py/obj.h"
20#include "py/objstr.h"
21#include "py/nlr.h"
22#include "py/runtime.h"
23#include "py/mphal.h"
24#include "py/stream.h"
25#include "bufhelper.h"
26#include "mpexception.h"
27#include "modnetwork.h"
28#include "py/stream.h"
29#include "modusocket.h"
30#include "pycom_config.h"
31#include "modbt.h"
32#include "mpirq.h"
33#include "antenna.h"
34
35#include "esp_bt.h"
36#include "common/bt_trace.h"
37#include "stack/bt_types.h"
38#include "stack/btm_api.h"
39#include "bta/bta_api.h"
40#include "bta/bta_gatt_api.h"
41#include "api/esp_gap_ble_api.h"
42#include "api/esp_gattc_api.h"
43#include "api/esp_gatts_api.h"
44#include "api/esp_gatt_defs.h"
45#include "api/esp_bt_main.h"
46#include "api/esp_gatt_common_api.h"
47
48#include "freertos/FreeRTOS.h"
49#include "freertos/task.h"
50#include "freertos/queue.h"
51#include "freertos/event_groups.h"
52
53#include "lwip/opt.h"
54#include "lwip/def.h"
55
56#include "mbedtls/sha1.h"
57#include "nvs.h"
58
59/******************************************************************************
60 DEFINE PRIVATE CONSTANTS
61 ******************************************************************************/
62#define BT_SCAN_QUEUE_SIZE_MAX (16)
63#define BT_GATTS_QUEUE_SIZE_MAX (2)
64#define BT_MTU_SIZE_MAX (200)
65#define BT_CHAR_VALUE_SIZE_MAX (BT_MTU_SIZE_MAX - 3)
66
67#define MOD_BT_CLIENT_APP_ID (0)
68#define MOD_BT_SERVER_APP_ID (1)
69
70#define MOD_BT_GATTC_ADV_EVT (0x0001)
71#define MOD_BT_GATTS_CONN_EVT (0x0002)
72#define MOD_BT_GATTS_DISCONN_EVT (0x0004)
73#define MOD_BT_GATTS_READ_EVT (0x0008)
74#define MOD_BT_GATTS_WRITE_EVT (0x0010)
75#define MOD_BT_GATTC_NOTIFY_EVT (0x0020)
76#define MOD_BT_GATTC_INDICATE_EVT (0x0040)
77#define MOD_BT_GATTS_SUBSCRIBE_EVT (0x0080)
78#define MOD_BT_GATTC_MTU_EVT (0x0100)
79#define MOD_BT_GATTS_MTU_EVT (0x0200)
80#define MOD_BT_GATTS_CLOSE_EVT (0x0400)
81#define MOD_BT_NVS_NAMESPACE "BT_NVS"
82#define MOD_BT_HASH_SIZE (20)
83#define MOD_BT_PIN_LENGTH (6)
84
85/******************************************************************************
86 DEFINE PRIVATE TYPES
87 ******************************************************************************/
88typedef struct {
89 mp_obj_base_t base;
90 int32_t scan_duration;
91 uint8_t gatts_mtu;
92 mp_obj_t handler;
93 mp_obj_t handler_arg;
94 esp_bd_addr_t client_bda;
95 int32_t gatts_conn_id;
96 uint32_t trigger;
97 int32_t events;
98 uint16_t gatts_if;
99 uint16_t gattc_if;
100 bool init;
101 bool busy;
102 bool scanning;
103 bool advertising;
104 bool controller_active;
105 bool secure;
106} bt_obj_t;
107
108typedef struct {
109 mp_obj_base_t base;
110 mp_obj_list_t srv_list;
111 esp_bd_addr_t srv_bda;
112 int32_t conn_id;
113 uint16_t mtu;
114 esp_gatt_if_t gatt_if;
115} bt_connection_obj_t;
116
117typedef struct {
118 mp_obj_base_t base;
119 mp_obj_list_t char_list;
120 bt_connection_obj_t *connection;
121 esp_gatt_id_t srv_id;
122 uint16_t start_handle;
123 uint16_t end_handle;
124} bt_srv_obj_t;
125
126typedef struct {
127 esp_gatt_id_t srv_id;
128 uint16_t start_handle;
129 uint16_t end_handle;
130} bt_srv_t;
131
132typedef struct {
133 esp_gatt_id_t char_id;
134 esp_gatt_char_prop_t char_prop;
135} bt_char_t;
136
137typedef struct {
138 mp_obj_base_t base;
139 bt_srv_obj_t *service;
140 esp_gattc_char_elem_t characteristic;
141 mp_obj_t handler;
142 mp_obj_t handler_arg;
143 uint32_t trigger;
144 uint32_t events;
145 uint16_t value_len;
146 uint8_t value[BT_CHAR_VALUE_SIZE_MAX];
147 // mp_obj_list_t desc_list;
148} bt_char_obj_t;
149
150typedef struct {
151 uint8_t value[BT_CHAR_VALUE_SIZE_MAX];
152 uint16_t value_len;
153} bt_read_value_t;
154
155typedef struct {
156 esp_gatt_status_t status;
157} bt_write_value_t;
158
159typedef enum {
160 E_BT_STACK_MODE_BLE = 0,
161 E_BT_STACK_MODE_BT
162} bt_mode_t;
163
164typedef struct {
165 int32_t conn_id;
166 esp_bd_addr_t srv_bda;
167 esp_gatt_if_t gatt_if;
168} bt_connection_event_t;
169
170typedef struct {
171 esp_gatt_status_t status;
172} bt_register_for_notify_event_t;
173
174typedef union {
175 esp_ble_gap_cb_param_t scan;
176 bt_srv_t service;
177 bt_read_value_t read;
178 bt_write_value_t write;
179 bt_connection_event_t connection;
180 bt_register_for_notify_event_t register_for_notify;
181} bt_event_result_t;
182
183typedef union {
184 uint16_t service_handle;
185 uint16_t char_handle;
186 uint16_t char_descr_handle;
187 bool adv_set;
188} bt_gatts_event_result_t;
189
190typedef struct {
191 mp_obj_base_t base;
192 uint16_t handle;
193 bool started;
194} bt_gatts_srv_obj_t;
195
196typedef struct {
197 mp_obj_base_t base;
198 mp_obj_t parent;
199 esp_bt_uuid_t uuid;
200 uint32_t properties;
201 uint16_t handle;
202 uint16_t value_len;
203 uint8_t value[BT_CHAR_VALUE_SIZE_MAX];
204 bool is_char;
205} bt_gatts_attr_obj_t;
206
207typedef struct {
208 bt_gatts_attr_obj_t attr_obj;
209 mp_obj_t handler;
210 mp_obj_t handler_arg;
211 uint32_t trigger;
212 uint32_t events;
213 uint32_t trans_id;
214 bool read_request;
215 uint16_t config;
216} bt_gatts_char_obj_t;
217
218typedef union {
219 uint32_t pin;
220 uint8_t value[4];
221} bt_hash_obj_t;
222
223/******************************************************************************
224 DECLARE PRIVATE DATA
225 ******************************************************************************/
226static volatile bt_obj_t bt_obj;
227static QueueHandle_t xScanQueue;
228static QueueHandle_t xGattsQueue;
229
230static esp_ble_adv_data_t adv_data;
231static esp_ble_adv_data_t scan_rsp_data;
232
233static const mp_obj_type_t mod_bt_connection_type;
234static const mp_obj_type_t mod_bt_service_type;
235static const mp_obj_type_t mod_bt_characteristic_type;
236// static const mp_obj_type_t mod_bt_descriptor_type;
237
238static const mp_obj_type_t mod_bt_gatts_service_type;
239static const mp_obj_type_t mod_bt_gatts_char_type;
240
241static esp_ble_adv_params_t bt_adv_params = {
242 .adv_int_min = 0x20,
243 .adv_int_max = 0x40,
244 .adv_type = ADV_TYPE_IND,
245 .own_addr_type = BLE_ADDR_TYPE_PUBLIC,
246 .channel_map = ADV_CHNL_ALL,
247 .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
248};
249
250static esp_ble_adv_params_t bt_adv_params_sec = {
251 .adv_int_min = 0x100,
252 .adv_int_max = 0x100,
253 .adv_type = ADV_TYPE_IND,
254 .own_addr_type = BLE_ADDR_TYPE_RANDOM,
255 .channel_map = ADV_CHNL_ALL,
256 .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
257};
258
259
260static bool mod_bt_allow_resume_deinit;
261static uint16_t mod_bt_gatts_mtu_restore = 0;
262static bool mod_bt_is_conn_restore_available;
263
264static nvs_handle modbt_nvs_handle;
265static uint8_t tx_pwr_level_to_dbm[] = {-12, -9, -6, -3, 0, 3, 6, 9};
266static EventGroupHandle_t bt_event_group;
267static uint16_t bt_conn_mtu = 0;
268/******************************************************************************
269 DECLARE PRIVATE FUNCTIONS
270 ******************************************************************************/
271static void gap_events_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
272static void gattc_events_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param);
273static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
274static void close_connection(int32_t conn_id);
275static esp_err_t modem_sleep(bool enable);
276
277STATIC void bluetooth_callback_handler(void *arg);
278STATIC void gattc_char_callback_handler(void *arg);
279STATIC void gatts_char_callback_handler(void *arg);
280static mp_obj_t modbt_start_scan(mp_obj_t timeout);
281static mp_obj_t modbt_conn_disconnect(mp_obj_t self_in);
282static mp_obj_t modbt_connect(mp_obj_t addr);
283
284/******************************************************************************
285 DEFINE PUBLIC FUNCTIONS
286 ******************************************************************************/
287void modbt_init0(void) {
288 if (!xScanQueue) {
289 xScanQueue = xQueueCreate(BT_SCAN_QUEUE_SIZE_MAX, sizeof(bt_event_result_t));
290 } else {
291 xQueueReset(xScanQueue);
292 }
293 if (!xGattsQueue) {
294 xGattsQueue = xQueueCreate(BT_GATTS_QUEUE_SIZE_MAX, sizeof(bt_gatts_event_result_t));
295 } else {
296 xQueueReset(xGattsQueue);
297 }
298 if(!bt_event_group)
299 {
300 bt_event_group = xEventGroupCreate();
301 }
302 else
303 {
304 //Using only specific events in group for now
305 xEventGroupClearBits(bt_event_group, MOD_BT_GATTC_MTU_EVT | MOD_BT_GATTS_MTU_EVT | MOD_BT_GATTS_DISCONN_EVT | MOD_BT_GATTS_CLOSE_EVT);
306 }
307 bt_event_group = xEventGroupCreate();
308
309 if (bt_obj.init) {
310 esp_ble_gattc_app_unregister(MOD_BT_CLIENT_APP_ID);
311 esp_ble_gatts_app_unregister(MOD_BT_SERVER_APP_ID);
312 }
313
314 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(btc_conn_list), 0);
315 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(bts_srv_list), 0);
316 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(bts_attr_list), 0);
317
318 esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
319
320 mod_bt_allow_resume_deinit = false;
321 mod_bt_is_conn_restore_available = false;
322}
323
324void modbt_deinit(bool allow_reconnect)
325{
326 uint16_t timeout = 0;
327 if (bt_obj.init)
328 {
329 if (bt_obj.scanning) {
330 esp_ble_gap_stop_scanning();
331 bt_obj.scanning = false;
332 }
333 /* Allow reconnection flag */
334 mod_bt_allow_resume_deinit = allow_reconnect;
335
336 bt_connection_obj_t *connection_obj;
337
338 for (mp_uint_t i = 0; i < MP_STATE_PORT(btc_conn_list).len; i++)
339 {
340 // loop through the connections
341 connection_obj = ((bt_connection_obj_t *)(MP_STATE_PORT(btc_conn_list).items[i]));
342 //close connections
343 modbt_conn_disconnect(connection_obj);
344 }
345 while ((MP_STATE_PORT(btc_conn_list).len > 0) && (timeout < 20) && !mod_bt_allow_resume_deinit)
346 {
347 vTaskDelay (50 / portTICK_PERIOD_MS);
348 timeout++;
349 }
350
351 if (bt_obj.gatts_conn_id >= 0)
352 {
353 if (!mod_bt_allow_resume_deinit) {
354 bt_obj.advertising = false;
355 }
356 esp_ble_gatts_close(bt_obj.gatts_if, bt_obj.gatts_conn_id);
357 xEventGroupWaitBits(bt_event_group, MOD_BT_GATTS_DISCONN_EVT | MOD_BT_GATTS_CLOSE_EVT, true, true, 1000/portTICK_PERIOD_MS);
358 }
359
360 esp_bluedroid_disable();
361 esp_bluedroid_deinit();
362 esp_bt_controller_disable();
363 bt_obj.init = false;
364 mod_bt_is_conn_restore_available = false;
365 xEventGroupClearBits(bt_event_group, MOD_BT_GATTC_MTU_EVT | MOD_BT_GATTS_MTU_EVT | MOD_BT_GATTS_DISCONN_EVT | MOD_BT_GATTS_CLOSE_EVT);
366 }
367}
368
369void bt_resume(bool reconnect)
370{
371 if(mod_bt_allow_resume_deinit && !bt_obj.init)
372 {
373 esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
374 esp_bt_controller_init(&bt_cfg);
375
376 esp_bt_controller_enable(ESP_BT_MODE_BLE);
377
378 if (ESP_OK != esp_bluedroid_init()) {
379 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Bluetooth init failed"));
380 }
381 if (ESP_OK != esp_bluedroid_enable()) {
382 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Bluetooth enable failed"));
383 }
384
385 esp_ble_gattc_app_register(MOD_BT_CLIENT_APP_ID);
386 esp_ble_gatts_app_register(MOD_BT_SERVER_APP_ID);
387
388 esp_ble_gatt_set_local_mtu(mod_bt_gatts_mtu_restore);
389
390 bt_connection_obj_t *connection_obj = NULL;
391
392 if(MP_STATE_PORT(btc_conn_list).len > 0)
393 {
394 /* Get the Last gattc connection obj before sleep */
395 connection_obj = ((bt_connection_obj_t *)(MP_STATE_PORT(btc_conn_list).items[MP_STATE_PORT(btc_conn_list).len - 1]));
396 }
397
398 if (reconnect)
399 {
400 /* Check if there was a gattc connection Active before sleep */
401 if (connection_obj != NULL) {
402 if (connection_obj->conn_id >= 0) {
403 /* Enable Scan */
404 modbt_start_scan(MP_OBJ_NEW_SMALL_INT(-1));
405 mp_hal_delay_ms(50);
406 while(!bt_obj.scanning){
407 /* Wait for scanning to start */
408 }
409 /* re-connect to Last Connection */
410 mp_obj_list_remove((void *)&MP_STATE_PORT(btc_conn_list), connection_obj);
411 mp_obj_list_append((void *)&MP_STATE_PORT(btc_conn_list), modbt_connect(mp_obj_new_bytes((const byte *)connection_obj->srv_bda, 6)));
412
413 mod_bt_is_conn_restore_available = true;
414 }
415 }
416
417 /* See if there was an averstisment active before Sleep */
418 if(bt_obj.advertising) {
419 if (!bt_obj.secure){
420 esp_ble_gap_start_advertising(&bt_adv_params);
421 } else {
422 esp_ble_gap_start_advertising(&bt_adv_params_sec);
423 }
424 }
425 }
426
427 bt_obj.init = true;
428 mod_bt_allow_resume_deinit = false;
429 }
430}
431
432/******************************************************************************
433 DEFINE PRIVATE FUNCTIONS
434 ******************************************************************************/
435static esp_gatt_status_t status = ESP_GATT_ERROR;
436
437static esp_ble_scan_params_t ble_scan_params = {
438 .scan_type = BLE_SCAN_TYPE_ACTIVE,
439 .own_addr_type = BLE_ADDR_TYPE_PUBLIC,
440 .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
441 .scan_interval = 0x50,
442 .scan_window = 0x30
443};
444
445STATIC mp_obj_t bt_nvram_erase (mp_obj_t self_in) {
446 if (nvs_open(MOD_BT_NVS_NAMESPACE, NVS_READWRITE, &modbt_nvs_handle) != ESP_OK) {
447 mp_printf(&mp_plat_print, "Error opening secure BLE NVS namespace!\n");
448 }
449
450 if (ESP_OK != nvs_erase_all(modbt_nvs_handle)) {
451 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
452 }
453 nvs_commit(modbt_nvs_handle);
454 nvs_close(modbt_nvs_handle);
455
456 return mp_const_none;
457}
458STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_nvram_erase_obj, bt_nvram_erase);
459
460static void create_hash(uint32_t pin, uint8_t *h_value)
461{
462 bt_hash_obj_t pin_hash;
463 mbedtls_sha1_context sha1_context;
464
465 mbedtls_sha1_init(&sha1_context);
466 mbedtls_sha1_starts_ret(&sha1_context);
467
468 pin_hash.pin = pin;
469 mbedtls_sha1_update_ret(&sha1_context, pin_hash.value, 4);
470
471 mbedtls_sha1_finish_ret(&sha1_context, h_value);
472 mbedtls_sha1_free(&sha1_context);
473}
474
475static bool is_pin_valid(uint32_t pin)
476{
477 int digits = 0;
478
479 while(pin != 0)
480 {
481 digits++;
482 pin /= 10;
483 }
484
485 if (digits != MOD_BT_PIN_LENGTH){
486 return false;
487 }
488
489 return true;
490}
491static bool pin_changed(uint32_t new_pin)
492{
493 bool ret = false;
494 uint32_t h_size = MOD_BT_HASH_SIZE;
495 uint8_t h_stored[MOD_BT_HASH_SIZE] = {0};
496 uint8_t h_created[MOD_BT_HASH_SIZE] = {0};
497 const char *key = "bt_pin_hash";
498 esp_err_t esp_err = ESP_OK;
499
500 if (nvs_open(MOD_BT_NVS_NAMESPACE, NVS_READWRITE, &modbt_nvs_handle) != ESP_OK) {
501 mp_printf(&mp_plat_print, "Error opening secure BLE NVS namespace!\n");
502 }
503 nvs_get_blob(modbt_nvs_handle, key, h_stored, &h_size);
504
505 create_hash(new_pin, h_created);
506
507 if (memcmp(h_stored, h_created, MOD_BT_HASH_SIZE) != 0) {
508 esp_err = nvs_set_blob(modbt_nvs_handle, key, h_created, h_size);
509 if (esp_err == ESP_OK) {
510 nvs_commit(modbt_nvs_handle);
511 ret = true;
512 }
513 }
514
515 nvs_close(modbt_nvs_handle);
516
517 return ret;
518}
519
520static void remove_all_bonded_devices(void)
521{
522 int dev_num = esp_ble_get_bond_device_num();
523
524 esp_ble_bond_dev_t *dev_list = heap_caps_malloc(sizeof(esp_ble_bond_dev_t) * dev_num, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
525 esp_ble_get_bond_device_list(&dev_num, dev_list);
526 for (int i = 0; i < dev_num; i++) {
527 esp_ble_remove_bond_device(dev_list[i].bd_addr);
528 }
529
530 free(dev_list);
531}
532
533static void set_secure_parameters(uint32_t passKey){
534
535 if (pin_changed(passKey)) {
536 remove_all_bonded_devices();
537 }
538
539 uint32_t passkey = passKey;
540 esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
541
542 esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND;
543 esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
544
545 esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT;
546 esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
547
548 uint8_t key_size = 16;
549 esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
550
551 uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE;
552 esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
553
554 uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
555 esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
556
557 uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
558 esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
559}
560
561static void close_connection (int32_t conn_id) {
562 for (mp_uint_t i = 0; i < MP_STATE_PORT(btc_conn_list).len; i++) {
563 bt_connection_obj_t *connection_obj = ((bt_connection_obj_t *)(MP_STATE_PORT(btc_conn_list).items[i]));
564 /* Only reset Conn Id if it is a normal disconnect not module de-init to mark conn obj to be restored */
565 if (connection_obj->conn_id == conn_id && (!mod_bt_allow_resume_deinit)) {
566 connection_obj->conn_id = -1;
567 mp_obj_list_remove((void *)&MP_STATE_PORT(btc_conn_list), connection_obj);
568 }
569 }
570}
571
572static esp_err_t modem_sleep(bool enable)
573{
574 esp_err_t err = esp_bt_controller_get_status();
575
576 if(enable)
577 {
578 /* Enable Modem Sleep */
579 err = esp_bt_sleep_enable();
580 }
581 else
582 {
583 /* Disable Modem Sleep */
584 err = esp_bt_sleep_disable();
585
586 /* Wakeup the modem is it is sleeping */
587 if (esp_bt_controller_is_sleeping() && err == ESP_OK)
588 {
589 esp_bt_controller_wakeup_request();
590 }
591 }
592 return err;
593}
594
595static bt_char_obj_t *find_gattc_char (int32_t conn_id, uint16_t char_handle) {
596 for (mp_uint_t i = 0; i < MP_STATE_PORT(btc_conn_list).len; i++) {
597 // search through the connections
598 bt_connection_obj_t *connection_obj = ((bt_connection_obj_t *)(MP_STATE_PORT(btc_conn_list).items[i]));
599 if (connection_obj->conn_id == conn_id) {
600 // search through the services
601 for (mp_uint_t j = 0; j < connection_obj->srv_list.len; j++) {
602 // search through the characteristics
603 bt_srv_obj_t *srv_obj = ((bt_srv_obj_t *)(connection_obj->srv_list.items[j]));
604 for (mp_uint_t j = 0; j < srv_obj->char_list.len; j++) {
605 bt_char_obj_t *char_obj = ((bt_char_obj_t *)(srv_obj->char_list.items[j]));
606 if (char_obj->characteristic.char_handle == char_handle) {
607 return char_obj;
608 }
609 }
610 }
611 }
612 }
613 return NULL;
614}
615
616static bt_gatts_attr_obj_t *find_gatts_attr_by_handle (uint16_t handle) {
617 for (mp_uint_t i = 0; i < MP_STATE_PORT(bts_attr_list).len; i++) {
618 bt_gatts_attr_obj_t *char_obj = ((bt_gatts_attr_obj_t *)(MP_STATE_PORT(bts_attr_list).items[i]));
619 if (char_obj->handle == handle) {
620 return char_obj;
621 }
622 }
623 return NULL;
624}
625
626static void gap_events_handler (esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
627 switch (event) {
628 case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
629 int32_t duration = bt_obj.scan_duration;
630 // the unit of the duration is seconds
631 if (duration < 0) {
632 duration = 0x0FFF;
633 }
634 esp_ble_gap_start_scanning(duration);
635 break;
636 }
637 case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: {
638 bt_gatts_event_result_t gatts_event;
639 gatts_event.adv_set = true;
640 xQueueSend(xGattsQueue, (void *)&gatts_event, (TickType_t)0);
641 break;
642 }
643 case ESP_GAP_BLE_PASSKEY_REQ_EVT: { /* passkey request event */
644 //esp_ble_passkey_reply(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, true, 0x00);
645 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Passkey Req"));
646 ESP_LOGI(GATTC_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT");
647 break;
648 }
649 case ESP_GAP_BLE_NC_REQ_EVT:
650 case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: {
651 printf("BLE paring passkey : %d\n", param->ble_security.key_notif.passkey);
652 break;
653 }
654 case ESP_GAP_BLE_SEC_REQ_EVT: {
655 if (bt_obj.secure){
656 esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
657 }
658 }
659 case ESP_GAP_BLE_SCAN_RESULT_EVT: {
660 bt_event_result_t bt_event_result;
661 esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
662 memcpy(&bt_event_result.scan, scan_result, sizeof(esp_ble_gap_cb_param_t));
663 switch (scan_result->scan_rst.search_evt) {
664 case ESP_GAP_SEARCH_INQ_RES_EVT:
665 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
666 bt_obj.events |= MOD_BT_GATTC_ADV_EVT;
667 if (bt_obj.trigger & MOD_BT_GATTC_ADV_EVT) {
668 mp_irq_queue_interrupt(bluetooth_callback_handler, (void *)&bt_obj);
669 }
670 break;
671 case ESP_GAP_SEARCH_DISC_RES_EVT:
672 break;
673 case ESP_GAP_SEARCH_INQ_CMPL_EVT:
674 if (bt_obj.scan_duration < 0) {
675 esp_ble_gap_set_scan_params(&ble_scan_params);
676 } else {
677 bt_obj.scanning = false;
678 }
679 break;
680 default:
681 break;
682 }
683 break;
684 }
685 default:
686 break;
687 }
688}
689
690static void gattc_events_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
691 int32_t conn_id = 0;
692 esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param;
693 bt_event_result_t bt_event_result;
694
695 switch (event) {
696 case ESP_GATTC_REG_EVT:
697 status = p_data->reg.status;
698 bt_obj.gattc_if = gattc_if;
699
700 esp_ble_gap_config_local_privacy(true);
701
702 break;
703 case ESP_GATTC_OPEN_EVT:
704 if (p_data->open.status != ESP_GATT_OK) {
705 bt_event_result.connection.conn_id = -1;
706 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
707 bt_obj.busy = false;
708 }
709 break;
710 case ESP_GATTC_CONNECT_EVT:
711 conn_id = p_data->connect.conn_id;
712 bt_event_result.connection.conn_id = conn_id;
713 bt_event_result.connection.gatt_if = gattc_if;
714 memcpy(bt_event_result.connection.srv_bda, p_data->connect.remote_bda, ESP_BD_ADDR_LEN);
715 esp_ble_gattc_send_mtu_req (gattc_if, p_data->connect.conn_id);
716 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
717 break;
718 case ESP_GATTC_CFG_MTU_EVT:
719 // connection process and MTU request complete
720 bt_obj.busy = false;
721 bt_conn_mtu = p_data->cfg_mtu.mtu;
722 xEventGroupSetBits(bt_event_group, MOD_BT_GATTC_MTU_EVT);
723 break;
724 case ESP_GATTC_READ_CHAR_EVT:
725 if (p_data->read.status == ESP_GATT_OK) {
726 uint16_t read_len = p_data->read.value_len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : p_data->read.value_len;
727 memcpy(&bt_event_result.read.value, p_data->read.value, read_len);
728 bt_event_result.read.value_len = read_len;
729 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
730 }
731 bt_obj.busy = false;
732 break;
733 case ESP_GATTC_WRITE_CHAR_EVT:
734 bt_event_result.write.status = p_data->write.status;
735 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
736 bt_obj.busy = false;
737 break;
738 case ESP_GATTC_SEARCH_RES_EVT: {
739 esp_gatt_id_t *srvc_id = (esp_gatt_id_t *)&p_data->search_res.srvc_id;
740 memcpy(&bt_event_result.service.srv_id, srvc_id, sizeof(esp_gatt_id_t));
741 bt_event_result.service.start_handle = p_data->search_res.start_handle;
742 bt_event_result.service.end_handle = p_data->search_res.end_handle;
743 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
744 break;
745 }
746 case ESP_GATTC_READ_DESCR_EVT:
747 if (p_data->read.status == ESP_GATT_OK) {
748 uint16_t read_len = p_data->read.value_len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : p_data->read.value_len;
749 memcpy(&bt_event_result.read.value, p_data->read.value, read_len);
750 bt_event_result.read.value_len = read_len;
751 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
752 }
753 bt_obj.busy = false;
754 break;
755 case ESP_GATTC_REG_FOR_NOTIFY_EVT:
756 bt_event_result.register_for_notify.status = p_data->reg_for_notify.status;
757 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
758 break;
759 case ESP_GATTC_NOTIFY_EVT: {
760 bt_char_obj_t *char_obj;
761 char_obj = find_gattc_char (p_data->notify.conn_id, p_data->notify.handle);
762 if (char_obj != NULL) {
763 // copy the new value into the characteristic
764 memcpy(&char_obj->value, p_data->notify.value, p_data->notify.value_len);
765 char_obj->value_len = p_data->notify.value_len;
766
767 // register the event
768 if (p_data->notify.is_notify) {
769 char_obj->events |= MOD_BT_GATTC_NOTIFY_EVT;
770 } else {
771 char_obj->events |= MOD_BT_GATTC_INDICATE_EVT;
772 }
773 if ((char_obj->trigger & MOD_BT_GATTC_NOTIFY_EVT) || (char_obj->trigger & MOD_BT_GATTC_INDICATE_EVT)) {
774 mp_irq_queue_interrupt(gattc_char_callback_handler, char_obj);
775 }
776 }
777 break;
778 }
779 case ESP_GATTC_SEARCH_CMPL_EVT:
780 case ESP_GATTC_CANCEL_OPEN_EVT:
781 bt_obj.busy = false;
782 break;
783 // intentional fall through
784 case ESP_GATTC_CLOSE_EVT:
785 case ESP_GATTC_DISCONNECT_EVT:
786 close_connection(p_data->close.conn_id);
787 bt_obj.busy = false;
788 break;
789 default:
790 break;
791 }
792}
793
794// this function will be called by the interrupt thread
795STATIC void bluetooth_callback_handler(void *arg) {
796 bt_obj_t *self = arg;
797
798 if (self->handler && self->handler != mp_const_none) {
799 mp_call_function_1(self->handler, self->handler_arg);
800 }
801}
802
803// this function will be called by the interrupt thread
804STATIC void gattc_char_callback_handler(void *arg) {
805 bt_char_obj_t *chr = arg;
806
807 if (chr->handler && chr->handler != mp_const_none) {
808 mp_call_function_1(chr->handler, chr->handler_arg);
809 }
810}
811
812// this function will be called by the interrupt thread
813STATIC void gatts_char_callback_handler(void *arg) {
814 bt_gatts_char_obj_t *chr = arg;
815
816 if (chr->handler && chr->handler != mp_const_none) {
817 mp_obj_t r_value = mp_call_function_1(chr->handler, chr->handler_arg);
818
819 if (chr->read_request) {
820 uint32_t u_value;
821 uint8_t *value;
822 uint8_t value_l = 1;
823
824 chr->read_request = false;
825 if (r_value != mp_const_none) {
826 if (mp_obj_is_integer(r_value)) {
827 u_value = mp_obj_get_int_truncated(r_value);
828 value = (uint8_t *)&u_value;
829 if (u_value > UINT16_MAX) {
830 value_l = 4;
831 u_value = lwip_htonl(u_value);
832 } else if (u_value > UINT8_MAX) {
833 value_l = 2;
834 u_value = lwip_htons(u_value);
835 }
836 } else {
837 mp_buffer_info_t bufinfo;
838 mp_get_buffer_raise(r_value, &bufinfo, MP_BUFFER_READ);
839 value = bufinfo.buf;
840 value_l = bufinfo.len;
841 }
842 } else {
843 value = chr->attr_obj.value;
844 value_l = chr->attr_obj.value_len;
845 }
846
847 esp_gatt_rsp_t rsp;
848 memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
849 rsp.attr_value.handle = chr->attr_obj.handle;
850 rsp.attr_value.len = value_l;
851 memcpy(&rsp.attr_value.value, value, value_l);
852 esp_ble_gatts_send_response(bt_obj.gatts_if, bt_obj.gatts_conn_id, chr->trans_id, ESP_GATT_OK, &rsp);
853 }
854 }
855}
856
857static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
858 esp_ble_gatts_cb_param_t *p = (esp_ble_gatts_cb_param_t *)param;
859
860 switch (event) {
861 case ESP_GATTS_REG_EVT:
862 bt_obj.gatts_if = gatts_if;
863 if (bt_obj.secure){
864 esp_ble_gap_config_local_privacy(true);
865 }
866 break;
867 case ESP_GATTS_READ_EVT: {
868 bt_gatts_attr_obj_t *attr_obj = find_gatts_attr_by_handle (p->read.handle);
869 if (attr_obj) {
870 if (attr_obj->is_char) {
871 bt_gatts_char_obj_t *char_obj = (bt_gatts_char_obj_t *)attr_obj;
872 char_obj->events |= MOD_BT_GATTS_READ_EVT;
873 if (char_obj->trigger & MOD_BT_GATTS_READ_EVT) {
874 char_obj->read_request = true;
875 char_obj->trans_id = p->read.trans_id;
876 mp_irq_queue_interrupt(gatts_char_callback_handler, char_obj);
877 break;
878 }
879 }
880 // send the response immediately if it's not a characteristic or if there's no callback registered
881 esp_gatt_rsp_t rsp;
882 memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
883 rsp.attr_value.handle = p->read.handle;
884 rsp.attr_value.len = attr_obj->value_len;
885 memcpy(&rsp.attr_value.value, attr_obj->value, attr_obj->value_len);
886 esp_ble_gatts_send_response(gatts_if, p->read.conn_id, p->read.trans_id, ESP_GATT_OK, &rsp);
887 }
888 break;
889 }
890 case ESP_GATTS_WRITE_EVT: {
891 if (!p->write.is_prep) {
892 bt_gatts_attr_obj_t *attr_obj = find_gatts_attr_by_handle (p->write.handle);
893 if (attr_obj) {
894 // only write up to the maximum allowed size
895 uint16_t write_len = p->write.len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : p->write.len;
896 memcpy(attr_obj->value, p->write.value, write_len);
897 attr_obj->value_len = write_len;
898
899 if (attr_obj->is_char) { // characteristic
900 bt_gatts_char_obj_t *char_obj = (bt_gatts_char_obj_t *)attr_obj;
901 char_obj->events |= MOD_BT_GATTS_WRITE_EVT;
902 if (char_obj->trigger & MOD_BT_GATTS_WRITE_EVT) {
903 mp_irq_queue_interrupt(gatts_char_callback_handler, char_obj);
904 }
905 } else { // descriptor
906 if (attr_obj->uuid.len == ESP_UUID_LEN_16 && attr_obj->uuid.uuid.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) {
907 uint16_t value = param->write.value[1] << 8 | param->write.value[0];
908 bt_gatts_char_obj_t *char_obj = (bt_gatts_char_obj_t *)attr_obj->parent;
909 char_obj->config = value;
910 char_obj->events |= MOD_BT_GATTS_SUBSCRIBE_EVT;
911 if (char_obj->trigger & MOD_BT_GATTS_SUBSCRIBE_EVT) {
912 mp_irq_queue_interrupt(gatts_char_callback_handler, char_obj);
913 }
914
915 if (value == 0x0001) { // notifications enabled
916 bt_gatts_char_obj_t *char_obj = (bt_gatts_char_obj_t *)attr_obj->parent;
917 // the size of value[] needs to be less than MTU size
918 esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, char_obj->attr_obj.handle, char_obj->attr_obj.value_len, char_obj->attr_obj.value, false);
919 }
920 }
921 }
922 esp_ble_gatts_send_response(gatts_if, p->write.conn_id, p->write.trans_id, ESP_GATT_OK, NULL);
923 }
924 }
925 break;
926 }
927 case ESP_GATTS_MTU_EVT:
928 bt_obj.gatts_mtu = p->mtu.mtu;
929 xEventGroupSetBits(bt_event_group, MOD_BT_GATTS_MTU_EVT);
930 break;
931 case ESP_GATTS_EXEC_WRITE_EVT:
932 case ESP_GATTS_CONF_EVT:
933 case ESP_GATTS_UNREG_EVT:
934 break;
935 case ESP_GATTS_CREATE_EVT: {
936 bt_gatts_event_result_t gatts_event;
937 gatts_event.service_handle = p->create.service_handle;
938 xQueueSend(xGattsQueue, (void *)&gatts_event, (TickType_t)0);
939 break;
940 }
941 case ESP_GATTS_ADD_INCL_SRVC_EVT:
942 break;
943 case ESP_GATTS_ADD_CHAR_EVT: {
944 bt_gatts_event_result_t gatts_event;
945 gatts_event.char_handle = p->add_char.attr_handle;
946 xQueueSend(xGattsQueue, (void *)&gatts_event, (TickType_t)0);
947 break;
948 }
949 case ESP_GATTS_ADD_CHAR_DESCR_EVT: {
950 bt_gatts_event_result_t gatts_event;
951 gatts_event.char_descr_handle = p->add_char_descr.attr_handle;
952 xQueueSend(xGattsQueue, (void *)&gatts_event, (TickType_t)0);
953 break;
954 }
955 case ESP_GATTS_DELETE_EVT:
956 break;
957 case ESP_GATTS_START_EVT:
958 break;
959 case ESP_GATTS_STOP_EVT:
960 break;
961 case ESP_GATTS_CONNECT_EVT:
962 // only allow one connection at a time
963 if (bt_obj.gatts_conn_id >= 0) {
964 esp_ble_gatts_close(bt_obj.gatts_if, p->connect.conn_id);
965 } else {
966 memcpy((void *)bt_obj.client_bda, p->connect.remote_bda, ESP_BD_ADDR_LEN);
967 bt_obj.gatts_conn_id = p->connect.conn_id;
968 bt_obj.events |= MOD_BT_GATTS_CONN_EVT;
969 if (bt_obj.trigger & MOD_BT_GATTS_CONN_EVT) {
970 mp_irq_queue_interrupt(bluetooth_callback_handler, (void *)&bt_obj);
971 }
972 if (bt_obj.secure){
973 esp_ble_set_encryption(p->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM);
974 }
975 }
976 break;
977 case ESP_GATTS_DISCONNECT_EVT:
978 bt_obj.gatts_conn_id = -1;
979 xEventGroupClearBits(bt_event_group, MOD_BT_GATTS_MTU_EVT);
980 if (bt_obj.advertising) {
981 if (!bt_obj.secure){
982 esp_ble_gap_start_advertising(&bt_adv_params);
983 } else {
984 esp_ble_gap_start_advertising(&bt_adv_params_sec);
985 }
986 }
987 bt_obj.events |= MOD_BT_GATTS_DISCONN_EVT;
988 xEventGroupSetBits(bt_event_group, MOD_BT_GATTS_DISCONN_EVT);
989 if (bt_obj.trigger & MOD_BT_GATTS_DISCONN_EVT) {
990 mp_irq_queue_interrupt(bluetooth_callback_handler, (void *)&bt_obj);
991 }
992 break;
993 case ESP_GATTS_CLOSE_EVT:
994 xEventGroupSetBits(bt_event_group, MOD_BT_GATTS_CLOSE_EVT);
995 break;
996 case ESP_GATTS_OPEN_EVT:
997 case ESP_GATTS_CANCEL_OPEN_EVT:
998 case ESP_GATTS_LISTEN_EVT:
999 case ESP_GATTS_CONGEST_EVT:
1000 default:
1001 break;
1002 }
1003}
1004
1005/******************************************************************************/
1006// Micro Python bindings; BT class
1007
1008/// \class Bluetooth
1009static mp_obj_t bt_init_helper(bt_obj_t *self, const mp_arg_val_t *args) {
1010 if (!self->init) {
1011 if (!self->controller_active) {
1012 esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
1013 esp_bt_controller_init(&bt_cfg);
1014 self->controller_active = true;
1015 }
1016
1017 esp_bt_controller_enable(ESP_BT_MODE_BLE);
1018
1019 if (ESP_OK != esp_bluedroid_init()) {
1020 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Bluetooth init failed"));
1021 }
1022 if (ESP_OK != esp_bluedroid_enable()) {
1023 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Bluetooth enable failed"));
1024 }
1025
1026 esp_ble_gap_register_callback(gap_events_handler);
1027 esp_ble_gattc_register_callback(gattc_events_handler);
1028 esp_ble_gatts_register_callback(gatts_event_handler);
1029
1030 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(btc_conn_list), 0);
1031 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(bts_srv_list), 0);
1032 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(bts_attr_list), 0);
1033 esp_ble_gattc_app_register(MOD_BT_CLIENT_APP_ID);
1034 esp_ble_gatts_app_register(MOD_BT_SERVER_APP_ID);
1035
1036 //set MTU
1037 uint16_t mtu = args[5].u_int;
1038 if(mtu > BT_MTU_SIZE_MAX)
1039 {
1040 esp_ble_gatt_set_local_mtu(BT_MTU_SIZE_MAX);
1041 mod_bt_gatts_mtu_restore = BT_MTU_SIZE_MAX;
1042 }
1043 else
1044 {
1045 esp_ble_gatt_set_local_mtu(mtu);
1046 mod_bt_gatts_mtu_restore = mtu;
1047 }
1048
1049 self->init = true;
1050 }
1051
1052 // get the antenna type
1053 uint8_t antenna;
1054 if (args[1].u_obj == MP_OBJ_NULL) {
1055 // first gen module, so select the internal antenna
1056 if (micropy_hw_antenna_diversity_pin_num == MICROPY_FIRST_GEN_ANT_SELECT_PIN_NUM) {
1057 antenna = ANTENNA_TYPE_INTERNAL;
1058 } else {
1059 antenna = ANTENNA_TYPE_MANUAL;
1060 }
1061 } else if (args[1].u_obj == mp_const_none) {
1062 antenna = ANTENNA_TYPE_MANUAL;
1063 } else {
1064 antenna = mp_obj_get_int(args[1].u_obj);
1065 }
1066 antenna_validate_antenna(antenna);
1067 antenna_select(antenna);
1068
1069 bt_obj.gatts_conn_id = -1;
1070
1071
1072 /* Set BLE modem sleep flag*/
1073 if (args[2].u_obj != MP_OBJ_NULL) {
1074 esp_err_t err = modem_sleep(mp_obj_is_true(args[2].u_obj));
1075 if(ESP_OK != err)
1076 {
1077 nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err)));
1078 }
1079 }
1080
1081 if (args[3].u_bool){
1082 bt_obj.secure = true;
1083
1084 uint32_t passKey = args[4].u_int;
1085 if (!is_pin_valid(passKey)){
1086 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Only 6 digit (0-9) pins are allowed"));
1087 }
1088 set_secure_parameters(passKey);
1089 }
1090
1091 return mp_const_none;
1092}
1093
1094STATIC const mp_arg_t bt_init_args[] = {
1095 { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
1096 { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = E_BT_STACK_MODE_BLE} },
1097 { MP_QSTR_antenna, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
1098 { MP_QSTR_modem_sleep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
1099 { MP_QSTR_secure, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
1100 { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 123456} },
1101 { MP_QSTR_mtu, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BT_MTU_SIZE_MAX} },
1102
1103};
1104STATIC mp_obj_t bt_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
1105 // parse args
1106 mp_map_t kw_args;
1107 mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
1108 // parse args
1109 mp_arg_val_t args[MP_ARRAY_SIZE(bt_init_args)];
1110 mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), bt_init_args, args);
1111
1112 // setup the object
1113 bt_obj_t *self = (bt_obj_t *)&bt_obj;
1114 self->base.type = (mp_obj_t)&mod_network_nic_type_bt;
1115
1116 // check the peripheral id
1117 if (args[0].u_int != 0) {
1118 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
1119 }
1120
1121 if (args[4].u_bool) {
1122 if (heap_caps_get_free_size(MALLOC_CAP_SPIRAM) == 0) {
1123 nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError,"Secure BLE not available for 512K RAM devices"));
1124 }
1125 }
1126
1127 // run the constructor if the peripehral is not initialized or extra parameters are given
1128 if (n_kw > 0 || !self->init) {
1129 // start the peripheral
1130 bt_init_helper(self, &args[1]);
1131 }
1132
1133 return (mp_obj_t)self;
1134}
1135
1136STATIC mp_obj_t bt_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1137 // parse args
1138 mp_arg_val_t args[MP_ARRAY_SIZE(bt_init_args) - 1];
1139 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &bt_init_args[1], args);
1140 return bt_init_helper(pos_args[0], args);
1141}
1142STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_init_obj, 1, bt_init);
1143
1144mp_obj_t bt_deinit(mp_obj_t self_in) {
1145
1146 MP_THREAD_GIL_EXIT();
1147 modbt_deinit(false);
1148 MP_THREAD_GIL_ENTER();
1149 return mp_const_none;
1150}
1151STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_deinit_obj, bt_deinit);
1152
1153STATIC mp_obj_t bt_start_scan(mp_obj_t self_in, mp_obj_t timeout) {
1154 if (bt_obj.scanning || bt_obj.busy) {
1155 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "operation already in progress"));
1156 }
1157
1158 int32_t duration = mp_obj_get_int(timeout);
1159 if (duration == 0) {
1160 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid scan time"));
1161 }
1162
1163 bt_obj.scan_duration = duration;
1164 bt_obj.scanning = true;
1165 xQueueReset(xScanQueue);
1166 if (ESP_OK != esp_ble_gap_set_scan_params(&ble_scan_params)) {
1167 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1168 }
1169
1170 return mp_const_none;
1171}
1172STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_start_scan_obj, bt_start_scan);
1173
1174static mp_obj_t modbt_start_scan(mp_obj_t timeout)
1175{
1176 return bt_start_scan(NULL, timeout);
1177}
1178
1179STATIC mp_obj_t bt_isscanning(mp_obj_t self_in) {
1180 if (bt_obj.scanning) {
1181 return mp_const_true;
1182 }
1183 return mp_const_false;
1184}
1185STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_isscanning_obj, bt_isscanning);
1186
1187STATIC mp_obj_t bt_modem_sleep(mp_uint_t n_args, const mp_obj_t *args) {
1188
1189 bt_obj_t *self = args[0];
1190 /* Modem sleep APIs shall not be called before bt_controller_enable() */
1191 if(self->init)
1192 {
1193 if(n_args > 1)
1194 {
1195 if(ESP_OK != modem_sleep(mp_obj_is_true(args[1])))
1196 {
1197 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1198 }
1199 }
1200 else
1201 {
1202 /* return modem sleep status */
1203 return mp_obj_new_bool(esp_bt_controller_is_sleeping());
1204 }
1205 }
1206 else
1207 {
1208 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "BLE module not initialized"));
1209 }
1210
1211 return mp_const_none;
1212}
1213STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bt_modem_sleep_obj, 1, 2, bt_modem_sleep);
1214
1215STATIC mp_obj_t bt_stop_scan(mp_obj_t self_in) {
1216 if (bt_obj.scanning) {
1217 esp_ble_gap_stop_scanning();
1218 bt_obj.scanning = false;
1219 }
1220 return mp_const_none;
1221}
1222STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_stop_scan_obj, bt_stop_scan);
1223
1224STATIC mp_obj_t bt_read_scan(mp_obj_t self_in) {
1225 bt_event_result_t bt_event;
1226
1227 STATIC const qstr bt_scan_info_fields[] = {
1228 MP_QSTR_mac, MP_QSTR_addr_type, MP_QSTR_adv_type, MP_QSTR_rssi, MP_QSTR_data,
1229 };
1230
1231 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)0)) {
1232 mp_obj_t tuple[5];
1233 tuple[0] = mp_obj_new_bytes((const byte *)bt_event.scan.scan_rst.bda, 6);
1234 tuple[1] = mp_obj_new_int(bt_event.scan.scan_rst.ble_addr_type);
1235 tuple[2] = mp_obj_new_int(bt_event.scan.scan_rst.ble_evt_type & 0x03); // FIXME
1236 tuple[3] = mp_obj_new_int(bt_event.scan.scan_rst.rssi);
1237 tuple[4] = mp_obj_new_bytes((const byte *)bt_event.scan.scan_rst.ble_adv, sizeof(bt_event.scan.scan_rst.ble_adv));
1238
1239 return mp_obj_new_attrtuple(bt_scan_info_fields, 5, tuple);
1240 }
1241 return mp_const_none;
1242}
1243STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_read_scan_obj, bt_read_scan);
1244
1245STATIC mp_obj_t bt_get_advertisements(mp_obj_t self_in) {
1246
1247 esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication
1248 esp_ble_io_cap_t iocap = ESP_IO_CAP_KBDISP; //set the IO capability to No output No input
1249 uint8_t key_size = 16; //the key size should be 7~16 bytes
1250 uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
1251 uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
1252 uint8_t oob_support = ESP_BLE_OOB_DISABLE;
1253 esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
1254 esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
1255 esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
1256 esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
1257 /* If your BLE device act as a Slave, the init_key means you hope which types of key of the master should distribute to you,
1258 and the response key means which key you can distribute to the Master;
1259 If your BLE device act as a master, the response key means you hope which types of key of the slave should distribute to you,
1260 and the init key means which key you can distribute to the slave. */
1261 esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
1262 esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
1263
1264 bt_event_result_t bt_event;
1265
1266 STATIC const qstr bt_scan_info_fields[] = {
1267 MP_QSTR_mac, MP_QSTR_addr_type, MP_QSTR_adv_type, MP_QSTR_rssi, MP_QSTR_data,
1268 };
1269
1270 mp_obj_t advs = mp_obj_new_list(0, NULL);
1271 while (xQueueReceive(xScanQueue, &bt_event, (TickType_t)0)) {
1272 mp_obj_t tuple[5];
1273 tuple[0] = mp_obj_new_bytes((const byte *)bt_event.scan.scan_rst.bda, 6);
1274 tuple[1] = mp_obj_new_int(bt_event.scan.scan_rst.ble_addr_type);
1275 tuple[2] = mp_obj_new_int(bt_event.scan.scan_rst.ble_evt_type & 0x03); // FIXME
1276 tuple[3] = mp_obj_new_int(bt_event.scan.scan_rst.rssi);
1277 tuple[4] = mp_obj_new_bytes((const byte *)bt_event.scan.scan_rst.ble_adv, sizeof(bt_event.scan.scan_rst.ble_adv));
1278
1279 mp_obj_list_append(advs, mp_obj_new_attrtuple(bt_scan_info_fields, 5, tuple));
1280 }
1281 return advs;
1282}
1283STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_get_advertisements_obj, bt_get_advertisements);
1284
1285STATIC mp_obj_t bt_resolve_adv_data(mp_obj_t self_in, mp_obj_t adv_data, mp_obj_t data_type) {
1286 mp_buffer_info_t bufinfo;
1287 uint8_t data_len;
1288 uint8_t *data;
1289
1290 uint8_t type = mp_obj_get_int(data_type);
1291 mp_get_buffer_raise(adv_data, &bufinfo, MP_BUFFER_READ);
1292 data = esp_ble_resolve_adv_data(bufinfo.buf, type, &data_len);
1293
1294 if (data) {
1295 switch(type) {
1296 case ESP_BLE_AD_TYPE_FLAG:
1297 return mp_obj_new_int(*(int8_t *)data);
1298 case ESP_BLE_AD_TYPE_16SRV_PART:
1299 case ESP_BLE_AD_TYPE_16SRV_CMPL:
1300 case ESP_BLE_AD_TYPE_32SRV_PART:
1301 case ESP_BLE_AD_TYPE_32SRV_CMPL:
1302 case ESP_BLE_AD_TYPE_128SRV_PART:
1303 case ESP_BLE_AD_TYPE_128SRV_CMPL:
1304 return mp_obj_new_bytes(data, data_len);
1305 case ESP_BLE_AD_TYPE_NAME_SHORT:
1306 case ESP_BLE_AD_TYPE_NAME_CMPL:
1307 return mp_obj_new_str((char *)data, data_len);
1308 case ESP_BLE_AD_TYPE_TX_PWR:
1309 return mp_obj_new_int(*(int8_t *)data);
1310 case ESP_BLE_AD_TYPE_DEV_CLASS:
1311 break;
1312 case ESP_BLE_AD_TYPE_SERVICE_DATA:
1313 return mp_obj_new_bytes(data, data_len);
1314 case ESP_BLE_AD_TYPE_APPEARANCE:
1315 break;
1316 case ESP_BLE_AD_TYPE_ADV_INT:
1317 break;
1318 case ESP_BLE_AD_TYPE_32SERVICE_DATA:
1319 break;
1320 case ESP_BLE_AD_TYPE_128SERVICE_DATA:
1321 break;
1322 case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE:
1323 return mp_obj_new_bytes(data, data_len);
1324 default:
1325 break;
1326 }
1327 }
1328 return mp_const_none;
1329}
1330STATIC MP_DEFINE_CONST_FUN_OBJ_3(bt_resolve_adv_data_obj, bt_resolve_adv_data);
1331
1332/// \method callback(trigger, handler, arg)
1333STATIC mp_obj_t bt_callback(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1334 STATIC const mp_arg_t allowed_args[] = {
1335 { MP_QSTR_trigger, MP_ARG_REQUIRED | MP_ARG_OBJ, },
1336 { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
1337 { MP_QSTR_arg, MP_ARG_OBJ, {.u_obj = mp_const_none} },
1338 };
1339
1340 // parse arguments
1341 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1342 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1343 bt_obj_t *self = pos_args[0];
1344
1345 // enable the callback
1346 if (args[0].u_obj != mp_const_none && args[1].u_obj != mp_const_none) {
1347 self->trigger = mp_obj_get_int(args[0].u_obj);
1348 self->handler = args[1].u_obj;
1349 if (args[2].u_obj == mp_const_none) {
1350 self->handler_arg = self;
1351 } else {
1352 self->handler_arg = args[2].u_obj;
1353 }
1354 } else { // disable the callback
1355 self->trigger = 0;
1356 mp_irq_remove(self);
1357 INTERRUPT_OBJ_CLEAN(self);
1358 }
1359
1360 mp_irq_add(self, args[1].u_obj);
1361
1362 return mp_const_none;
1363}
1364STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_callback_obj, 1, bt_callback);
1365
1366STATIC mp_obj_t bt_events(mp_obj_t self_in) {
1367 bt_obj_t *self = self_in;
1368
1369 int32_t events = self->events;
1370 self->events = 0;
1371 return mp_obj_new_int(events);
1372}
1373STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_events_obj, bt_events);
1374
1375static mp_obj_t bt_connect_helper(mp_obj_t addr, TickType_t timeout){
1376
1377 bt_event_result_t bt_event;
1378 EventBits_t uxBits;
1379
1380 if (bt_obj.busy) {
1381 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "operation already in progress"));
1382 }
1383
1384 if (bt_obj.scanning) {
1385 esp_ble_gap_stop_scanning();
1386 mp_hal_delay_ms(50);
1387 bt_obj.scanning = false;
1388 }
1389
1390 mp_buffer_info_t bufinfo;
1391 mp_get_buffer_raise(addr, &bufinfo, MP_BUFFER_READ);
1392
1393 xQueueReset(xScanQueue);
1394 bt_obj.busy = true;
1395
1396 /* Initiate a background connection, esp_ble_gattc_open returns immediately */
1397 if (ESP_OK != esp_ble_gattc_open(bt_obj.gattc_if, bufinfo.buf, BLE_ADDR_TYPE_PUBLIC, true)) {
1398 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1399 }
1400 MP_THREAD_GIL_EXIT();
1401 if (xQueueReceive(xScanQueue, &bt_event, timeout) == pdTRUE)
1402 {
1403 if (bt_event.connection.conn_id < 0) {
1404 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection refusedxx"));
1405 }
1406
1407 // setup the object
1408 bt_connection_obj_t *conn = m_new_obj(bt_connection_obj_t);
1409 conn->base.type = (mp_obj_t)&mod_bt_connection_type;
1410 conn->conn_id = bt_event.connection.conn_id;
1411 conn->gatt_if = bt_event.connection.gatt_if;
1412 uxBits = xEventGroupWaitBits(bt_event_group, MOD_BT_GATTC_MTU_EVT, true, true, 1000/portTICK_PERIOD_MS);
1413 if(uxBits & MOD_BT_GATTC_MTU_EVT)
1414 {
1415 conn->mtu = bt_conn_mtu;
1416 }
1417 memcpy(conn->srv_bda, bt_event.connection.srv_bda, 6);
1418 mp_obj_list_append((void *)&MP_STATE_PORT(btc_conn_list), conn);
1419 return conn;
1420 }
1421 else
1422 {
1423 (void)esp_ble_gap_disconnect(bufinfo.buf);
1424 nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out"));
1425 }
1426 MP_THREAD_GIL_ENTER();
1427 return mp_const_none;
1428}
1429
1430
1431STATIC mp_obj_t bt_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1432
1433 STATIC const mp_arg_t allowed_args[] = {
1434 { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_OBJ, },
1435 { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
1436 };
1437
1438 // parse arguments
1439 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1440 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1441
1442 mp_obj_t addr = args[0].u_obj;
1443
1444 /* Timeout parameter is in miliseconds */
1445 TickType_t timeout;
1446 if(args[1].u_obj == MP_OBJ_NULL){
1447 timeout = portMAX_DELAY;
1448 }
1449 else
1450 {
1451 if(MP_OBJ_IS_SMALL_INT(args[1].u_obj) == true) {
1452 timeout = mp_obj_get_int(args[1].u_obj);
1453 }
1454 else
1455 {
1456 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "If timeout is specified it must be a valid integer number"));
1457 }
1458 }
1459
1460 return bt_connect_helper(addr, timeout);
1461}
1462STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_connect_obj, 1, bt_connect);
1463
1464static mp_obj_t modbt_connect(mp_obj_t addr)
1465{
1466 return bt_connect_helper(addr, portMAX_DELAY);
1467}
1468
1469
1470STATIC mp_obj_t bt_set_advertisement_params (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1471 static const mp_arg_t allowed_args[] = {
1472 { MP_QSTR_adv_int_min, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x20} },
1473 { MP_QSTR_adv_int_max, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x40} },
1474 { MP_QSTR_adv_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ADV_TYPE_IND} },
1475 { MP_QSTR_own_addr_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BLE_ADDR_TYPE_PUBLIC} },
1476 { MP_QSTR_channel_map, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ADV_CHNL_ALL} },
1477 { MP_QSTR_adv_filter_policy, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY} },
1478 };
1479
1480 // parse args
1481 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1482 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1483
1484 // adv_int_min
1485 bt_adv_params.adv_int_min = (uint16_t)args[0].u_int;
1486
1487 // adv_int_max
1488 bt_adv_params.adv_int_max = (uint16_t)args[1].u_int;
1489
1490 // adv_type
1491 bt_adv_params.adv_type = (esp_ble_adv_type_t)args[2].u_int;
1492
1493 // own_addr_type
1494 bt_adv_params.own_addr_type = (esp_ble_addr_type_t)args[3].u_int;
1495
1496 // channel_map
1497 bt_adv_params.channel_map = (esp_ble_adv_channel_t)args[4].u_int;
1498
1499 // adv_filter_policy
1500 bt_adv_params.adv_filter_policy = (esp_ble_adv_filter_t)args[5].u_int;
1501
1502 return mp_const_none;
1503}
1504STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_set_advertisement_params_obj, 1, bt_set_advertisement_params);
1505
1506
1507STATIC mp_obj_t bt_set_advertisement (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1508 static const mp_arg_t allowed_args[] = {
1509 { MP_QSTR_name, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1510 { MP_QSTR_manufacturer_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1511 { MP_QSTR_service_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1512 { MP_QSTR_service_uuid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1513 };
1514
1515 mp_buffer_info_t manuf_bufinfo;
1516 mp_buffer_info_t srv_bufinfo;
1517 mp_buffer_info_t uuid_bufinfo;
1518
1519 // parse args
1520 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1521 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1522
1523 // device name
1524 if (args[0].u_obj != mp_const_none) {
1525 const char *name = mp_obj_str_get_str(args[0].u_obj);
1526 adv_data.include_name = true;
1527 esp_ble_gap_set_device_name(name);
1528 } else {
1529 adv_data.include_name = false;
1530 esp_ble_gap_set_device_name(" ");
1531 }
1532
1533 // manufacturer data
1534 if (args[1].u_obj != mp_const_none) {
1535 mp_get_buffer_raise(args[1].u_obj, &manuf_bufinfo, MP_BUFFER_READ);
1536 adv_data.manufacturer_len = manuf_bufinfo.len;
1537 adv_data.p_manufacturer_data = manuf_bufinfo.buf;
1538 } else {
1539 adv_data.manufacturer_len = 0;
1540 adv_data.p_manufacturer_data = NULL;
1541 }
1542
1543 // service data
1544 if (args[2].u_obj != mp_const_none) {
1545 mp_get_buffer_raise(args[2].u_obj, &srv_bufinfo, MP_BUFFER_READ);
1546 adv_data.service_data_len = srv_bufinfo.len;
1547 adv_data.p_service_data = srv_bufinfo.buf;
1548 } else {
1549 adv_data.service_data_len = 0;
1550 adv_data.p_service_data = NULL;
1551 }
1552
1553 // service uuid
1554 if (args[3].u_obj != mp_const_none) {
1555 if (mp_obj_is_integer(args[3].u_obj)) {
1556 uint32_t srv_uuid = mp_obj_get_int_truncated(args[3].u_obj);
1557 uint8_t uuid_buf[16] = {0};
1558 memcpy(uuid_buf, (uint8_t *)&srv_uuid, sizeof(uuid_buf));
1559 adv_data.service_uuid_len = 16;
1560 adv_data.p_service_uuid = (uint8_t *)&srv_uuid;
1561 } else {
1562 mp_get_buffer_raise(args[3].u_obj, &uuid_bufinfo, MP_BUFFER_READ);
1563 adv_data.service_uuid_len = uuid_bufinfo.len;
1564 adv_data.p_service_uuid = uuid_bufinfo.buf;
1565 if (adv_data.service_uuid_len % 16) {
1566 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "incorrect service UUID length"));
1567 }
1568 }
1569 } else {
1570 adv_data.service_uuid_len = 0;
1571 adv_data.p_service_uuid = NULL;
1572 }
1573
1574 adv_data.set_scan_rsp = false;
1575 adv_data.include_txpower = true,
1576 adv_data.min_interval = 0x20;
1577 adv_data.max_interval = 0x40;
1578 adv_data.appearance = 0x00;
1579 adv_data.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT);
1580
1581 // copy all the info to the scan response
1582 memcpy(&scan_rsp_data, &adv_data, sizeof(esp_ble_adv_data_t));
1583 scan_rsp_data.set_scan_rsp = true;
1584 // do not include the name or the tx power in the scan response
1585 scan_rsp_data.include_name = false;
1586 scan_rsp_data.include_txpower = false;
1587 // do not include the service uuid or service data in the advertisement, only in the scan response
1588 adv_data.manufacturer_len = 0;
1589 adv_data.p_manufacturer_data = NULL;
1590 adv_data.service_data_len = 0;
1591 adv_data.p_service_data = NULL;
1592 adv_data.service_uuid_len = 0;
1593 adv_data.p_service_uuid = NULL;
1594 esp_ble_gap_config_adv_data(&adv_data);
1595 esp_ble_gap_config_adv_data(&scan_rsp_data);
1596
1597 // wait for the advertisement data to be configured
1598 bt_gatts_event_result_t gatts_event;
1599 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1600
1601 return mp_const_none;
1602}
1603STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_set_advertisement_obj, 1, bt_set_advertisement);
1604
1605
1606STATIC mp_obj_t bt_set_advertisement_raw(mp_obj_t self_in, mp_obj_t raw_data) {
1607 mp_buffer_info_t bufinfo;
1608 uint32_t data_len;
1609 uint8_t data[30] = {0};
1610
1611 if (raw_data != mp_const_none) {
1612 mp_get_buffer_raise(raw_data, &bufinfo, MP_BUFFER_READ);
1613 if (bufinfo.len < 31) {
1614 memcpy(data, (uint8_t *)bufinfo.buf, bufinfo.len);
1615 data_len = bufinfo.len;
1616 } else {
1617 memcpy(data, (uint8_t *)bufinfo.buf, sizeof(data));
1618 data_len = sizeof(data);
1619 }
1620
1621 esp_ble_gap_config_adv_data_raw(data, data_len);
1622
1623 // wait for the advertisement data to be configured
1624 bt_gatts_event_result_t gatts_event;
1625 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1626 }
1627
1628 return mp_const_none;
1629}
1630STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_set_advertisement_raw_obj, bt_set_advertisement_raw);
1631
1632
1633STATIC mp_obj_t bt_advertise(mp_obj_t self_in, mp_obj_t enable) {
1634 if (mp_obj_is_true(enable)) {
1635 // some sensible time to wait for the advertisement configuration to complete
1636 mp_hal_delay_ms(50);
1637 if (!bt_obj.secure){
1638 esp_ble_gap_start_advertising(&bt_adv_params);
1639 } else {
1640 esp_ble_gap_start_advertising(&bt_adv_params_sec);
1641 }
1642 bt_obj.advertising = true;
1643 } else {
1644 esp_ble_gap_stop_advertising();
1645 bt_obj.advertising = false;
1646 }
1647 return mp_const_none;
1648}
1649STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_advertise_obj, bt_advertise);
1650
1651STATIC mp_obj_t bt_service (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1652 static const mp_arg_t allowed_args[] = {
1653 { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ },
1654 { MP_QSTR_isprimary, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
1655 { MP_QSTR_nbr_chars, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
1656 { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
1657 };
1658
1659 mp_buffer_info_t uuid_bufinfo;
1660 esp_gatt_srvc_id_t service_id;
1661
1662 // parse args
1663 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1664 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1665
1666 // service uuid
1667 if (mp_obj_is_integer(args[0].u_obj)) {
1668 uint32_t srv_uuid = mp_obj_get_int_truncated(args[0].u_obj);
1669 if (srv_uuid > UINT16_MAX) {
1670 service_id.id.uuid.len = 4;
1671 service_id.id.uuid.uuid.uuid32 = srv_uuid;
1672 } else {
1673 service_id.id.uuid.len = 2;
1674 service_id.id.uuid.uuid.uuid16 = srv_uuid;
1675 }
1676 } else {
1677 mp_get_buffer_raise(args[0].u_obj, &uuid_bufinfo, MP_BUFFER_READ);
1678 if (uuid_bufinfo.len != 16) {
1679 goto error;
1680 }
1681 service_id.id.uuid.len = uuid_bufinfo.len;
1682 memcpy(service_id.id.uuid.uuid.uuid128, uuid_bufinfo.buf, sizeof(service_id.id.uuid.uuid.uuid128));
1683 }
1684
1685 service_id.is_primary = args[1].u_bool;
1686 service_id.id.inst_id = 0x00;
1687
1688 esp_ble_gatts_create_service(bt_obj.gatts_if, &service_id, (args[2].u_int * 3) + 1);
1689
1690 bt_gatts_event_result_t gatts_event;
1691 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1692
1693 bt_gatts_srv_obj_t *srv = m_new_obj(bt_gatts_srv_obj_t);
1694 srv->base.type = (mp_obj_t)&mod_bt_gatts_service_type;
1695 srv->handle = gatts_event.service_handle;
1696
1697 if (args[3].u_bool) {
1698 esp_ble_gatts_start_service(gatts_event.service_handle);
1699 srv->started = true;
1700 }
1701
1702 mp_obj_list_append((mp_obj_t)&MP_STATE_PORT(bts_srv_list), srv);
1703
1704 return srv;
1705
1706error:
1707 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
1708}
1709STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_service_obj, 1, bt_service);
1710
1711STATIC mp_obj_t bt_service_start(mp_obj_t self_in) {
1712 bt_gatts_srv_obj_t *self = self_in;
1713 if (!self->started) {
1714 if (ESP_OK != esp_ble_gatts_start_service(self->handle)) {
1715 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1716 }
1717 self->started = true;
1718 }
1719 return mp_const_none;
1720}
1721STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_service_start_obj, bt_service_start);
1722
1723STATIC mp_obj_t bt_service_stop(mp_obj_t self_in) {
1724 bt_gatts_srv_obj_t *self = self_in;
1725 if (self->started) {
1726 if (ESP_OK != esp_ble_gatts_stop_service(self->handle)) {
1727 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1728 }
1729 self->started = false;
1730 }
1731 return mp_const_none;
1732}
1733STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_service_stop_obj, bt_service_stop);
1734
1735STATIC mp_obj_t bt_characteristic (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1736 static const mp_arg_t allowed_args[] = {
1737 { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ },
1738 { MP_QSTR_permissions, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1739 { MP_QSTR_properties, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1740 { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1741 };
1742
1743 bt_gatts_srv_obj_t *self = pos_args[0];
1744
1745 // parse args
1746 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1747 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1748
1749 mp_buffer_info_t uuid_bufinfo;
1750 esp_bt_uuid_t char_uuid;
1751
1752 // characteristic uuid
1753 if (mp_obj_is_integer(args[0].u_obj)) {
1754 uint32_t srv_uuid = mp_obj_get_int_truncated(args[0].u_obj);
1755 if (srv_uuid > UINT16_MAX) {
1756 char_uuid.len = 4;
1757 char_uuid.uuid.uuid32 = srv_uuid;
1758 } else {
1759 char_uuid.len = 2;
1760 char_uuid.uuid.uuid16 = srv_uuid;
1761 }
1762 } else {
1763 mp_get_buffer_raise(args[0].u_obj, &uuid_bufinfo, MP_BUFFER_READ);
1764 if (uuid_bufinfo.len != 16) {
1765 goto error;
1766 }
1767 char_uuid.len = uuid_bufinfo.len;
1768 memcpy(char_uuid.uuid.uuid128, uuid_bufinfo.buf, sizeof(char_uuid.uuid.uuid128));
1769 }
1770
1771 uint32_t permissions = 0;
1772 if (args[1].u_obj != mp_const_none) {
1773 permissions = mp_obj_get_int(args[1].u_obj);
1774 } else {
1775 if (!bt_obj.secure){
1776 permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
1777 } else {
1778 permissions = ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED;
1779 }
1780 }
1781
1782 uint32_t properties = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
1783 if (args[2].u_obj != mp_const_none) {
1784 properties = mp_obj_get_int(args[2].u_obj);
1785 }
1786
1787 bt_gatts_char_obj_t *characteristic = m_new_obj(bt_gatts_char_obj_t);
1788 characteristic->attr_obj.base.type = (mp_obj_t)&mod_bt_gatts_char_type;
1789 characteristic->attr_obj.parent = self;
1790 characteristic->attr_obj.is_char = true;
1791 characteristic->attr_obj.properties = properties;
1792 characteristic->trigger = 0;
1793 characteristic->events = 0;
1794
1795 if (args[3].u_obj != mp_const_none) {
1796 // characteristic value
1797 if (mp_obj_is_integer(args[3].u_obj)) {
1798 uint32_t value = mp_obj_get_int_truncated(args[3].u_obj);
1799 if (value > UINT16_MAX) {
1800 characteristic->attr_obj.value_len = 4;
1801 value = lwip_htonl(value);
1802 } else if (value > UINT8_MAX) {
1803 characteristic->attr_obj.value_len = 2;
1804 value = lwip_htons(value);
1805 } else {
1806 characteristic->attr_obj.value_len = 1;
1807 }
1808 memcpy(characteristic->attr_obj.value, &value, sizeof(value));
1809 } else {
1810 mp_buffer_info_t value_bufinfo;
1811 mp_get_buffer_raise(args[3].u_obj, &value_bufinfo, MP_BUFFER_READ);
1812 uint16_t write_len = value_bufinfo.len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : value_bufinfo.len;
1813 memcpy(characteristic->attr_obj.value, value_bufinfo.buf, write_len);
1814 characteristic->attr_obj.value_len = write_len;
1815 }
1816 } else {
1817 characteristic->attr_obj.value[0] = 0;
1818 characteristic->attr_obj.value_len = 1;
1819 }
1820
1821 esp_ble_gatts_add_char(self->handle, &char_uuid, permissions, properties, NULL, NULL);
1822
1823 bt_gatts_event_result_t gatts_event;
1824 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1825
1826 characteristic->attr_obj.handle = gatts_event.char_handle;
1827 memcpy(&characteristic->attr_obj.uuid, &char_uuid, sizeof(char_uuid));
1828
1829 mp_obj_list_append((mp_obj_t)&MP_STATE_PORT(bts_attr_list), characteristic);
1830
1831 bt_gatts_attr_obj_t *descriptor = m_new_obj(bt_gatts_attr_obj_t);
1832 descriptor->uuid.len = ESP_UUID_LEN_16;
1833 descriptor->uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
1834
1835 esp_ble_gatts_add_char_descr(self->handle, &descriptor->uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
1836
1837 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1838
1839 descriptor->base.type = (mp_obj_t)&mod_bt_gatts_char_type;
1840 descriptor->handle = gatts_event.char_descr_handle;
1841 descriptor->parent = characteristic;
1842 descriptor->is_char = false;
1843 descriptor->value_len = 2;
1844 descriptor->value[0] = 0;
1845 descriptor->value[1] = 0;
1846
1847 mp_obj_list_append((mp_obj_t)&MP_STATE_PORT(bts_attr_list), descriptor);
1848
1849 return characteristic;
1850
1851error:
1852 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
1853}
1854STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_characteristic_obj, 1, bt_characteristic);
1855
1856
1857STATIC const mp_map_elem_t bt_gatts_service_locals_dict_table[] = {
1858 // instance methods
1859 { MP_OBJ_NEW_QSTR(MP_QSTR_characteristic), (mp_obj_t)&bt_characteristic_obj },
1860 { MP_OBJ_NEW_QSTR(MP_QSTR_start), (mp_obj_t)&bt_service_start_obj },
1861 { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&bt_service_stop_obj },
1862};
1863STATIC MP_DEFINE_CONST_DICT(bt_gatts_service_locals_dict, bt_gatts_service_locals_dict_table);
1864
1865static const mp_obj_type_t mod_bt_gatts_service_type = {
1866 { &mp_type_type },
1867 .name = MP_QSTR_GATTSService,
1868 .locals_dict = (mp_obj_t)&bt_gatts_service_locals_dict,
1869};
1870
1871STATIC mp_obj_t bt_characteristic_value (mp_uint_t n_args, const mp_obj_t *args) {
1872 bt_gatts_char_obj_t *self = args[0];
1873 if (n_args == 1) {
1874 // get
1875 return mp_obj_new_bytes(self->attr_obj.value, self->attr_obj.value_len);
1876 } else {
1877 // set
1878 if (mp_obj_is_integer(args[1])) {
1879 uint32_t value = mp_obj_get_int_truncated(args[1]);
1880 memcpy(self->attr_obj.value, &value, sizeof(value));
1881 if (value > 0xFF) {
1882 self->attr_obj.value_len = 2;
1883 } else if (value > 0xFFFF) {
1884 self->attr_obj.value_len = 4;
1885 } else {
1886 self->attr_obj.value_len = 1;
1887 }
1888 } else {
1889 mp_buffer_info_t value_bufinfo;
1890 mp_get_buffer_raise(args[1], &value_bufinfo, MP_BUFFER_READ);
1891 uint8_t value_len = value_bufinfo.len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : value_bufinfo.len;
1892 memcpy(self->attr_obj.value, value_bufinfo.buf, value_len);
1893 self->attr_obj.value_len = value_len;
1894 }
1895
1896 bool confirm = self->attr_obj.properties & ESP_GATT_CHAR_PROP_BIT_INDICATE;
1897 if (ESP_OK != esp_ble_gatts_send_indicate(bt_obj.gatts_if, bt_obj.gatts_conn_id, self->attr_obj.handle,
1898 self->attr_obj.value_len, self->attr_obj.value, confirm)) {
1899 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Erorr while sending BLE indication/notification"));
1900 }
1901 return mp_const_none;
1902 }
1903}
1904STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bt_characteristic_value_obj, 1, 2, bt_characteristic_value);
1905
1906/// \method callback(trigger, handler, arg)
1907STATIC mp_obj_t bt_characteristic_callback(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1908 STATIC const mp_arg_t allowed_args[] = {
1909 { MP_QSTR_trigger, MP_ARG_REQUIRED | MP_ARG_OBJ, },
1910 { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
1911 { MP_QSTR_arg, MP_ARG_OBJ, {.u_obj = mp_const_none} },
1912 };
1913
1914 // parse arguments
1915 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1916 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1917 bt_gatts_char_obj_t *self = pos_args[0];
1918
1919 // enable the callback
1920 if (args[0].u_obj != mp_const_none && args[1].u_obj != mp_const_none) {
1921 self->trigger = mp_obj_get_int(args[0].u_obj);
1922 self->handler = args[1].u_obj;
1923 if (args[2].u_obj == mp_const_none) {
1924 self->handler_arg = self;
1925 } else {
1926 self->handler_arg = args[2].u_obj;
1927 }
1928 } else {
1929 self->trigger = 0;
1930 mp_irq_remove(self);
1931 INTERRUPT_OBJ_CLEAN(self);
1932 }
1933
1934 mp_irq_add(self, args[1].u_obj);
1935
1936 return mp_const_none;
1937}
1938STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_characteristic_callback_obj, 1, bt_characteristic_callback);
1939
1940STATIC mp_obj_t bt_characteristic_events(mp_obj_t self_in) {
1941 bt_gatts_char_obj_t *self = self_in;
1942
1943 int32_t events = self->events;
1944 self->events = 0;
1945 return mp_obj_new_int(events);
1946}
1947STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_characteristic_events_obj, bt_characteristic_events);
1948
1949STATIC mp_obj_t bt_characteristic_config(mp_obj_t self_in) {
1950 bt_gatts_char_obj_t *self = self_in;
1951 return mp_obj_new_int(self->config);
1952}
1953STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_characteristic_config_obj, bt_characteristic_config);
1954
1955STATIC const mp_map_elem_t bt_gatts_char_locals_dict_table[] = {
1956 // instance methods
1957 { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&bt_characteristic_value_obj },
1958 { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&bt_characteristic_callback_obj },
1959 { MP_OBJ_NEW_QSTR(MP_QSTR_events), (mp_obj_t)&bt_characteristic_events_obj },
1960 { MP_OBJ_NEW_QSTR(MP_QSTR_config), (mp_obj_t)&bt_characteristic_config_obj },
1961};
1962STATIC MP_DEFINE_CONST_DICT(bt_gatts_char_locals_dict, bt_gatts_char_locals_dict_table);
1963
1964static const mp_obj_type_t mod_bt_gatts_char_type = {
1965 { &mp_type_type },
1966 .name = MP_QSTR_GATTSCharacteristic,
1967 .locals_dict = (mp_obj_t)&bt_gatts_char_locals_dict,
1968};
1969
1970STATIC mp_obj_t bt_gatts_disconnect_client(mp_obj_t self_in) {
1971 if (bt_obj.gatts_conn_id >= 0) {
1972 esp_ble_gatts_close(bt_obj.gatts_if, bt_obj.gatts_conn_id);
1973 esp_ble_gap_disconnect((void *)bt_obj.client_bda);
1974 bt_obj.gatts_conn_id = -1;
1975 }
1976 return mp_const_none;
1977}
1978STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_gatts_disconnect_client_obj, bt_gatts_disconnect_client);
1979
1980STATIC mp_obj_t bt_tx_power(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1981
1982 STATIC const mp_arg_t allowed_args[] = {
1983 { MP_QSTR_type, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = mp_const_none} },
1984 { MP_QSTR_level, MP_ARG_INT, {.u_obj = mp_const_none} }
1985 };
1986
1987 // parse arguments
1988 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1989 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1990
1991 mp_int_t type = args[0].u_int;
1992
1993 // Do not accept "Connection Handlers 1-8", we do not support different connections in parallel
1994 if(type == ESP_BLE_PWR_TYPE_CONN_HDL0 ||
1995 (type > ESP_BLE_PWR_TYPE_CONN_HDL8 && type < ESP_BLE_PWR_TYPE_NUM)) {
1996
1997 // If "level" is not specified, return with the TX Power marked in "type" parameter
1998 if(args[1].u_obj == mp_const_none)
1999 {
2000 esp_power_level_t ret = esp_ble_tx_power_get(type);
2001 if(ret < 0) {
2002 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "TX Power level could not be get, error code: %d", ret));
2003 // Just for the compiler
2004 return mp_const_none;
2005 }
2006 else {
2007 return mp_obj_new_int(tx_pwr_level_to_dbm[ret]);
2008 }
2009 }
2010 else {
2011
2012 mp_int_t level = args[1].u_int;
2013
2014 if(level >= (sizeof(tx_pwr_level_to_dbm)/sizeof(tx_pwr_level_to_dbm[0]))) {
2015 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid value as \"level\", must be between 0-7: %d", type));
2016 }
2017
2018 esp_power_level_t ret = esp_ble_tx_power_set(type, level);
2019
2020 if(ret != ESP_OK) {
2021 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "TX Power level could not be set, error code: %d", ret));
2022 // Just for the compiler
2023 return mp_const_none;
2024 }
2025 else {
2026 return mp_const_none;
2027 }
2028 }
2029 }
2030 else {
2031 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid value as \"type\": %d", type));
2032 // Just for the compiler
2033 return mp_const_none;
2034 }
2035}
2036STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_tx_power_obj, 2, bt_tx_power);
2037
2038STATIC mp_obj_t bt_conn_get_mtu(mp_obj_t self_in) {
2039
2040 bt_connection_obj_t * self = (bt_connection_obj_t *)self_in;
2041
2042 if(self->conn_id >= 0)
2043 {
2044 return mp_obj_new_int(self->mtu);
2045 }
2046 return mp_const_none;
2047}
2048STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_conn_get_mtu_obj, bt_conn_get_mtu);
2049
2050STATIC mp_obj_t bt_gatts_get_mtu(mp_obj_t self_in) {
2051
2052 bt_obj_t * self = (bt_obj_t *)self_in;
2053 EventBits_t uxBits;
2054
2055 if(self->gatts_conn_id >= 0)
2056 {
2057 MP_THREAD_GIL_EXIT();
2058 uxBits = xEventGroupWaitBits(bt_event_group, MOD_BT_GATTS_MTU_EVT, true, true, 1000/portTICK_PERIOD_MS);
2059 MP_THREAD_GIL_ENTER();
2060 if(uxBits & MOD_BT_GATTS_MTU_EVT)
2061 {
2062 return mp_obj_new_int(self->gatts_mtu);
2063 }
2064 }
2065 return mp_const_none;
2066}
2067STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_gatts_get_mtu_obj, bt_gatts_get_mtu);
2068
2069STATIC const mp_map_elem_t bt_locals_dict_table[] = {
2070 // instance methods
2071 { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&bt_init_obj },
2072 { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&bt_deinit_obj },
2073 { MP_OBJ_NEW_QSTR(MP_QSTR_start_scan), (mp_obj_t)&bt_start_scan_obj },
2074 { MP_OBJ_NEW_QSTR(MP_QSTR_isscanning), (mp_obj_t)&bt_isscanning_obj },
2075 { MP_OBJ_NEW_QSTR(MP_QSTR_stop_scan), (mp_obj_t)&bt_stop_scan_obj },
2076 { MP_OBJ_NEW_QSTR(MP_QSTR_get_adv), (mp_obj_t)&bt_read_scan_obj },
2077 { MP_OBJ_NEW_QSTR(MP_QSTR_get_advertisements), (mp_obj_t)&bt_get_advertisements_obj },
2078 { MP_OBJ_NEW_QSTR(MP_QSTR_resolve_adv_data), (mp_obj_t)&bt_resolve_adv_data_obj },
2079 { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&bt_connect_obj },
2080 { MP_OBJ_NEW_QSTR(MP_QSTR_set_advertisement_params),(mp_obj_t)&bt_set_advertisement_params_obj },
2081 { MP_OBJ_NEW_QSTR(MP_QSTR_set_advertisement), (mp_obj_t)&bt_set_advertisement_obj },
2082 { MP_OBJ_NEW_QSTR(MP_QSTR_set_advertisement_raw), (mp_obj_t)&bt_set_advertisement_raw_obj },
2083 { MP_OBJ_NEW_QSTR(MP_QSTR_advertise), (mp_obj_t)&bt_advertise_obj },
2084 { MP_OBJ_NEW_QSTR(MP_QSTR_service), (mp_obj_t)&bt_service_obj },
2085 { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&bt_callback_obj },
2086 { MP_OBJ_NEW_QSTR(MP_QSTR_events), (mp_obj_t)&bt_events_obj },
2087 { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect_client), (mp_obj_t)&bt_gatts_disconnect_client_obj },
2088 { MP_OBJ_NEW_QSTR(MP_QSTR_modem_sleep), (mp_obj_t)&bt_modem_sleep_obj },
2089 { MP_OBJ_NEW_QSTR(MP_QSTR_tx_power), (mp_obj_t)&bt_tx_power_obj },
2090 { MP_OBJ_NEW_QSTR(MP_QSTR_gatts_mtu), (mp_obj_t)&bt_gatts_get_mtu_obj },
2091 { MP_OBJ_NEW_QSTR(MP_QSTR_nvram_erase), (mp_obj_t)&bt_nvram_erase_obj },
2092
2093
2094 // exceptions
2095 { MP_OBJ_NEW_QSTR(MP_QSTR_timeout), (mp_obj_t)&mp_type_TimeoutError },
2096
2097 // constants
2098 { MP_OBJ_NEW_QSTR(MP_QSTR_CONN_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_CONN_ADV) },
2099 { MP_OBJ_NEW_QSTR(MP_QSTR_CONN_DIR_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_CONN_DIR_ADV) },
2100 { MP_OBJ_NEW_QSTR(MP_QSTR_DISC_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_DISC_ADV) },
2101 { MP_OBJ_NEW_QSTR(MP_QSTR_NON_CONN_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_NON_CONN_ADV) },
2102 { MP_OBJ_NEW_QSTR(MP_QSTR_SCAN_RSP), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_SCAN_RSP) },
2103
2104 { MP_OBJ_NEW_QSTR(MP_QSTR_PUBLIC_ADDR), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_PUBLIC) },
2105 { MP_OBJ_NEW_QSTR(MP_QSTR_RANDOM_ADDR), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RANDOM) },
2106 { MP_OBJ_NEW_QSTR(MP_QSTR_PUBLIC_RPA_ADDR), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RPA_PUBLIC) },
2107 { MP_OBJ_NEW_QSTR(MP_QSTR_RANDOM_RPA_ADDR), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RPA_RANDOM) },
2108
2109 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_FLAG), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_FLAG) },
2110 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_16SRV_PART), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_16SRV_PART) },
2111 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_T16SRV_CMPL), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_16SRV_CMPL) },
2112 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_32SRV_PART), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_32SRV_PART) },
2113 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_32SRV_CMPL), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_32SRV_CMPL) },
2114 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_128SRV_PART), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_128SRV_PART) },
2115 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_128SRV_CMPL), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_128SRV_CMPL) },
2116 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_NAME_SHORT), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_NAME_SHORT) },
2117 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_NAME_CMPL), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_NAME_CMPL) },
2118 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TX_PWR), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_TX_PWR) },
2119 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_DEV_CLASS), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_DEV_CLASS) },
2120 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_SERVICE_DATA), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_SERVICE_DATA) },
2121 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_APPEARANCE), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_APPEARANCE) },
2122 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_ADV_INT), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_ADV_INT) },
2123 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_32SERVICE_DATA), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_32SERVICE_DATA) },
2124 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_128SERVICE_DATA), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_128SERVICE_DATA) },
2125 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_MANUFACTURER_DATA), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE) },
2126
2127 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_BROADCAST), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_BROADCAST) },
2128 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_READ), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_READ) },
2129 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_WRITE_NR), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_WRITE_NR) },
2130 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_WRITE), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_WRITE) },
2131 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_NOTIFY), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_NOTIFY) },
2132 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_INDICATE), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_INDICATE) },
2133 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_AUTH), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_AUTH) },
2134 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_EXT_PROP), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_EXT_PROP) },
2135
2136 // Defined at https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
2137 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_CONFIG_NOTIFY), MP_OBJ_NEW_SMALL_INT(1 << 0) },
2138 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_CONFIG_INDICATE), MP_OBJ_NEW_SMALL_INT(1 << 1) },
2139
2140 { MP_OBJ_NEW_QSTR(MP_QSTR_NEW_ADV_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTC_ADV_EVT) },
2141 { MP_OBJ_NEW_QSTR(MP_QSTR_CLIENT_CONNECTED), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_CONN_EVT) },
2142 { MP_OBJ_NEW_QSTR(MP_QSTR_CLIENT_DISCONNECTED), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_DISCONN_EVT) },
2143 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_READ_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_READ_EVT) },
2144 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_WRITE_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_WRITE_EVT) },
2145 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_NOTIFY_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTC_NOTIFY_EVT) },
2146 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_SUBSCRIBE_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_SUBSCRIBE_EVT) },
2147 // { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_INDICATE_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTC_INDICATE_EVT) },
2148
2149 { MP_OBJ_NEW_QSTR(MP_QSTR_INT_ANT), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_INTERNAL) },
2150 { MP_OBJ_NEW_QSTR(MP_QSTR_EXT_ANT), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_EXTERNAL) },
2151
2152 // Constants for bt_set_advertisement_params API
2153 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_IND), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_IND) },
2154 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_DIRECT_IND_HIGH), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_DIRECT_IND_HIGH) },
2155 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_SCAN_IND), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_SCAN_IND) },
2156 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_NONCONN_IND), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_NONCONN_IND) },
2157 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_DIRECT_IND_LOW), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_DIRECT_IND_LOW) },
2158 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_BLE_ADDR_TYPE_PUBLIC), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_PUBLIC) },
2159 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_BLE_ADDR_TYPE_RANDOM), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RANDOM) },
2160 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_BLE_ADDR_TYPE_RPA_PUBLIC), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RPA_PUBLIC) },
2161 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_BLE_ADDR_TYPE_RPA_RANDOM), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RPA_RANDOM) },
2162 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_CHNL_37), MP_OBJ_NEW_SMALL_INT(ADV_CHNL_37) },
2163 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_CHNL_38), MP_OBJ_NEW_SMALL_INT(ADV_CHNL_38) },
2164 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_CHNL_39), MP_OBJ_NEW_SMALL_INT(ADV_CHNL_39) },
2165 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_CHNL_ALL), MP_OBJ_NEW_SMALL_INT(ADV_CHNL_ALL) },
2166 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY), MP_OBJ_NEW_SMALL_INT(ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY) },
2167 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY), MP_OBJ_NEW_SMALL_INT(ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY) },
2168 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST), MP_OBJ_NEW_SMALL_INT(ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST) },
2169 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST), MP_OBJ_NEW_SMALL_INT(ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST) },
2170
2171 // Constants for setting TX Power
2172 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_CONN), MP_OBJ_NEW_SMALL_INT(ESP_BLE_PWR_TYPE_CONN_HDL0) },
2173 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_PWR_TYPE_ADV) },
2174 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_SCAN), MP_OBJ_NEW_SMALL_INT(ESP_BLE_PWR_TYPE_SCAN) },
2175 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_DEFAULT), MP_OBJ_NEW_SMALL_INT(ESP_BLE_PWR_TYPE_DEFAULT) },
2176 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_N12), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N12) },
2177 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_N9), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N9) },
2178 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_N6), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N6) },
2179 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_N3), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N3) },
2180 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_0), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N0) },
2181 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_P3), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_P3) },
2182 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_P6), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_P6) },
2183 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_P9), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_P9) },
2184
2185};
2186STATIC MP_DEFINE_CONST_DICT(bt_locals_dict, bt_locals_dict_table);
2187
2188const mod_network_nic_type_t mod_network_nic_type_bt = {
2189 .base = {
2190 { &mp_type_type },
2191 .name = MP_QSTR_Bluetooth,
2192 .make_new = bt_make_new,
2193 .locals_dict = (mp_obj_t)&bt_locals_dict,
2194 },
2195};
2196
2197STATIC mp_obj_t bt_conn_isconnected(mp_obj_t self_in) {
2198 bt_connection_obj_t *self = self_in;
2199
2200 if (self->conn_id >= 0) {
2201 return mp_const_true;
2202 }
2203 return mp_const_false;
2204}
2205STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_conn_isconnected_obj, bt_conn_isconnected);
2206
2207STATIC mp_obj_t bt_conn_disconnect(mp_obj_t self_in) {
2208 bt_connection_obj_t *self = self_in;
2209
2210 if (self->conn_id >= 0) {
2211 esp_ble_gattc_close(bt_obj.gattc_if, self->conn_id);
2212 esp_ble_gap_disconnect(self->srv_bda);
2213 /* Only reset Conn Id if it is a normal disconnect not module de-init to mark conn obj to be restored */
2214 if(!mod_bt_allow_resume_deinit)
2215 {
2216 self->conn_id = -1;
2217 }
2218 }
2219 return mp_const_none;
2220}
2221STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_conn_disconnect_obj, bt_conn_disconnect);
2222
2223static mp_obj_t modbt_conn_disconnect(mp_obj_t self_in)
2224{
2225 return bt_conn_disconnect(self_in);
2226}
2227
2228STATIC mp_obj_t bt_conn_services (mp_obj_t self_in) {
2229 bt_connection_obj_t *self = self_in;
2230 bt_event_result_t bt_event;
2231
2232 if (self->conn_id >= 0) {
2233 xQueueReset(xScanQueue);
2234 bt_obj.busy = true;
2235 mp_obj_list_init(&self->srv_list, 0);
2236
2237 if (ESP_OK != esp_ble_gattc_search_service(bt_obj.gattc_if, self->conn_id, NULL)) {
2238 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2239 }
2240
2241 while (bt_obj.busy) {
2242 while (xQueueReceive(xScanQueue, &bt_event, (TickType_t)0)) {
2243 bt_srv_obj_t *srv = m_new_obj(bt_srv_obj_t);
2244 srv->base.type = (mp_obj_t)&mod_bt_service_type;
2245 srv->connection = self;
2246 memcpy(&srv->srv_id, &bt_event.service.srv_id, sizeof(esp_gatt_id_t));
2247 srv->start_handle = bt_event.service.start_handle;
2248 srv->end_handle = bt_event.service.end_handle;
2249 mp_obj_list_append(&self->srv_list, srv);
2250 }
2251 }
2252 return &self->srv_list;
2253 } else {
2254 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2255 }
2256}
2257STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_conn_services_obj, bt_conn_services);
2258
2259STATIC const mp_map_elem_t bt_connection_locals_dict_table[] = {
2260 // instance methods
2261 { MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&bt_conn_isconnected_obj },
2262 { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&bt_conn_disconnect_obj },
2263 { MP_OBJ_NEW_QSTR(MP_QSTR_services), (mp_obj_t)&bt_conn_services_obj },
2264 { MP_OBJ_NEW_QSTR(MP_QSTR_get_mtu), (mp_obj_t)&bt_conn_get_mtu_obj },
2265
2266};
2267STATIC MP_DEFINE_CONST_DICT(bt_connection_locals_dict, bt_connection_locals_dict_table);
2268
2269static const mp_obj_type_t mod_bt_connection_type = {
2270 { &mp_type_type },
2271 .name = MP_QSTR_GATTCConnection,
2272 .locals_dict = (mp_obj_t)&bt_connection_locals_dict,
2273};
2274
2275STATIC mp_obj_t bt_srv_isprimary(mp_obj_t self_in) {
2276 return mp_const_true;
2277}
2278STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_srv_isprimary_obj, bt_srv_isprimary);
2279
2280STATIC mp_obj_t bt_srv_uuid(mp_obj_t self_in) {
2281 bt_srv_obj_t *self = self_in;
2282
2283 if (self->srv_id.uuid.len == ESP_UUID_LEN_16) {
2284 return mp_obj_new_int(self->srv_id.uuid.uuid.uuid16);
2285 } else if (self->srv_id.uuid.len == ESP_UUID_LEN_32) {
2286 return mp_obj_new_int(self->srv_id.uuid.uuid.uuid32);
2287 } else {
2288 return mp_obj_new_bytes(self->srv_id.uuid.uuid.uuid128, ESP_UUID_LEN_128);
2289 }
2290}
2291STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_srv_uuid_obj, bt_srv_uuid);
2292
2293STATIC mp_obj_t bt_srv_instance(mp_obj_t self_in) {
2294 bt_srv_obj_t *self = self_in;
2295 return mp_obj_new_int(self->srv_id.inst_id);
2296}
2297STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_srv_instance_obj, bt_srv_instance);
2298
2299STATIC mp_obj_t bt_srv_characteristics(mp_obj_t self_in) {
2300 bt_srv_obj_t *self = self_in;
2301
2302 if (self->connection->conn_id >= 0) {
2303 mp_obj_list_init(&self->char_list, 0);
2304
2305
2306 uint16_t attr_count = 0;
2307 esp_ble_gattc_get_attr_count(bt_obj.gattc_if,
2308 self->connection->conn_id,
2309 ESP_GATT_DB_CHARACTERISTIC,
2310 self->start_handle,
2311 self->end_handle,
2312 0,
2313 &attr_count);
2314
2315 if (attr_count > 0) {
2316 esp_gattc_char_elem_t *char_elems = (esp_gattc_char_elem_t *)heap_caps_malloc(sizeof(esp_gattc_char_elem_t) * attr_count, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
2317 if (!char_elems) {
2318 mp_raise_OSError(MP_ENOMEM);
2319 } else {
2320 esp_ble_gattc_get_all_char(bt_obj.gattc_if,
2321 self->connection->conn_id,
2322 self->start_handle,
2323 self->end_handle,
2324 char_elems,
2325 &attr_count,
2326 0);
2327 if (attr_count > 0) {
2328 for (int i = 0; i < attr_count; ++i) {
2329 bt_char_obj_t *chr = m_new_obj(bt_char_obj_t);
2330 chr->base.type = (mp_obj_t)&mod_bt_characteristic_type;
2331 chr->service = self;
2332 memcpy(&chr->characteristic, &char_elems[i], sizeof(esp_gattc_char_elem_t));
2333 chr->value[0] = 0;
2334 chr->value_len = 1;
2335 mp_obj_list_append(&self->char_list, chr);
2336 }
2337 }
2338 free(char_elems);
2339 }
2340 }
2341 return &self->char_list;
2342 } else {
2343 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2344 }
2345}
2346STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_srv_characteristics_obj, bt_srv_characteristics);
2347
2348STATIC const mp_map_elem_t bt_service_locals_dict_table[] = {
2349 // instance methods
2350 { MP_OBJ_NEW_QSTR(MP_QSTR_isprimary), (mp_obj_t)&bt_srv_isprimary_obj },
2351 { MP_OBJ_NEW_QSTR(MP_QSTR_uuid), (mp_obj_t)&bt_srv_uuid_obj },
2352 { MP_OBJ_NEW_QSTR(MP_QSTR_instance), (mp_obj_t)&bt_srv_instance_obj },
2353 { MP_OBJ_NEW_QSTR(MP_QSTR_characteristics), (mp_obj_t)&bt_srv_characteristics_obj },
2354};
2355STATIC MP_DEFINE_CONST_DICT(bt_service_locals_dict, bt_service_locals_dict_table);
2356
2357static const mp_obj_type_t mod_bt_service_type = {
2358 { &mp_type_type },
2359 .name = MP_QSTR_GATTCService,
2360 .locals_dict = (mp_obj_t)&bt_service_locals_dict,
2361};
2362
2363STATIC mp_obj_t bt_char_uuid(mp_obj_t self_in) {
2364 bt_char_obj_t *self = self_in;
2365
2366 if (self->characteristic.uuid.len == ESP_UUID_LEN_16) {
2367 return mp_obj_new_int(self->characteristic.uuid.uuid.uuid16);
2368 } else if (self->characteristic.uuid.len == ESP_UUID_LEN_32) {
2369 return mp_obj_new_int(self->characteristic.uuid.uuid.uuid32);
2370 } else {
2371 return mp_obj_new_bytes(self->characteristic.uuid.uuid.uuid128, ESP_UUID_LEN_128);
2372 }
2373}
2374STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_uuid_obj, bt_char_uuid);
2375
2376STATIC mp_obj_t bt_char_instance(mp_obj_t self_in) {
2377 return mp_obj_new_int(0);
2378}
2379STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_instance_obj, bt_char_instance);
2380
2381STATIC mp_obj_t bt_char_properties(mp_obj_t self_in) {
2382 bt_char_obj_t *self = self_in;
2383 return mp_obj_new_int(self->characteristic.properties);
2384}
2385STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_properties_obj, bt_char_properties);
2386
2387STATIC mp_obj_t bt_char_read(mp_obj_t self_in) {
2388 bt_char_obj_t *self = self_in;
2389 bt_event_result_t bt_event;
2390
2391 if (self->service->connection->conn_id >= 0) {
2392 xQueueReset(xScanQueue);
2393 bt_obj.busy = true;
2394
2395 if (ESP_OK != esp_ble_gattc_read_char (bt_obj.gattc_if, self->service->connection->conn_id,
2396 self->characteristic.char_handle,
2397 ESP_GATT_AUTH_REQ_NONE)) {
2398 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2399 }
2400 while (bt_obj.busy) {
2401 mp_hal_delay_ms(5);
2402 }
2403 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)5)) {
2404 memcpy(self->value, bt_event.read.value, bt_event.read.value_len);
2405 self->value_len = bt_event.read.value_len;
2406 return mp_obj_new_bytes(bt_event.read.value, bt_event.read.value_len);
2407 } else {
2408 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2409 }
2410 } else {
2411 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2412 }
2413}
2414STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_read_obj, bt_char_read);
2415
2416STATIC mp_obj_t bt_char_read_descriptor(mp_obj_t self_in, mp_obj_t uuid) {
2417 bt_char_obj_t *self = self_in;
2418 bt_event_result_t bt_event;
2419
2420 uint16_t descr_uuid_value = mp_obj_get_int(uuid);
2421
2422 if (self->service->connection->conn_id >= 0) {
2423 xQueueReset(xScanQueue);
2424
2425 esp_gattc_descr_elem_t format_descriptor;
2426 uint16_t count = 1;
2427 esp_bt_uuid_t descr_uuid = {.len = ESP_UUID_LEN_16, .uuid.uuid16 = descr_uuid_value};
2428 esp_gatt_status_t ret_val = esp_ble_gattc_get_descr_by_uuid(bt_obj.gattc_if,
2429 self->service->connection->conn_id,
2430 self->service->start_handle,
2431 self->service->end_handle,
2432 self->characteristic.uuid,
2433 descr_uuid,
2434 &format_descriptor,
2435 &count);
2436 if(ret_val == ESP_OK && count == 1) {
2437 bt_obj.busy = true;
2438
2439 if (ESP_OK != esp_ble_gattc_read_char_descr(bt_obj.gattc_if,
2440 self->service->connection->conn_id,
2441 format_descriptor.handle,
2442 ESP_GATT_AUTH_REQ_NONE)) {
2443 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2444 }
2445
2446 while (bt_obj.busy) {
2447 mp_hal_delay_ms(5);
2448 }
2449
2450 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)5)) {
2451 return mp_obj_new_bytes(bt_event.read.value, bt_event.read.value_len);
2452 } else {
2453 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2454 }
2455 } else {
2456 return mp_const_none; // Descriptor not found, no read
2457 }
2458 } else {
2459 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2460 }
2461}
2462STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_char_read_descriptor_obj, bt_char_read_descriptor);
2463
2464STATIC mp_obj_t bt_char_write(mp_obj_t self_in, mp_obj_t value) {
2465 bt_char_obj_t *self = self_in;
2466 bt_event_result_t bt_event;
2467
2468 mp_buffer_info_t bufinfo;
2469 mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ);
2470
2471 if (self->service->connection->conn_id >= 0) {
2472 xQueueReset(xScanQueue);
2473 bt_obj.busy = true;
2474
2475 if (ESP_OK != esp_ble_gattc_write_char (bt_obj.gattc_if, self->service->connection->conn_id,
2476 self->characteristic.char_handle,
2477 bufinfo.len,
2478 bufinfo.buf,
2479 ESP_GATT_WRITE_TYPE_RSP,
2480 ESP_GATT_AUTH_REQ_NONE)) {
2481 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2482 }
2483
2484 while (bt_obj.busy) {
2485 mp_hal_delay_ms(5);
2486 }
2487 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)5)) {
2488 if (bt_event.write.status != ESP_GATT_OK) {
2489 goto error;
2490 }
2491 } else {
2492 goto error;
2493 }
2494 } else {
2495 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2496 }
2497 return mp_const_none;
2498
2499error:
2500 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2501}
2502STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_char_write_obj, bt_char_write);
2503
2504/// \method callback(trigger, handler, arg)
2505STATIC mp_obj_t bt_char_callback(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
2506 STATIC const mp_arg_t allowed_args[] = {
2507 { MP_QSTR_trigger, MP_ARG_REQUIRED | MP_ARG_OBJ, },
2508 { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
2509 { MP_QSTR_arg, MP_ARG_OBJ, {.u_obj = mp_const_none} },
2510 };
2511
2512 // parse arguments
2513 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
2514 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
2515 bt_char_obj_t *self = pos_args[0];
2516 bt_event_result_t bt_event;
2517
2518 // enable the callback
2519 if (args[0].u_obj != mp_const_none && args[1].u_obj != mp_const_none) {
2520 uint32_t trigger = mp_obj_get_int(args[0].u_obj);
2521 if (trigger != MOD_BT_GATTC_NOTIFY_EVT) {
2522 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid trigger"));
2523 }
2524 self->trigger = trigger;
2525 self->handler = args[1].u_obj;
2526 if (args[2].u_obj == mp_const_none) {
2527 self->handler_arg = self;
2528 } else {
2529 self->handler_arg = args[2].u_obj;
2530 }
2531
2532 if (self->service->connection->conn_id >= 0) {
2533 if (ESP_OK != esp_ble_gattc_register_for_notify (self->service->connection->gatt_if,
2534 self->service->connection->srv_bda,
2535 self->characteristic.char_handle)) {
2536 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2537 }
2538
2539 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)(2500 / portTICK_RATE_MS))) {
2540 if (bt_event.register_for_notify.status != ESP_GATT_OK) {
2541 goto error;
2542 }
2543 } else {
2544 goto error;
2545 }
2546
2547 uint16_t attr_count = 0;
2548 uint16_t notify_en = 1;
2549 esp_ble_gattc_get_attr_count(bt_obj.gattc_if,
2550 self->service->connection->conn_id,
2551 ESP_GATT_DB_DESCRIPTOR,
2552 self->service->start_handle,
2553 self->service->end_handle,
2554 self->characteristic.char_handle,
2555 &attr_count);
2556 if (attr_count > 0) {
2557 esp_gattc_descr_elem_t *descr_elems = (esp_gattc_descr_elem_t *)heap_caps_malloc(sizeof(esp_gattc_descr_elem_t) * attr_count, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
2558 if (!descr_elems) {
2559 mp_raise_OSError(MP_ENOMEM);
2560 } else {
2561 esp_ble_gattc_get_all_descr(bt_obj.gattc_if,
2562 self->service->connection->conn_id,
2563 self->characteristic.char_handle,
2564 descr_elems,
2565 &attr_count,
2566 0);
2567 for (int i = 0; i < attr_count; ++i) {
2568 if (descr_elems[i].uuid.len == ESP_UUID_LEN_16 && descr_elems[i].uuid.uuid.uuid16 == ESP_GATT_UUID_CHAR_CLIENT_CONFIG) {
2569 esp_ble_gattc_write_char_descr (bt_obj.gattc_if,
2570 self->service->connection->conn_id,
2571 descr_elems[i].handle,
2572 sizeof(notify_en),
2573 (uint8_t *)¬ify_en,
2574 ESP_GATT_WRITE_TYPE_RSP,
2575 ESP_GATT_AUTH_REQ_NONE);
2576
2577 break;
2578 }
2579 }
2580 free(descr_elems);
2581 }
2582 }
2583 } else {
2584 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2585 }
2586 } else {
2587 self->trigger = 0;
2588 mp_irq_remove(self);
2589 INTERRUPT_OBJ_CLEAN(self);
2590 }
2591
2592 mp_irq_add(self, args[1].u_obj);
2593
2594 return mp_const_none;
2595
2596error:
2597 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2598}
2599STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_char_callback_obj, 1, bt_char_callback);
2600
2601STATIC mp_obj_t bt_char_value(mp_obj_t self_in) {
2602 bt_char_obj_t *self = self_in;
2603 return mp_obj_new_bytes(self->value, self->value_len);
2604}
2605STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_value_obj, bt_char_value);
2606
2607STATIC const mp_map_elem_t bt_characteristic_locals_dict_table[] = {
2608 // instance methods
2609 { MP_OBJ_NEW_QSTR(MP_QSTR_uuid), (mp_obj_t)&bt_char_uuid_obj },
2610 { MP_OBJ_NEW_QSTR(MP_QSTR_instance), (mp_obj_t)&bt_char_instance_obj },
2611 { MP_OBJ_NEW_QSTR(MP_QSTR_properties), (mp_obj_t)&bt_char_properties_obj },
2612 { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&bt_char_read_obj },
2613 { MP_OBJ_NEW_QSTR(MP_QSTR_read_descriptor), (mp_obj_t)&bt_char_read_descriptor_obj },
2614 { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&bt_char_write_obj },
2615 { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&bt_char_callback_obj },
2616 { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&bt_char_value_obj },
2617 // { MP_OBJ_NEW_QSTR(MP_QSTR_descriptors), (mp_obj_t)&bt_char_descriptors_obj },
2618};
2619STATIC MP_DEFINE_CONST_DICT(bt_characteristic_locals_dict, bt_characteristic_locals_dict_table);
2620
2621static const mp_obj_type_t mod_bt_characteristic_type = {
2622 { &mp_type_type },
2623 .name = MP_QSTR_GATTCCharacteristic,
2624 .locals_dict = (mp_obj_t)&bt_characteristic_locals_dict,
2625};
2626
2627// static const mp_obj_type_t mod_bt_descriptor_type = {
2628 // { &mp_type_type },
2629 // .name = MP_QSTR_BT_DESCRIPTOR,
2630 // .locals_dict = (mp_obj_t)&bt_descriptor_locals_dict,
2631// };