· 6 years ago · Feb 04, 2020, 03:04 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 /* Call the following function to input the passkey which is displayed on the remote device */
645 //esp_ble_passkey_reply(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, true, 0x00);
646 //ESP_LOGI(GATTC_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT");
647 printf("PASSKEY1");
648 break;
649 }
650 case ESP_GAP_BLE_NC_REQ_EVT:
651 case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: {
652 printf("BLE paring passkey : %d\n", param->ble_security.key_notif.passkey);
653 break;
654 }
655 case ESP_GAP_BLE_SEC_REQ_EVT: {
656 if (bt_obj.secure){
657 esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
658 }
659 }
660 case ESP_GAP_BLE_SCAN_RESULT_EVT: {
661 bt_event_result_t bt_event_result;
662 esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
663 memcpy(&bt_event_result.scan, scan_result, sizeof(esp_ble_gap_cb_param_t));
664 switch (scan_result->scan_rst.search_evt) {
665 case ESP_GAP_SEARCH_INQ_RES_EVT:
666 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
667 bt_obj.events |= MOD_BT_GATTC_ADV_EVT;
668 if (bt_obj.trigger & MOD_BT_GATTC_ADV_EVT) {
669 mp_irq_queue_interrupt(bluetooth_callback_handler, (void *)&bt_obj);
670 }
671 break;
672 case ESP_GAP_SEARCH_DISC_RES_EVT:
673 break;
674 case ESP_GAP_SEARCH_INQ_CMPL_EVT:
675 if (bt_obj.scan_duration < 0) {
676 esp_ble_gap_set_scan_params(&ble_scan_params);
677 } else {
678 bt_obj.scanning = false;
679 }
680 break;
681 default:
682 break;
683 }
684 break;
685 }
686 default:
687 break;
688 }
689}
690
691static void gattc_events_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
692 int32_t conn_id = 0;
693 esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param;
694 bt_event_result_t bt_event_result;
695
696 switch (event) {
697 case ESP_GATTC_REG_EVT:
698 status = p_data->reg.status;
699 bt_obj.gattc_if = gattc_if;
700 if (bt_obj.secure){
701 esp_ble_gap_config_local_privacy(true);
702 }
703 break;
704 case ESP_GATTC_OPEN_EVT:
705 if (p_data->open.status != ESP_GATT_OK) {
706 bt_event_result.connection.conn_id = -1;
707 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
708 bt_obj.busy = false;
709 }
710 break;
711 case ESP_GATTC_CONNECT_EVT:
712 conn_id = p_data->connect.conn_id;
713 bt_event_result.connection.conn_id = conn_id;
714 bt_event_result.connection.gatt_if = gattc_if;
715 memcpy(bt_event_result.connection.srv_bda, p_data->connect.remote_bda, ESP_BD_ADDR_LEN);
716 esp_ble_gattc_send_mtu_req (gattc_if, p_data->connect.conn_id);
717 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
718 break;
719 case ESP_GATTC_CFG_MTU_EVT:
720 // connection process and MTU request complete
721 bt_obj.busy = false;
722 bt_conn_mtu = p_data->cfg_mtu.mtu;
723 xEventGroupSetBits(bt_event_group, MOD_BT_GATTC_MTU_EVT);
724 break;
725 case ESP_GATTC_READ_CHAR_EVT:
726 if (p_data->read.status == ESP_GATT_OK) {
727 uint16_t read_len = p_data->read.value_len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : p_data->read.value_len;
728 memcpy(&bt_event_result.read.value, p_data->read.value, read_len);
729 bt_event_result.read.value_len = read_len;
730 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
731 }
732 bt_obj.busy = false;
733 break;
734 case ESP_GATTC_WRITE_CHAR_EVT:
735 bt_event_result.write.status = p_data->write.status;
736 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
737 bt_obj.busy = false;
738 break;
739 case ESP_GATTC_SEARCH_RES_EVT: {
740 esp_gatt_id_t *srvc_id = (esp_gatt_id_t *)&p_data->search_res.srvc_id;
741 memcpy(&bt_event_result.service.srv_id, srvc_id, sizeof(esp_gatt_id_t));
742 bt_event_result.service.start_handle = p_data->search_res.start_handle;
743 bt_event_result.service.end_handle = p_data->search_res.end_handle;
744 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
745 break;
746 }
747 case ESP_GATTC_READ_DESCR_EVT:
748 if (p_data->read.status == ESP_GATT_OK) {
749 uint16_t read_len = p_data->read.value_len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : p_data->read.value_len;
750 memcpy(&bt_event_result.read.value, p_data->read.value, read_len);
751 bt_event_result.read.value_len = read_len;
752 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
753 }
754 bt_obj.busy = false;
755 break;
756 case ESP_GATTC_REG_FOR_NOTIFY_EVT:
757 bt_event_result.register_for_notify.status = p_data->reg_for_notify.status;
758 xQueueSend(xScanQueue, (void *)&bt_event_result, (TickType_t)0);
759 break;
760 case ESP_GATTC_NOTIFY_EVT: {
761 bt_char_obj_t *char_obj;
762 char_obj = find_gattc_char (p_data->notify.conn_id, p_data->notify.handle);
763 if (char_obj != NULL) {
764 // copy the new value into the characteristic
765 memcpy(&char_obj->value, p_data->notify.value, p_data->notify.value_len);
766 char_obj->value_len = p_data->notify.value_len;
767
768 // register the event
769 if (p_data->notify.is_notify) {
770 char_obj->events |= MOD_BT_GATTC_NOTIFY_EVT;
771 } else {
772 char_obj->events |= MOD_BT_GATTC_INDICATE_EVT;
773 }
774 if ((char_obj->trigger & MOD_BT_GATTC_NOTIFY_EVT) || (char_obj->trigger & MOD_BT_GATTC_INDICATE_EVT)) {
775 mp_irq_queue_interrupt(gattc_char_callback_handler, char_obj);
776 }
777 }
778 break;
779 }
780 case ESP_GATTC_SEARCH_CMPL_EVT:
781 case ESP_GATTC_CANCEL_OPEN_EVT:
782 bt_obj.busy = false;
783 break;
784 // intentional fall through
785 case ESP_GATTC_CLOSE_EVT:
786 case ESP_GATTC_DISCONNECT_EVT:
787 close_connection(p_data->close.conn_id);
788 bt_obj.busy = false;
789 break;
790 default:
791 break;
792 }
793}
794
795// this function will be called by the interrupt thread
796STATIC void bluetooth_callback_handler(void *arg) {
797 bt_obj_t *self = arg;
798
799 if (self->handler && self->handler != mp_const_none) {
800 mp_call_function_1(self->handler, self->handler_arg);
801 }
802}
803
804// this function will be called by the interrupt thread
805STATIC void gattc_char_callback_handler(void *arg) {
806 bt_char_obj_t *chr = arg;
807
808 if (chr->handler && chr->handler != mp_const_none) {
809 mp_call_function_1(chr->handler, chr->handler_arg);
810 }
811}
812
813// this function will be called by the interrupt thread
814STATIC void gatts_char_callback_handler(void *arg) {
815 bt_gatts_char_obj_t *chr = arg;
816
817 if (chr->handler && chr->handler != mp_const_none) {
818 mp_obj_t r_value = mp_call_function_1(chr->handler, chr->handler_arg);
819
820 if (chr->read_request) {
821 uint32_t u_value;
822 uint8_t *value;
823 uint8_t value_l = 1;
824
825 chr->read_request = false;
826 if (r_value != mp_const_none) {
827 if (mp_obj_is_integer(r_value)) {
828 u_value = mp_obj_get_int_truncated(r_value);
829 value = (uint8_t *)&u_value;
830 if (u_value > UINT16_MAX) {
831 value_l = 4;
832 u_value = lwip_htonl(u_value);
833 } else if (u_value > UINT8_MAX) {
834 value_l = 2;
835 u_value = lwip_htons(u_value);
836 }
837 } else {
838 mp_buffer_info_t bufinfo;
839 mp_get_buffer_raise(r_value, &bufinfo, MP_BUFFER_READ);
840 value = bufinfo.buf;
841 value_l = bufinfo.len;
842 }
843 } else {
844 value = chr->attr_obj.value;
845 value_l = chr->attr_obj.value_len;
846 }
847
848 esp_gatt_rsp_t rsp;
849 memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
850 rsp.attr_value.handle = chr->attr_obj.handle;
851 rsp.attr_value.len = value_l;
852 memcpy(&rsp.attr_value.value, value, value_l);
853 esp_ble_gatts_send_response(bt_obj.gatts_if, bt_obj.gatts_conn_id, chr->trans_id, ESP_GATT_OK, &rsp);
854 }
855 }
856}
857
858static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
859 esp_ble_gatts_cb_param_t *p = (esp_ble_gatts_cb_param_t *)param;
860
861 switch (event) {
862 case ESP_GATTS_REG_EVT:
863 bt_obj.gatts_if = gatts_if;
864 if (bt_obj.secure){
865 esp_ble_gap_config_local_privacy(true);
866 }
867 break;
868 case ESP_GATTS_READ_EVT: {
869 bt_gatts_attr_obj_t *attr_obj = find_gatts_attr_by_handle (p->read.handle);
870 if (attr_obj) {
871 if (attr_obj->is_char) {
872 bt_gatts_char_obj_t *char_obj = (bt_gatts_char_obj_t *)attr_obj;
873 char_obj->events |= MOD_BT_GATTS_READ_EVT;
874 if (char_obj->trigger & MOD_BT_GATTS_READ_EVT) {
875 char_obj->read_request = true;
876 char_obj->trans_id = p->read.trans_id;
877 mp_irq_queue_interrupt(gatts_char_callback_handler, char_obj);
878 break;
879 }
880 }
881 // send the response immediately if it's not a characteristic or if there's no callback registered
882 esp_gatt_rsp_t rsp;
883 memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
884 rsp.attr_value.handle = p->read.handle;
885 rsp.attr_value.len = attr_obj->value_len;
886 memcpy(&rsp.attr_value.value, attr_obj->value, attr_obj->value_len);
887 esp_ble_gatts_send_response(gatts_if, p->read.conn_id, p->read.trans_id, ESP_GATT_OK, &rsp);
888 }
889 break;
890 }
891 case ESP_GATTS_WRITE_EVT: {
892 if (!p->write.is_prep) {
893 bt_gatts_attr_obj_t *attr_obj = find_gatts_attr_by_handle (p->write.handle);
894 if (attr_obj) {
895 // only write up to the maximum allowed size
896 uint16_t write_len = p->write.len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : p->write.len;
897 memcpy(attr_obj->value, p->write.value, write_len);
898 attr_obj->value_len = write_len;
899
900 if (attr_obj->is_char) { // characteristic
901 bt_gatts_char_obj_t *char_obj = (bt_gatts_char_obj_t *)attr_obj;
902 char_obj->events |= MOD_BT_GATTS_WRITE_EVT;
903 if (char_obj->trigger & MOD_BT_GATTS_WRITE_EVT) {
904 mp_irq_queue_interrupt(gatts_char_callback_handler, char_obj);
905 }
906 } else { // descriptor
907 if (attr_obj->uuid.len == ESP_UUID_LEN_16 && attr_obj->uuid.uuid.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) {
908 uint16_t value = param->write.value[1] << 8 | param->write.value[0];
909 bt_gatts_char_obj_t *char_obj = (bt_gatts_char_obj_t *)attr_obj->parent;
910 char_obj->config = value;
911 char_obj->events |= MOD_BT_GATTS_SUBSCRIBE_EVT;
912 if (char_obj->trigger & MOD_BT_GATTS_SUBSCRIBE_EVT) {
913 mp_irq_queue_interrupt(gatts_char_callback_handler, char_obj);
914 }
915
916 if (value == 0x0001) { // notifications enabled
917 bt_gatts_char_obj_t *char_obj = (bt_gatts_char_obj_t *)attr_obj->parent;
918 // the size of value[] needs to be less than MTU size
919 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);
920 }
921 }
922 }
923 esp_ble_gatts_send_response(gatts_if, p->write.conn_id, p->write.trans_id, ESP_GATT_OK, NULL);
924 }
925 }
926 break;
927 }
928 case ESP_GATTS_MTU_EVT:
929 bt_obj.gatts_mtu = p->mtu.mtu;
930 xEventGroupSetBits(bt_event_group, MOD_BT_GATTS_MTU_EVT);
931 break;
932 case ESP_GATTS_EXEC_WRITE_EVT:
933 case ESP_GATTS_CONF_EVT:
934 case ESP_GATTS_UNREG_EVT:
935 break;
936 case ESP_GATTS_CREATE_EVT: {
937 bt_gatts_event_result_t gatts_event;
938 gatts_event.service_handle = p->create.service_handle;
939 xQueueSend(xGattsQueue, (void *)&gatts_event, (TickType_t)0);
940 break;
941 }
942 case ESP_GATTS_ADD_INCL_SRVC_EVT:
943 break;
944 case ESP_GATTS_ADD_CHAR_EVT: {
945 bt_gatts_event_result_t gatts_event;
946 gatts_event.char_handle = p->add_char.attr_handle;
947 xQueueSend(xGattsQueue, (void *)&gatts_event, (TickType_t)0);
948 break;
949 }
950 case ESP_GATTS_ADD_CHAR_DESCR_EVT: {
951 bt_gatts_event_result_t gatts_event;
952 gatts_event.char_descr_handle = p->add_char_descr.attr_handle;
953 xQueueSend(xGattsQueue, (void *)&gatts_event, (TickType_t)0);
954 break;
955 }
956 case ESP_GATTS_DELETE_EVT:
957 break;
958 case ESP_GATTS_START_EVT:
959 break;
960 case ESP_GATTS_STOP_EVT:
961 break;
962 case ESP_GATTS_CONNECT_EVT:
963 // only allow one connection at a time
964 if (bt_obj.gatts_conn_id >= 0) {
965 esp_ble_gatts_close(bt_obj.gatts_if, p->connect.conn_id);
966 } else {
967 memcpy((void *)bt_obj.client_bda, p->connect.remote_bda, ESP_BD_ADDR_LEN);
968 bt_obj.gatts_conn_id = p->connect.conn_id;
969 bt_obj.events |= MOD_BT_GATTS_CONN_EVT;
970 if (bt_obj.trigger & MOD_BT_GATTS_CONN_EVT) {
971 mp_irq_queue_interrupt(bluetooth_callback_handler, (void *)&bt_obj);
972 }
973 if (bt_obj.secure){
974 esp_ble_set_encryption(p->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM);
975 }
976 }
977 break;
978 case ESP_GATTS_DISCONNECT_EVT:
979 bt_obj.gatts_conn_id = -1;
980 xEventGroupClearBits(bt_event_group, MOD_BT_GATTS_MTU_EVT);
981 if (bt_obj.advertising) {
982 if (!bt_obj.secure){
983 esp_ble_gap_start_advertising(&bt_adv_params);
984 } else {
985 esp_ble_gap_start_advertising(&bt_adv_params_sec);
986 }
987 }
988 bt_obj.events |= MOD_BT_GATTS_DISCONN_EVT;
989 xEventGroupSetBits(bt_event_group, MOD_BT_GATTS_DISCONN_EVT);
990 if (bt_obj.trigger & MOD_BT_GATTS_DISCONN_EVT) {
991 mp_irq_queue_interrupt(bluetooth_callback_handler, (void *)&bt_obj);
992 }
993 break;
994 case ESP_GATTS_CLOSE_EVT:
995 xEventGroupSetBits(bt_event_group, MOD_BT_GATTS_CLOSE_EVT);
996 break;
997 case ESP_GATTS_OPEN_EVT:
998 case ESP_GATTS_CANCEL_OPEN_EVT:
999 case ESP_GATTS_LISTEN_EVT:
1000 case ESP_GATTS_CONGEST_EVT:
1001 default:
1002 break;
1003 }
1004}
1005
1006/******************************************************************************/
1007// Micro Python bindings; BT class
1008
1009/// \class Bluetooth
1010static mp_obj_t bt_init_helper(bt_obj_t *self, const mp_arg_val_t *args) {
1011 if (!self->init) {
1012 if (!self->controller_active) {
1013 esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
1014 esp_bt_controller_init(&bt_cfg);
1015 self->controller_active = true;
1016 }
1017
1018 esp_bt_controller_enable(ESP_BT_MODE_BLE);
1019
1020 if (ESP_OK != esp_bluedroid_init()) {
1021 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Bluetooth init failed"));
1022 }
1023 if (ESP_OK != esp_bluedroid_enable()) {
1024 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Bluetooth enable failed"));
1025 }
1026
1027 esp_ble_gap_register_callback(gap_events_handler);
1028 esp_ble_gattc_register_callback(gattc_events_handler);
1029 esp_ble_gatts_register_callback(gatts_event_handler);
1030
1031 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(btc_conn_list), 0);
1032 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(bts_srv_list), 0);
1033 mp_obj_list_init((mp_obj_t)&MP_STATE_PORT(bts_attr_list), 0);
1034 esp_ble_gattc_app_register(MOD_BT_CLIENT_APP_ID);
1035 esp_ble_gatts_app_register(MOD_BT_SERVER_APP_ID);
1036
1037 //set MTU
1038 uint16_t mtu = args[5].u_int;
1039 if(mtu > BT_MTU_SIZE_MAX)
1040 {
1041 esp_ble_gatt_set_local_mtu(BT_MTU_SIZE_MAX);
1042 mod_bt_gatts_mtu_restore = BT_MTU_SIZE_MAX;
1043 }
1044 else
1045 {
1046 esp_ble_gatt_set_local_mtu(mtu);
1047 mod_bt_gatts_mtu_restore = mtu;
1048 }
1049
1050 self->init = true;
1051 }
1052
1053 // get the antenna type
1054 uint8_t antenna;
1055 if (args[1].u_obj == MP_OBJ_NULL) {
1056 // first gen module, so select the internal antenna
1057 if (micropy_hw_antenna_diversity_pin_num == MICROPY_FIRST_GEN_ANT_SELECT_PIN_NUM) {
1058 antenna = ANTENNA_TYPE_INTERNAL;
1059 } else {
1060 antenna = ANTENNA_TYPE_MANUAL;
1061 }
1062 } else if (args[1].u_obj == mp_const_none) {
1063 antenna = ANTENNA_TYPE_MANUAL;
1064 } else {
1065 antenna = mp_obj_get_int(args[1].u_obj);
1066 }
1067 antenna_validate_antenna(antenna);
1068 antenna_select(antenna);
1069
1070 bt_obj.gatts_conn_id = -1;
1071
1072
1073 /* Set BLE modem sleep flag*/
1074 if (args[2].u_obj != MP_OBJ_NULL) {
1075 esp_err_t err = modem_sleep(mp_obj_is_true(args[2].u_obj));
1076 if(ESP_OK != err)
1077 {
1078 nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err)));
1079 }
1080 }
1081
1082 if (args[3].u_bool){
1083 bt_obj.secure = true;
1084
1085 uint32_t passKey = args[4].u_int;
1086 if (!is_pin_valid(passKey)){
1087 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Only 6 digit (0-9) pins are allowed"));
1088 }
1089 set_secure_parameters(passKey);
1090 }
1091
1092 return mp_const_none;
1093}
1094
1095STATIC const mp_arg_t bt_init_args[] = {
1096 { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
1097 { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = E_BT_STACK_MODE_BLE} },
1098 { MP_QSTR_antenna, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
1099 { MP_QSTR_modem_sleep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
1100 { MP_QSTR_secure, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
1101 { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 123456} },
1102 { MP_QSTR_mtu, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BT_MTU_SIZE_MAX} },
1103
1104};
1105STATIC 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) {
1106 // parse args
1107 mp_map_t kw_args;
1108 mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
1109 // parse args
1110 mp_arg_val_t args[MP_ARRAY_SIZE(bt_init_args)];
1111 mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), bt_init_args, args);
1112
1113 // setup the object
1114 bt_obj_t *self = (bt_obj_t *)&bt_obj;
1115 self->base.type = (mp_obj_t)&mod_network_nic_type_bt;
1116
1117 // check the peripheral id
1118 if (args[0].u_int != 0) {
1119 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
1120 }
1121
1122 if (args[4].u_bool) {
1123 if (heap_caps_get_free_size(MALLOC_CAP_SPIRAM) == 0) {
1124 nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError,"Secure BLE not available for 512K RAM devices"));
1125 }
1126 }
1127
1128 // run the constructor if the peripehral is not initialized or extra parameters are given
1129 if (n_kw > 0 || !self->init) {
1130 // start the peripheral
1131 bt_init_helper(self, &args[1]);
1132 }
1133
1134 return (mp_obj_t)self;
1135}
1136
1137STATIC mp_obj_t bt_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1138 // parse args
1139 mp_arg_val_t args[MP_ARRAY_SIZE(bt_init_args) - 1];
1140 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &bt_init_args[1], args);
1141 return bt_init_helper(pos_args[0], args);
1142}
1143STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_init_obj, 1, bt_init);
1144
1145mp_obj_t bt_deinit(mp_obj_t self_in) {
1146
1147 MP_THREAD_GIL_EXIT();
1148 modbt_deinit(false);
1149 MP_THREAD_GIL_ENTER();
1150 return mp_const_none;
1151}
1152STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_deinit_obj, bt_deinit);
1153
1154STATIC mp_obj_t bt_start_scan(mp_obj_t self_in, mp_obj_t timeout) {
1155 if (bt_obj.scanning || bt_obj.busy) {
1156 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "operation already in progress"));
1157 }
1158
1159 int32_t duration = mp_obj_get_int(timeout);
1160 if (duration == 0) {
1161 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid scan time"));
1162 }
1163
1164 bt_obj.scan_duration = duration;
1165 bt_obj.scanning = true;
1166 xQueueReset(xScanQueue);
1167 if (ESP_OK != esp_ble_gap_set_scan_params(&ble_scan_params)) {
1168 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1169 }
1170
1171 return mp_const_none;
1172}
1173STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_start_scan_obj, bt_start_scan);
1174
1175static mp_obj_t modbt_start_scan(mp_obj_t timeout)
1176{
1177 return bt_start_scan(NULL, timeout);
1178}
1179
1180STATIC mp_obj_t bt_isscanning(mp_obj_t self_in) {
1181 if (bt_obj.scanning) {
1182 return mp_const_true;
1183 }
1184 return mp_const_false;
1185}
1186STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_isscanning_obj, bt_isscanning);
1187
1188STATIC mp_obj_t bt_modem_sleep(mp_uint_t n_args, const mp_obj_t *args) {
1189
1190 bt_obj_t *self = args[0];
1191 /* Modem sleep APIs shall not be called before bt_controller_enable() */
1192 if(self->init)
1193 {
1194 if(n_args > 1)
1195 {
1196 if(ESP_OK != modem_sleep(mp_obj_is_true(args[1])))
1197 {
1198 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1199 }
1200 }
1201 else
1202 {
1203 /* return modem sleep status */
1204 return mp_obj_new_bool(esp_bt_controller_is_sleeping());
1205 }
1206 }
1207 else
1208 {
1209 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "BLE module not initialized"));
1210 }
1211
1212 return mp_const_none;
1213}
1214STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bt_modem_sleep_obj, 1, 2, bt_modem_sleep);
1215
1216STATIC mp_obj_t bt_stop_scan(mp_obj_t self_in) {
1217 if (bt_obj.scanning) {
1218 esp_ble_gap_stop_scanning();
1219 bt_obj.scanning = false;
1220 }
1221 return mp_const_none;
1222}
1223STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_stop_scan_obj, bt_stop_scan);
1224
1225STATIC mp_obj_t bt_read_scan(mp_obj_t self_in) {
1226 bt_event_result_t bt_event;
1227
1228 STATIC const qstr bt_scan_info_fields[] = {
1229 MP_QSTR_mac, MP_QSTR_addr_type, MP_QSTR_adv_type, MP_QSTR_rssi, MP_QSTR_data,
1230 };
1231
1232 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)0)) {
1233 mp_obj_t tuple[5];
1234 tuple[0] = mp_obj_new_bytes((const byte *)bt_event.scan.scan_rst.bda, 6);
1235 tuple[1] = mp_obj_new_int(bt_event.scan.scan_rst.ble_addr_type);
1236 tuple[2] = mp_obj_new_int(bt_event.scan.scan_rst.ble_evt_type & 0x03); // FIXME
1237 tuple[3] = mp_obj_new_int(bt_event.scan.scan_rst.rssi);
1238 tuple[4] = mp_obj_new_bytes((const byte *)bt_event.scan.scan_rst.ble_adv, sizeof(bt_event.scan.scan_rst.ble_adv));
1239
1240 return mp_obj_new_attrtuple(bt_scan_info_fields, 5, tuple);
1241 }
1242 return mp_const_none;
1243}
1244STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_read_scan_obj, bt_read_scan);
1245
1246STATIC mp_obj_t bt_get_advertisements(mp_obj_t self_in) {
1247 bt_event_result_t bt_event;
1248
1249 STATIC const qstr bt_scan_info_fields[] = {
1250 MP_QSTR_mac, MP_QSTR_addr_type, MP_QSTR_adv_type, MP_QSTR_rssi, MP_QSTR_data,
1251 };
1252
1253 mp_obj_t advs = mp_obj_new_list(0, NULL);
1254 while (xQueueReceive(xScanQueue, &bt_event, (TickType_t)0)) {
1255 mp_obj_t tuple[5];
1256 tuple[0] = mp_obj_new_bytes((const byte *)bt_event.scan.scan_rst.bda, 6);
1257 tuple[1] = mp_obj_new_int(bt_event.scan.scan_rst.ble_addr_type);
1258 tuple[2] = mp_obj_new_int(bt_event.scan.scan_rst.ble_evt_type & 0x03); // FIXME
1259 tuple[3] = mp_obj_new_int(bt_event.scan.scan_rst.rssi);
1260 tuple[4] = mp_obj_new_bytes((const byte *)bt_event.scan.scan_rst.ble_adv, sizeof(bt_event.scan.scan_rst.ble_adv));
1261
1262 mp_obj_list_append(advs, mp_obj_new_attrtuple(bt_scan_info_fields, 5, tuple));
1263 }
1264 return advs;
1265}
1266STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_get_advertisements_obj, bt_get_advertisements);
1267
1268STATIC mp_obj_t bt_resolve_adv_data(mp_obj_t self_in, mp_obj_t adv_data, mp_obj_t data_type) {
1269 mp_buffer_info_t bufinfo;
1270 uint8_t data_len;
1271 uint8_t *data;
1272
1273 uint8_t type = mp_obj_get_int(data_type);
1274 mp_get_buffer_raise(adv_data, &bufinfo, MP_BUFFER_READ);
1275 data = esp_ble_resolve_adv_data(bufinfo.buf, type, &data_len);
1276
1277 if (data) {
1278 switch(type) {
1279 case ESP_BLE_AD_TYPE_FLAG:
1280 return mp_obj_new_int(*(int8_t *)data);
1281 case ESP_BLE_AD_TYPE_16SRV_PART:
1282 case ESP_BLE_AD_TYPE_16SRV_CMPL:
1283 case ESP_BLE_AD_TYPE_32SRV_PART:
1284 case ESP_BLE_AD_TYPE_32SRV_CMPL:
1285 case ESP_BLE_AD_TYPE_128SRV_PART:
1286 case ESP_BLE_AD_TYPE_128SRV_CMPL:
1287 return mp_obj_new_bytes(data, data_len);
1288 case ESP_BLE_AD_TYPE_NAME_SHORT:
1289 case ESP_BLE_AD_TYPE_NAME_CMPL:
1290 return mp_obj_new_str((char *)data, data_len);
1291 case ESP_BLE_AD_TYPE_TX_PWR:
1292 return mp_obj_new_int(*(int8_t *)data);
1293 case ESP_BLE_AD_TYPE_DEV_CLASS:
1294 break;
1295 case ESP_BLE_AD_TYPE_SERVICE_DATA:
1296 return mp_obj_new_bytes(data, data_len);
1297 case ESP_BLE_AD_TYPE_APPEARANCE:
1298 break;
1299 case ESP_BLE_AD_TYPE_ADV_INT:
1300 break;
1301 case ESP_BLE_AD_TYPE_32SERVICE_DATA:
1302 break;
1303 case ESP_BLE_AD_TYPE_128SERVICE_DATA:
1304 break;
1305 case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE:
1306 return mp_obj_new_bytes(data, data_len);
1307 default:
1308 break;
1309 }
1310 }
1311 return mp_const_none;
1312}
1313STATIC MP_DEFINE_CONST_FUN_OBJ_3(bt_resolve_adv_data_obj, bt_resolve_adv_data);
1314
1315/// \method callback(trigger, handler, arg)
1316STATIC mp_obj_t bt_callback(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1317 STATIC const mp_arg_t allowed_args[] = {
1318 { MP_QSTR_trigger, MP_ARG_REQUIRED | MP_ARG_OBJ, },
1319 { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
1320 { MP_QSTR_arg, MP_ARG_OBJ, {.u_obj = mp_const_none} },
1321 };
1322
1323 // parse arguments
1324 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1325 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1326 bt_obj_t *self = pos_args[0];
1327
1328 // enable the callback
1329 if (args[0].u_obj != mp_const_none && args[1].u_obj != mp_const_none) {
1330 self->trigger = mp_obj_get_int(args[0].u_obj);
1331 self->handler = args[1].u_obj;
1332 if (args[2].u_obj == mp_const_none) {
1333 self->handler_arg = self;
1334 } else {
1335 self->handler_arg = args[2].u_obj;
1336 }
1337 } else { // disable the callback
1338 self->trigger = 0;
1339 mp_irq_remove(self);
1340 INTERRUPT_OBJ_CLEAN(self);
1341 }
1342
1343 mp_irq_add(self, args[1].u_obj);
1344
1345 return mp_const_none;
1346}
1347STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_callback_obj, 1, bt_callback);
1348
1349STATIC mp_obj_t bt_events(mp_obj_t self_in) {
1350 bt_obj_t *self = self_in;
1351
1352 int32_t events = self->events;
1353 self->events = 0;
1354 return mp_obj_new_int(events);
1355}
1356STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_events_obj, bt_events);
1357
1358static mp_obj_t bt_connect_helper(mp_obj_t addr, TickType_t timeout){
1359
1360 bt_event_result_t bt_event;
1361 EventBits_t uxBits;
1362
1363
1364 esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication
1365 esp_ble_io_cap_t iocap = ESP_IO_CAP_IN; //set the IO capability to No output No input
1366 uint8_t key_size = 16; //the key size should be 7~16 bytes
1367 uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
1368 uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
1369 uint8_t oob_support = ESP_BLE_OOB_DISABLE;
1370 esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
1371 esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
1372 esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
1373 esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
1374 esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
1375 esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
1376
1377 esp_ble_gap_config_local_privacy(true); //Sets local
1378
1379 if (bt_obj.busy) {
1380 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "operation already in progress"));
1381 }
1382
1383 if (bt_obj.scanning) {
1384 esp_ble_gap_stop_scanning();
1385 mp_hal_delay_ms(50);
1386 bt_obj.scanning = false;
1387 }
1388
1389 mp_buffer_info_t bufinfo;
1390 mp_get_buffer_raise(addr, &bufinfo, MP_BUFFER_READ);
1391
1392 xQueueReset(xScanQueue);
1393 bt_obj.busy = true;
1394
1395 /* Initiate a background connection, esp_ble_gattc_open returns immediately */
1396 if (ESP_OK != esp_ble_gattc_open(bt_obj.gattc_if, bufinfo.buf, BLE_ADDR_TYPE_PUBLIC, true)) {
1397 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1398 }
1399 MP_THREAD_GIL_EXIT();
1400 if (xQueueReceive(xScanQueue, &bt_event, timeout) == pdTRUE)
1401 {
1402 if (bt_event.connection.conn_id < 0) {
1403 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection refused"));
1404 }
1405
1406 // setup the object
1407 bt_connection_obj_t *conn = m_new_obj(bt_connection_obj_t);
1408 conn->base.type = (mp_obj_t)&mod_bt_connection_type;
1409 conn->conn_id = bt_event.connection.conn_id;
1410 conn->gatt_if = bt_event.connection.gatt_if;
1411 uxBits = xEventGroupWaitBits(bt_event_group, MOD_BT_GATTC_MTU_EVT, true, true, 1000/portTICK_PERIOD_MS);
1412 if(uxBits & MOD_BT_GATTC_MTU_EVT)
1413 {
1414 conn->mtu = bt_conn_mtu;
1415 }
1416 memcpy(conn->srv_bda, bt_event.connection.srv_bda, 6);
1417 mp_obj_list_append((void *)&MP_STATE_PORT(btc_conn_list), conn);
1418 return conn;
1419 }
1420 else
1421 {
1422 (void)esp_ble_gap_disconnect(bufinfo.buf);
1423 nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out"));
1424 }
1425 MP_THREAD_GIL_ENTER();
1426 return mp_const_none;
1427}
1428
1429
1430STATIC mp_obj_t bt_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1431
1432 STATIC const mp_arg_t allowed_args[] = {
1433 { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_OBJ, },
1434 { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
1435 };
1436
1437 // parse arguments
1438 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1439 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1440
1441 mp_obj_t addr = args[0].u_obj;
1442
1443 /* Timeout parameter is in miliseconds */
1444 TickType_t timeout;
1445 if(args[1].u_obj == MP_OBJ_NULL){
1446 timeout = portMAX_DELAY;
1447 }
1448 else
1449 {
1450 if(MP_OBJ_IS_SMALL_INT(args[1].u_obj) == true) {
1451 timeout = mp_obj_get_int(args[1].u_obj);
1452 }
1453 else
1454 {
1455 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "If timeout is specified it must be a valid integer number"));
1456 }
1457 }
1458
1459 return bt_connect_helper(addr, timeout);
1460}
1461STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_connect_obj, 1, bt_connect);
1462
1463static mp_obj_t modbt_connect(mp_obj_t addr)
1464{
1465 return bt_connect_helper(addr, portMAX_DELAY);
1466}
1467
1468
1469STATIC mp_obj_t bt_set_advertisement_params (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1470 static const mp_arg_t allowed_args[] = {
1471 { MP_QSTR_adv_int_min, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x20} },
1472 { MP_QSTR_adv_int_max, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x40} },
1473 { MP_QSTR_adv_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ADV_TYPE_IND} },
1474 { MP_QSTR_own_addr_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BLE_ADDR_TYPE_PUBLIC} },
1475 { MP_QSTR_channel_map, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ADV_CHNL_ALL} },
1476 { MP_QSTR_adv_filter_policy, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY} },
1477 };
1478
1479 // parse args
1480 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1481 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1482
1483 // adv_int_min
1484 bt_adv_params.adv_int_min = (uint16_t)args[0].u_int;
1485
1486 // adv_int_max
1487 bt_adv_params.adv_int_max = (uint16_t)args[1].u_int;
1488
1489 // adv_type
1490 bt_adv_params.adv_type = (esp_ble_adv_type_t)args[2].u_int;
1491
1492 // own_addr_type
1493 bt_adv_params.own_addr_type = (esp_ble_addr_type_t)args[3].u_int;
1494
1495 // channel_map
1496 bt_adv_params.channel_map = (esp_ble_adv_channel_t)args[4].u_int;
1497
1498 // adv_filter_policy
1499 bt_adv_params.adv_filter_policy = (esp_ble_adv_filter_t)args[5].u_int;
1500
1501 return mp_const_none;
1502}
1503STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_set_advertisement_params_obj, 1, bt_set_advertisement_params);
1504
1505
1506STATIC mp_obj_t bt_set_advertisement (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1507 static const mp_arg_t allowed_args[] = {
1508 { MP_QSTR_name, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1509 { MP_QSTR_manufacturer_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1510 { MP_QSTR_service_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1511 { MP_QSTR_service_uuid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1512 };
1513
1514 mp_buffer_info_t manuf_bufinfo;
1515 mp_buffer_info_t srv_bufinfo;
1516 mp_buffer_info_t uuid_bufinfo;
1517
1518 // parse args
1519 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1520 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1521
1522 // device name
1523 if (args[0].u_obj != mp_const_none) {
1524 const char *name = mp_obj_str_get_str(args[0].u_obj);
1525 adv_data.include_name = true;
1526 esp_ble_gap_set_device_name(name);
1527 } else {
1528 adv_data.include_name = false;
1529 esp_ble_gap_set_device_name(" ");
1530 }
1531
1532 // manufacturer data
1533 if (args[1].u_obj != mp_const_none) {
1534 mp_get_buffer_raise(args[1].u_obj, &manuf_bufinfo, MP_BUFFER_READ);
1535 adv_data.manufacturer_len = manuf_bufinfo.len;
1536 adv_data.p_manufacturer_data = manuf_bufinfo.buf;
1537 } else {
1538 adv_data.manufacturer_len = 0;
1539 adv_data.p_manufacturer_data = NULL;
1540 }
1541
1542 // service data
1543 if (args[2].u_obj != mp_const_none) {
1544 mp_get_buffer_raise(args[2].u_obj, &srv_bufinfo, MP_BUFFER_READ);
1545 adv_data.service_data_len = srv_bufinfo.len;
1546 adv_data.p_service_data = srv_bufinfo.buf;
1547 } else {
1548 adv_data.service_data_len = 0;
1549 adv_data.p_service_data = NULL;
1550 }
1551
1552 // service uuid
1553 if (args[3].u_obj != mp_const_none) {
1554 if (mp_obj_is_integer(args[3].u_obj)) {
1555 uint32_t srv_uuid = mp_obj_get_int_truncated(args[3].u_obj);
1556 uint8_t uuid_buf[16] = {0};
1557 memcpy(uuid_buf, (uint8_t *)&srv_uuid, sizeof(uuid_buf));
1558 adv_data.service_uuid_len = 16;
1559 adv_data.p_service_uuid = (uint8_t *)&srv_uuid;
1560 } else {
1561 mp_get_buffer_raise(args[3].u_obj, &uuid_bufinfo, MP_BUFFER_READ);
1562 adv_data.service_uuid_len = uuid_bufinfo.len;
1563 adv_data.p_service_uuid = uuid_bufinfo.buf;
1564 if (adv_data.service_uuid_len % 16) {
1565 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "incorrect service UUID length"));
1566 }
1567 }
1568 } else {
1569 adv_data.service_uuid_len = 0;
1570 adv_data.p_service_uuid = NULL;
1571 }
1572
1573 adv_data.set_scan_rsp = false;
1574 adv_data.include_txpower = true,
1575 adv_data.min_interval = 0x20;
1576 adv_data.max_interval = 0x40;
1577 adv_data.appearance = 0x00;
1578 adv_data.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT);
1579
1580 // copy all the info to the scan response
1581 memcpy(&scan_rsp_data, &adv_data, sizeof(esp_ble_adv_data_t));
1582 scan_rsp_data.set_scan_rsp = true;
1583 // do not include the name or the tx power in the scan response
1584 scan_rsp_data.include_name = false;
1585 scan_rsp_data.include_txpower = false;
1586 // do not include the service uuid or service data in the advertisement, only in the scan response
1587 adv_data.manufacturer_len = 0;
1588 adv_data.p_manufacturer_data = NULL;
1589 adv_data.service_data_len = 0;
1590 adv_data.p_service_data = NULL;
1591 adv_data.service_uuid_len = 0;
1592 adv_data.p_service_uuid = NULL;
1593 esp_ble_gap_config_adv_data(&adv_data);
1594 esp_ble_gap_config_adv_data(&scan_rsp_data);
1595
1596 // wait for the advertisement data to be configured
1597 bt_gatts_event_result_t gatts_event;
1598 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1599
1600 return mp_const_none;
1601}
1602STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_set_advertisement_obj, 1, bt_set_advertisement);
1603
1604
1605STATIC mp_obj_t bt_set_advertisement_raw(mp_obj_t self_in, mp_obj_t raw_data) {
1606 mp_buffer_info_t bufinfo;
1607 uint32_t data_len;
1608 uint8_t data[30] = {0};
1609
1610 if (raw_data != mp_const_none) {
1611 mp_get_buffer_raise(raw_data, &bufinfo, MP_BUFFER_READ);
1612 if (bufinfo.len < 31) {
1613 memcpy(data, (uint8_t *)bufinfo.buf, bufinfo.len);
1614 data_len = bufinfo.len;
1615 } else {
1616 memcpy(data, (uint8_t *)bufinfo.buf, sizeof(data));
1617 data_len = sizeof(data);
1618 }
1619
1620 esp_ble_gap_config_adv_data_raw(data, data_len);
1621
1622 // wait for the advertisement data to be configured
1623 bt_gatts_event_result_t gatts_event;
1624 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1625 }
1626
1627 return mp_const_none;
1628}
1629STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_set_advertisement_raw_obj, bt_set_advertisement_raw);
1630
1631
1632STATIC mp_obj_t bt_advertise(mp_obj_t self_in, mp_obj_t enable) {
1633 if (mp_obj_is_true(enable)) {
1634 // some sensible time to wait for the advertisement configuration to complete
1635 mp_hal_delay_ms(50);
1636 if (!bt_obj.secure){
1637 esp_ble_gap_start_advertising(&bt_adv_params);
1638 } else {
1639 esp_ble_gap_start_advertising(&bt_adv_params_sec);
1640 }
1641 bt_obj.advertising = true;
1642 } else {
1643 esp_ble_gap_stop_advertising();
1644 bt_obj.advertising = false;
1645 }
1646 return mp_const_none;
1647}
1648STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_advertise_obj, bt_advertise);
1649
1650STATIC mp_obj_t bt_service (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1651 static const mp_arg_t allowed_args[] = {
1652 { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ },
1653 { MP_QSTR_isprimary, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
1654 { MP_QSTR_nbr_chars, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
1655 { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
1656 };
1657
1658 mp_buffer_info_t uuid_bufinfo;
1659 esp_gatt_srvc_id_t service_id;
1660
1661 // parse args
1662 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1663 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1664
1665 // service uuid
1666 if (mp_obj_is_integer(args[0].u_obj)) {
1667 uint32_t srv_uuid = mp_obj_get_int_truncated(args[0].u_obj);
1668 if (srv_uuid > UINT16_MAX) {
1669 service_id.id.uuid.len = 4;
1670 service_id.id.uuid.uuid.uuid32 = srv_uuid;
1671 } else {
1672 service_id.id.uuid.len = 2;
1673 service_id.id.uuid.uuid.uuid16 = srv_uuid;
1674 }
1675 } else {
1676 mp_get_buffer_raise(args[0].u_obj, &uuid_bufinfo, MP_BUFFER_READ);
1677 if (uuid_bufinfo.len != 16) {
1678 goto error;
1679 }
1680 service_id.id.uuid.len = uuid_bufinfo.len;
1681 memcpy(service_id.id.uuid.uuid.uuid128, uuid_bufinfo.buf, sizeof(service_id.id.uuid.uuid.uuid128));
1682 }
1683
1684 service_id.is_primary = args[1].u_bool;
1685 service_id.id.inst_id = 0x00;
1686
1687 esp_ble_gatts_create_service(bt_obj.gatts_if, &service_id, (args[2].u_int * 3) + 1);
1688
1689 bt_gatts_event_result_t gatts_event;
1690 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1691
1692 bt_gatts_srv_obj_t *srv = m_new_obj(bt_gatts_srv_obj_t);
1693 srv->base.type = (mp_obj_t)&mod_bt_gatts_service_type;
1694 srv->handle = gatts_event.service_handle;
1695
1696 if (args[3].u_bool) {
1697 esp_ble_gatts_start_service(gatts_event.service_handle);
1698 srv->started = true;
1699 }
1700
1701 mp_obj_list_append((mp_obj_t)&MP_STATE_PORT(bts_srv_list), srv);
1702
1703 return srv;
1704
1705error:
1706 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
1707}
1708STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_service_obj, 1, bt_service);
1709
1710STATIC mp_obj_t bt_service_start(mp_obj_t self_in) {
1711 bt_gatts_srv_obj_t *self = self_in;
1712 if (!self->started) {
1713 if (ESP_OK != esp_ble_gatts_start_service(self->handle)) {
1714 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1715 }
1716 self->started = true;
1717 }
1718 return mp_const_none;
1719}
1720STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_service_start_obj, bt_service_start);
1721
1722STATIC mp_obj_t bt_service_stop(mp_obj_t self_in) {
1723 bt_gatts_srv_obj_t *self = self_in;
1724 if (self->started) {
1725 if (ESP_OK != esp_ble_gatts_stop_service(self->handle)) {
1726 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
1727 }
1728 self->started = false;
1729 }
1730 return mp_const_none;
1731}
1732STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_service_stop_obj, bt_service_stop);
1733
1734STATIC mp_obj_t bt_characteristic (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1735 static const mp_arg_t allowed_args[] = {
1736 { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ },
1737 { MP_QSTR_permissions, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1738 { MP_QSTR_properties, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1739 { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
1740 };
1741
1742 bt_gatts_srv_obj_t *self = pos_args[0];
1743
1744 // parse args
1745 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1746 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1747
1748 mp_buffer_info_t uuid_bufinfo;
1749 esp_bt_uuid_t char_uuid;
1750
1751 // characteristic uuid
1752 if (mp_obj_is_integer(args[0].u_obj)) {
1753 uint32_t srv_uuid = mp_obj_get_int_truncated(args[0].u_obj);
1754 if (srv_uuid > UINT16_MAX) {
1755 char_uuid.len = 4;
1756 char_uuid.uuid.uuid32 = srv_uuid;
1757 } else {
1758 char_uuid.len = 2;
1759 char_uuid.uuid.uuid16 = srv_uuid;
1760 }
1761 } else {
1762 mp_get_buffer_raise(args[0].u_obj, &uuid_bufinfo, MP_BUFFER_READ);
1763 if (uuid_bufinfo.len != 16) {
1764 goto error;
1765 }
1766 char_uuid.len = uuid_bufinfo.len;
1767 memcpy(char_uuid.uuid.uuid128, uuid_bufinfo.buf, sizeof(char_uuid.uuid.uuid128));
1768 }
1769
1770 uint32_t permissions = 0;
1771 if (args[1].u_obj != mp_const_none) {
1772 permissions = mp_obj_get_int(args[1].u_obj);
1773 } else {
1774 if (!bt_obj.secure){
1775 permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
1776 } else {
1777 permissions = ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED;
1778 }
1779 }
1780
1781 uint32_t properties = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
1782 if (args[2].u_obj != mp_const_none) {
1783 properties = mp_obj_get_int(args[2].u_obj);
1784 }
1785
1786 bt_gatts_char_obj_t *characteristic = m_new_obj(bt_gatts_char_obj_t);
1787 characteristic->attr_obj.base.type = (mp_obj_t)&mod_bt_gatts_char_type;
1788 characteristic->attr_obj.parent = self;
1789 characteristic->attr_obj.is_char = true;
1790 characteristic->attr_obj.properties = properties;
1791 characteristic->trigger = 0;
1792 characteristic->events = 0;
1793
1794 if (args[3].u_obj != mp_const_none) {
1795 // characteristic value
1796 if (mp_obj_is_integer(args[3].u_obj)) {
1797 uint32_t value = mp_obj_get_int_truncated(args[3].u_obj);
1798 if (value > UINT16_MAX) {
1799 characteristic->attr_obj.value_len = 4;
1800 value = lwip_htonl(value);
1801 } else if (value > UINT8_MAX) {
1802 characteristic->attr_obj.value_len = 2;
1803 value = lwip_htons(value);
1804 } else {
1805 characteristic->attr_obj.value_len = 1;
1806 }
1807 memcpy(characteristic->attr_obj.value, &value, sizeof(value));
1808 } else {
1809 mp_buffer_info_t value_bufinfo;
1810 mp_get_buffer_raise(args[3].u_obj, &value_bufinfo, MP_BUFFER_READ);
1811 uint16_t write_len = value_bufinfo.len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : value_bufinfo.len;
1812 memcpy(characteristic->attr_obj.value, value_bufinfo.buf, write_len);
1813 characteristic->attr_obj.value_len = write_len;
1814 }
1815 } else {
1816 characteristic->attr_obj.value[0] = 0;
1817 characteristic->attr_obj.value_len = 1;
1818 }
1819
1820 esp_ble_gatts_add_char(self->handle, &char_uuid, permissions, properties, NULL, NULL);
1821
1822 bt_gatts_event_result_t gatts_event;
1823 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1824
1825 characteristic->attr_obj.handle = gatts_event.char_handle;
1826 memcpy(&characteristic->attr_obj.uuid, &char_uuid, sizeof(char_uuid));
1827
1828 mp_obj_list_append((mp_obj_t)&MP_STATE_PORT(bts_attr_list), characteristic);
1829
1830 bt_gatts_attr_obj_t *descriptor = m_new_obj(bt_gatts_attr_obj_t);
1831 descriptor->uuid.len = ESP_UUID_LEN_16;
1832 descriptor->uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
1833
1834 esp_ble_gatts_add_char_descr(self->handle, &descriptor->uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
1835
1836 xQueueReceive(xGattsQueue, &gatts_event, portMAX_DELAY);
1837
1838 descriptor->base.type = (mp_obj_t)&mod_bt_gatts_char_type;
1839 descriptor->handle = gatts_event.char_descr_handle;
1840 descriptor->parent = characteristic;
1841 descriptor->is_char = false;
1842 descriptor->value_len = 2;
1843 descriptor->value[0] = 0;
1844 descriptor->value[1] = 0;
1845
1846 mp_obj_list_append((mp_obj_t)&MP_STATE_PORT(bts_attr_list), descriptor);
1847
1848 return characteristic;
1849
1850error:
1851 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
1852}
1853STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_characteristic_obj, 1, bt_characteristic);
1854
1855
1856STATIC const mp_map_elem_t bt_gatts_service_locals_dict_table[] = {
1857 // instance methods
1858 { MP_OBJ_NEW_QSTR(MP_QSTR_characteristic), (mp_obj_t)&bt_characteristic_obj },
1859 { MP_OBJ_NEW_QSTR(MP_QSTR_start), (mp_obj_t)&bt_service_start_obj },
1860 { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&bt_service_stop_obj },
1861};
1862STATIC MP_DEFINE_CONST_DICT(bt_gatts_service_locals_dict, bt_gatts_service_locals_dict_table);
1863
1864static const mp_obj_type_t mod_bt_gatts_service_type = {
1865 { &mp_type_type },
1866 .name = MP_QSTR_GATTSService,
1867 .locals_dict = (mp_obj_t)&bt_gatts_service_locals_dict,
1868};
1869
1870STATIC mp_obj_t bt_characteristic_value (mp_uint_t n_args, const mp_obj_t *args) {
1871 bt_gatts_char_obj_t *self = args[0];
1872 if (n_args == 1) {
1873 // get
1874 return mp_obj_new_bytes(self->attr_obj.value, self->attr_obj.value_len);
1875 } else {
1876 // set
1877 if (mp_obj_is_integer(args[1])) {
1878 uint32_t value = mp_obj_get_int_truncated(args[1]);
1879 memcpy(self->attr_obj.value, &value, sizeof(value));
1880 if (value > 0xFF) {
1881 self->attr_obj.value_len = 2;
1882 } else if (value > 0xFFFF) {
1883 self->attr_obj.value_len = 4;
1884 } else {
1885 self->attr_obj.value_len = 1;
1886 }
1887 } else {
1888 mp_buffer_info_t value_bufinfo;
1889 mp_get_buffer_raise(args[1], &value_bufinfo, MP_BUFFER_READ);
1890 uint8_t value_len = value_bufinfo.len > BT_CHAR_VALUE_SIZE_MAX ? BT_CHAR_VALUE_SIZE_MAX : value_bufinfo.len;
1891 memcpy(self->attr_obj.value, value_bufinfo.buf, value_len);
1892 self->attr_obj.value_len = value_len;
1893 }
1894
1895 bool confirm = self->attr_obj.properties & ESP_GATT_CHAR_PROP_BIT_INDICATE;
1896 if (ESP_OK != esp_ble_gatts_send_indicate(bt_obj.gatts_if, bt_obj.gatts_conn_id, self->attr_obj.handle,
1897 self->attr_obj.value_len, self->attr_obj.value, confirm)) {
1898 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Erorr while sending BLE indication/notification"));
1899 }
1900 return mp_const_none;
1901 }
1902}
1903STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bt_characteristic_value_obj, 1, 2, bt_characteristic_value);
1904
1905/// \method callback(trigger, handler, arg)
1906STATIC mp_obj_t bt_characteristic_callback(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1907 STATIC const mp_arg_t allowed_args[] = {
1908 { MP_QSTR_trigger, MP_ARG_REQUIRED | MP_ARG_OBJ, },
1909 { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
1910 { MP_QSTR_arg, MP_ARG_OBJ, {.u_obj = mp_const_none} },
1911 };
1912
1913 // parse arguments
1914 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1915 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1916 bt_gatts_char_obj_t *self = pos_args[0];
1917
1918 // enable the callback
1919 if (args[0].u_obj != mp_const_none && args[1].u_obj != mp_const_none) {
1920 self->trigger = mp_obj_get_int(args[0].u_obj);
1921 self->handler = args[1].u_obj;
1922 if (args[2].u_obj == mp_const_none) {
1923 self->handler_arg = self;
1924 } else {
1925 self->handler_arg = args[2].u_obj;
1926 }
1927 } else {
1928 self->trigger = 0;
1929 mp_irq_remove(self);
1930 INTERRUPT_OBJ_CLEAN(self);
1931 }
1932
1933 mp_irq_add(self, args[1].u_obj);
1934
1935 return mp_const_none;
1936}
1937STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_characteristic_callback_obj, 1, bt_characteristic_callback);
1938
1939STATIC mp_obj_t bt_characteristic_events(mp_obj_t self_in) {
1940 bt_gatts_char_obj_t *self = self_in;
1941
1942 int32_t events = self->events;
1943 self->events = 0;
1944 return mp_obj_new_int(events);
1945}
1946STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_characteristic_events_obj, bt_characteristic_events);
1947
1948STATIC mp_obj_t bt_characteristic_config(mp_obj_t self_in) {
1949 bt_gatts_char_obj_t *self = self_in;
1950 return mp_obj_new_int(self->config);
1951}
1952STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_characteristic_config_obj, bt_characteristic_config);
1953
1954STATIC const mp_map_elem_t bt_gatts_char_locals_dict_table[] = {
1955 // instance methods
1956 { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&bt_characteristic_value_obj },
1957 { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&bt_characteristic_callback_obj },
1958 { MP_OBJ_NEW_QSTR(MP_QSTR_events), (mp_obj_t)&bt_characteristic_events_obj },
1959 { MP_OBJ_NEW_QSTR(MP_QSTR_config), (mp_obj_t)&bt_characteristic_config_obj },
1960};
1961STATIC MP_DEFINE_CONST_DICT(bt_gatts_char_locals_dict, bt_gatts_char_locals_dict_table);
1962
1963static const mp_obj_type_t mod_bt_gatts_char_type = {
1964 { &mp_type_type },
1965 .name = MP_QSTR_GATTSCharacteristic,
1966 .locals_dict = (mp_obj_t)&bt_gatts_char_locals_dict,
1967};
1968
1969STATIC mp_obj_t bt_gatts_disconnect_client(mp_obj_t self_in) {
1970 if (bt_obj.gatts_conn_id >= 0) {
1971 esp_ble_gatts_close(bt_obj.gatts_if, bt_obj.gatts_conn_id);
1972 esp_ble_gap_disconnect((void *)bt_obj.client_bda);
1973 bt_obj.gatts_conn_id = -1;
1974 }
1975 return mp_const_none;
1976}
1977STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_gatts_disconnect_client_obj, bt_gatts_disconnect_client);
1978
1979STATIC mp_obj_t bt_tx_power(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
1980
1981 STATIC const mp_arg_t allowed_args[] = {
1982 { MP_QSTR_type, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = mp_const_none} },
1983 { MP_QSTR_level, MP_ARG_INT, {.u_obj = mp_const_none} }
1984 };
1985
1986 // parse arguments
1987 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
1988 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
1989
1990 mp_int_t type = args[0].u_int;
1991
1992 // Do not accept "Connection Handlers 1-8", we do not support different connections in parallel
1993 if(type == ESP_BLE_PWR_TYPE_CONN_HDL0 ||
1994 (type > ESP_BLE_PWR_TYPE_CONN_HDL8 && type < ESP_BLE_PWR_TYPE_NUM)) {
1995
1996 // If "level" is not specified, return with the TX Power marked in "type" parameter
1997 if(args[1].u_obj == mp_const_none)
1998 {
1999 esp_power_level_t ret = esp_ble_tx_power_get(type);
2000 if(ret < 0) {
2001 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "TX Power level could not be get, error code: %d", ret));
2002 // Just for the compiler
2003 return mp_const_none;
2004 }
2005 else {
2006 return mp_obj_new_int(tx_pwr_level_to_dbm[ret]);
2007 }
2008 }
2009 else {
2010
2011 mp_int_t level = args[1].u_int;
2012
2013 if(level >= (sizeof(tx_pwr_level_to_dbm)/sizeof(tx_pwr_level_to_dbm[0]))) {
2014 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid value as \"level\", must be between 0-7: %d", type));
2015 }
2016
2017 esp_power_level_t ret = esp_ble_tx_power_set(type, level);
2018
2019 if(ret != ESP_OK) {
2020 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "TX Power level could not be set, error code: %d", ret));
2021 // Just for the compiler
2022 return mp_const_none;
2023 }
2024 else {
2025 return mp_const_none;
2026 }
2027 }
2028 }
2029 else {
2030 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid value as \"type\": %d", type));
2031 // Just for the compiler
2032 return mp_const_none;
2033 }
2034}
2035STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_tx_power_obj, 2, bt_tx_power);
2036
2037STATIC mp_obj_t bt_conn_get_mtu(mp_obj_t self_in) {
2038
2039 bt_connection_obj_t * self = (bt_connection_obj_t *)self_in;
2040
2041 if(self->conn_id >= 0)
2042 {
2043 return mp_obj_new_int(self->mtu);
2044 }
2045 return mp_const_none;
2046}
2047STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_conn_get_mtu_obj, bt_conn_get_mtu);
2048
2049STATIC mp_obj_t bt_gatts_get_mtu(mp_obj_t self_in) {
2050
2051 bt_obj_t * self = (bt_obj_t *)self_in;
2052 EventBits_t uxBits;
2053
2054 if(self->gatts_conn_id >= 0)
2055 {
2056 MP_THREAD_GIL_EXIT();
2057 uxBits = xEventGroupWaitBits(bt_event_group, MOD_BT_GATTS_MTU_EVT, true, true, 1000/portTICK_PERIOD_MS);
2058 MP_THREAD_GIL_ENTER();
2059 if(uxBits & MOD_BT_GATTS_MTU_EVT)
2060 {
2061 return mp_obj_new_int(self->gatts_mtu);
2062 }
2063 }
2064 return mp_const_none;
2065}
2066STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_gatts_get_mtu_obj, bt_gatts_get_mtu);
2067
2068STATIC const mp_map_elem_t bt_locals_dict_table[] = {
2069 // instance methods
2070 { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&bt_init_obj },
2071 { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&bt_deinit_obj },
2072 { MP_OBJ_NEW_QSTR(MP_QSTR_start_scan), (mp_obj_t)&bt_start_scan_obj },
2073 { MP_OBJ_NEW_QSTR(MP_QSTR_isscanning), (mp_obj_t)&bt_isscanning_obj },
2074 { MP_OBJ_NEW_QSTR(MP_QSTR_stop_scan), (mp_obj_t)&bt_stop_scan_obj },
2075 { MP_OBJ_NEW_QSTR(MP_QSTR_get_adv), (mp_obj_t)&bt_read_scan_obj },
2076 { MP_OBJ_NEW_QSTR(MP_QSTR_get_advertisements), (mp_obj_t)&bt_get_advertisements_obj },
2077 { MP_OBJ_NEW_QSTR(MP_QSTR_resolve_adv_data), (mp_obj_t)&bt_resolve_adv_data_obj },
2078 { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&bt_connect_obj },
2079 { MP_OBJ_NEW_QSTR(MP_QSTR_set_advertisement_params),(mp_obj_t)&bt_set_advertisement_params_obj },
2080 { MP_OBJ_NEW_QSTR(MP_QSTR_set_advertisement), (mp_obj_t)&bt_set_advertisement_obj },
2081 { MP_OBJ_NEW_QSTR(MP_QSTR_set_advertisement_raw), (mp_obj_t)&bt_set_advertisement_raw_obj },
2082 { MP_OBJ_NEW_QSTR(MP_QSTR_advertise), (mp_obj_t)&bt_advertise_obj },
2083 { MP_OBJ_NEW_QSTR(MP_QSTR_service), (mp_obj_t)&bt_service_obj },
2084 { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&bt_callback_obj },
2085 { MP_OBJ_NEW_QSTR(MP_QSTR_events), (mp_obj_t)&bt_events_obj },
2086 { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect_client), (mp_obj_t)&bt_gatts_disconnect_client_obj },
2087 { MP_OBJ_NEW_QSTR(MP_QSTR_modem_sleep), (mp_obj_t)&bt_modem_sleep_obj },
2088 { MP_OBJ_NEW_QSTR(MP_QSTR_tx_power), (mp_obj_t)&bt_tx_power_obj },
2089 { MP_OBJ_NEW_QSTR(MP_QSTR_gatts_mtu), (mp_obj_t)&bt_gatts_get_mtu_obj },
2090 { MP_OBJ_NEW_QSTR(MP_QSTR_nvram_erase), (mp_obj_t)&bt_nvram_erase_obj },
2091
2092
2093 // exceptions
2094 { MP_OBJ_NEW_QSTR(MP_QSTR_timeout), (mp_obj_t)&mp_type_TimeoutError },
2095
2096 // constants
2097 { MP_OBJ_NEW_QSTR(MP_QSTR_CONN_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_CONN_ADV) },
2098 { MP_OBJ_NEW_QSTR(MP_QSTR_CONN_DIR_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_CONN_DIR_ADV) },
2099 { MP_OBJ_NEW_QSTR(MP_QSTR_DISC_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_DISC_ADV) },
2100 { MP_OBJ_NEW_QSTR(MP_QSTR_NON_CONN_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_NON_CONN_ADV) },
2101 { MP_OBJ_NEW_QSTR(MP_QSTR_SCAN_RSP), MP_OBJ_NEW_SMALL_INT(ESP_BLE_EVT_SCAN_RSP) },
2102
2103 { MP_OBJ_NEW_QSTR(MP_QSTR_PUBLIC_ADDR), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_PUBLIC) },
2104 { MP_OBJ_NEW_QSTR(MP_QSTR_RANDOM_ADDR), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RANDOM) },
2105 { MP_OBJ_NEW_QSTR(MP_QSTR_PUBLIC_RPA_ADDR), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RPA_PUBLIC) },
2106 { MP_OBJ_NEW_QSTR(MP_QSTR_RANDOM_RPA_ADDR), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RPA_RANDOM) },
2107
2108 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_FLAG), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_FLAG) },
2109 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_16SRV_PART), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_16SRV_PART) },
2110 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_T16SRV_CMPL), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_16SRV_CMPL) },
2111 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_32SRV_PART), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_32SRV_PART) },
2112 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_32SRV_CMPL), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_32SRV_CMPL) },
2113 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_128SRV_PART), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_128SRV_PART) },
2114 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_128SRV_CMPL), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_128SRV_CMPL) },
2115 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_NAME_SHORT), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_NAME_SHORT) },
2116 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_NAME_CMPL), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_NAME_CMPL) },
2117 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TX_PWR), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_TX_PWR) },
2118 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_DEV_CLASS), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_DEV_CLASS) },
2119 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_SERVICE_DATA), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_SERVICE_DATA) },
2120 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_APPEARANCE), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_APPEARANCE) },
2121 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_ADV_INT), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_ADV_INT) },
2122 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_32SERVICE_DATA), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_32SERVICE_DATA) },
2123 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_128SERVICE_DATA), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_TYPE_128SERVICE_DATA) },
2124 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_MANUFACTURER_DATA), MP_OBJ_NEW_SMALL_INT(ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE) },
2125
2126 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_BROADCAST), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_BROADCAST) },
2127 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_READ), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_READ) },
2128 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_WRITE_NR), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_WRITE_NR) },
2129 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_WRITE), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_WRITE) },
2130 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_NOTIFY), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_NOTIFY) },
2131 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_INDICATE), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_INDICATE) },
2132 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_AUTH), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_AUTH) },
2133 { MP_OBJ_NEW_QSTR(MP_QSTR_PROP_EXT_PROP), MP_OBJ_NEW_SMALL_INT(ESP_GATT_CHAR_PROP_BIT_EXT_PROP) },
2134
2135 // Defined at https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
2136 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_CONFIG_NOTIFY), MP_OBJ_NEW_SMALL_INT(1 << 0) },
2137 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_CONFIG_INDICATE), MP_OBJ_NEW_SMALL_INT(1 << 1) },
2138
2139 { MP_OBJ_NEW_QSTR(MP_QSTR_NEW_ADV_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTC_ADV_EVT) },
2140 { MP_OBJ_NEW_QSTR(MP_QSTR_CLIENT_CONNECTED), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_CONN_EVT) },
2141 { MP_OBJ_NEW_QSTR(MP_QSTR_CLIENT_DISCONNECTED), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_DISCONN_EVT) },
2142 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_READ_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_READ_EVT) },
2143 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_WRITE_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_WRITE_EVT) },
2144 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_NOTIFY_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTC_NOTIFY_EVT) },
2145 { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_SUBSCRIBE_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTS_SUBSCRIBE_EVT) },
2146 // { MP_OBJ_NEW_QSTR(MP_QSTR_CHAR_INDICATE_EVENT), MP_OBJ_NEW_SMALL_INT(MOD_BT_GATTC_INDICATE_EVT) },
2147
2148 { MP_OBJ_NEW_QSTR(MP_QSTR_INT_ANT), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_INTERNAL) },
2149 { MP_OBJ_NEW_QSTR(MP_QSTR_EXT_ANT), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_EXTERNAL) },
2150
2151 // Constants for bt_set_advertisement_params API
2152 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_IND), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_IND) },
2153 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_DIRECT_IND_HIGH), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_DIRECT_IND_HIGH) },
2154 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_SCAN_IND), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_SCAN_IND) },
2155 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_NONCONN_IND), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_NONCONN_IND) },
2156 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_TYPE_DIRECT_IND_LOW), MP_OBJ_NEW_SMALL_INT(ADV_TYPE_DIRECT_IND_LOW) },
2157 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_BLE_ADDR_TYPE_PUBLIC), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_PUBLIC) },
2158 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_BLE_ADDR_TYPE_RANDOM), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RANDOM) },
2159 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_BLE_ADDR_TYPE_RPA_PUBLIC), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RPA_PUBLIC) },
2160 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_BLE_ADDR_TYPE_RPA_RANDOM), MP_OBJ_NEW_SMALL_INT(BLE_ADDR_TYPE_RPA_RANDOM) },
2161 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_CHNL_37), MP_OBJ_NEW_SMALL_INT(ADV_CHNL_37) },
2162 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_CHNL_38), MP_OBJ_NEW_SMALL_INT(ADV_CHNL_38) },
2163 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_CHNL_39), MP_OBJ_NEW_SMALL_INT(ADV_CHNL_39) },
2164 { MP_OBJ_NEW_QSTR(MP_QSTR_ADV_CHNL_ALL), MP_OBJ_NEW_SMALL_INT(ADV_CHNL_ALL) },
2165 { 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) },
2166 { 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) },
2167 { 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) },
2168 { 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) },
2169
2170 // Constants for setting TX Power
2171 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_CONN), MP_OBJ_NEW_SMALL_INT(ESP_BLE_PWR_TYPE_CONN_HDL0) },
2172 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_ADV), MP_OBJ_NEW_SMALL_INT(ESP_BLE_PWR_TYPE_ADV) },
2173 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_SCAN), MP_OBJ_NEW_SMALL_INT(ESP_BLE_PWR_TYPE_SCAN) },
2174 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_DEFAULT), MP_OBJ_NEW_SMALL_INT(ESP_BLE_PWR_TYPE_DEFAULT) },
2175 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_N12), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N12) },
2176 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_N9), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N9) },
2177 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_N6), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N6) },
2178 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_N3), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N3) },
2179 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_0), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_N0) },
2180 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_P3), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_P3) },
2181 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_P6), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_P6) },
2182 { MP_OBJ_NEW_QSTR(MP_QSTR_TX_PWR_P9), MP_OBJ_NEW_SMALL_INT(ESP_PWR_LVL_P9) },
2183
2184};
2185STATIC MP_DEFINE_CONST_DICT(bt_locals_dict, bt_locals_dict_table);
2186
2187const mod_network_nic_type_t mod_network_nic_type_bt = {
2188 .base = {
2189 { &mp_type_type },
2190 .name = MP_QSTR_Bluetooth,
2191 .make_new = bt_make_new,
2192 .locals_dict = (mp_obj_t)&bt_locals_dict,
2193 },
2194};
2195
2196STATIC mp_obj_t bt_conn_isconnected(mp_obj_t self_in) {
2197 bt_connection_obj_t *self = self_in;
2198
2199 if (self->conn_id >= 0) {
2200 return mp_const_true;
2201 }
2202 return mp_const_false;
2203}
2204STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_conn_isconnected_obj, bt_conn_isconnected);
2205
2206STATIC mp_obj_t bt_conn_disconnect(mp_obj_t self_in) {
2207 bt_connection_obj_t *self = self_in;
2208
2209 if (self->conn_id >= 0) {
2210 esp_ble_gattc_close(bt_obj.gattc_if, self->conn_id);
2211 esp_ble_gap_disconnect(self->srv_bda);
2212 /* Only reset Conn Id if it is a normal disconnect not module de-init to mark conn obj to be restored */
2213 if(!mod_bt_allow_resume_deinit)
2214 {
2215 self->conn_id = -1;
2216 }
2217 }
2218 return mp_const_none;
2219}
2220STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_conn_disconnect_obj, bt_conn_disconnect);
2221
2222static mp_obj_t modbt_conn_disconnect(mp_obj_t self_in)
2223{
2224 return bt_conn_disconnect(self_in);
2225}
2226
2227STATIC mp_obj_t bt_conn_services (mp_obj_t self_in) {
2228 bt_connection_obj_t *self = self_in;
2229 bt_event_result_t bt_event;
2230
2231 if (self->conn_id >= 0) {
2232 xQueueReset(xScanQueue);
2233 bt_obj.busy = true;
2234 mp_obj_list_init(&self->srv_list, 0);
2235
2236 if (ESP_OK != esp_ble_gattc_search_service(bt_obj.gattc_if, self->conn_id, NULL)) {
2237 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2238 }
2239
2240 while (bt_obj.busy) {
2241 while (xQueueReceive(xScanQueue, &bt_event, (TickType_t)0)) {
2242 bt_srv_obj_t *srv = m_new_obj(bt_srv_obj_t);
2243 srv->base.type = (mp_obj_t)&mod_bt_service_type;
2244 srv->connection = self;
2245 memcpy(&srv->srv_id, &bt_event.service.srv_id, sizeof(esp_gatt_id_t));
2246 srv->start_handle = bt_event.service.start_handle;
2247 srv->end_handle = bt_event.service.end_handle;
2248 mp_obj_list_append(&self->srv_list, srv);
2249 }
2250 }
2251 return &self->srv_list;
2252 } else {
2253 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2254 }
2255}
2256STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_conn_services_obj, bt_conn_services);
2257
2258STATIC const mp_map_elem_t bt_connection_locals_dict_table[] = {
2259 // instance methods
2260 { MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&bt_conn_isconnected_obj },
2261 { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&bt_conn_disconnect_obj },
2262 { MP_OBJ_NEW_QSTR(MP_QSTR_services), (mp_obj_t)&bt_conn_services_obj },
2263 { MP_OBJ_NEW_QSTR(MP_QSTR_get_mtu), (mp_obj_t)&bt_conn_get_mtu_obj },
2264
2265};
2266STATIC MP_DEFINE_CONST_DICT(bt_connection_locals_dict, bt_connection_locals_dict_table);
2267
2268static const mp_obj_type_t mod_bt_connection_type = {
2269 { &mp_type_type },
2270 .name = MP_QSTR_GATTCConnection,
2271 .locals_dict = (mp_obj_t)&bt_connection_locals_dict,
2272};
2273
2274STATIC mp_obj_t bt_srv_isprimary(mp_obj_t self_in) {
2275 return mp_const_true;
2276}
2277STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_srv_isprimary_obj, bt_srv_isprimary);
2278
2279STATIC mp_obj_t bt_srv_uuid(mp_obj_t self_in) {
2280 bt_srv_obj_t *self = self_in;
2281
2282 if (self->srv_id.uuid.len == ESP_UUID_LEN_16) {
2283 return mp_obj_new_int(self->srv_id.uuid.uuid.uuid16);
2284 } else if (self->srv_id.uuid.len == ESP_UUID_LEN_32) {
2285 return mp_obj_new_int(self->srv_id.uuid.uuid.uuid32);
2286 } else {
2287 return mp_obj_new_bytes(self->srv_id.uuid.uuid.uuid128, ESP_UUID_LEN_128);
2288 }
2289}
2290STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_srv_uuid_obj, bt_srv_uuid);
2291
2292STATIC mp_obj_t bt_srv_instance(mp_obj_t self_in) {
2293 bt_srv_obj_t *self = self_in;
2294 return mp_obj_new_int(self->srv_id.inst_id);
2295}
2296STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_srv_instance_obj, bt_srv_instance);
2297
2298STATIC mp_obj_t bt_srv_characteristics(mp_obj_t self_in) {
2299 bt_srv_obj_t *self = self_in;
2300
2301 if (self->connection->conn_id >= 0) {
2302 mp_obj_list_init(&self->char_list, 0);
2303
2304
2305 uint16_t attr_count = 0;
2306 esp_ble_gattc_get_attr_count(bt_obj.gattc_if,
2307 self->connection->conn_id,
2308 ESP_GATT_DB_CHARACTERISTIC,
2309 self->start_handle,
2310 self->end_handle,
2311 0,
2312 &attr_count);
2313
2314 if (attr_count > 0) {
2315 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);
2316 if (!char_elems) {
2317 mp_raise_OSError(MP_ENOMEM);
2318 } else {
2319 esp_ble_gattc_get_all_char(bt_obj.gattc_if,
2320 self->connection->conn_id,
2321 self->start_handle,
2322 self->end_handle,
2323 char_elems,
2324 &attr_count,
2325 0);
2326 if (attr_count > 0) {
2327 for (int i = 0; i < attr_count; ++i) {
2328 bt_char_obj_t *chr = m_new_obj(bt_char_obj_t);
2329 chr->base.type = (mp_obj_t)&mod_bt_characteristic_type;
2330 chr->service = self;
2331 memcpy(&chr->characteristic, &char_elems[i], sizeof(esp_gattc_char_elem_t));
2332 chr->value[0] = 0;
2333 chr->value_len = 1;
2334 mp_obj_list_append(&self->char_list, chr);
2335 }
2336 }
2337 free(char_elems);
2338 }
2339 }
2340 return &self->char_list;
2341 } else {
2342 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2343 }
2344}
2345STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_srv_characteristics_obj, bt_srv_characteristics);
2346
2347STATIC const mp_map_elem_t bt_service_locals_dict_table[] = {
2348 // instance methods
2349 { MP_OBJ_NEW_QSTR(MP_QSTR_isprimary), (mp_obj_t)&bt_srv_isprimary_obj },
2350 { MP_OBJ_NEW_QSTR(MP_QSTR_uuid), (mp_obj_t)&bt_srv_uuid_obj },
2351 { MP_OBJ_NEW_QSTR(MP_QSTR_instance), (mp_obj_t)&bt_srv_instance_obj },
2352 { MP_OBJ_NEW_QSTR(MP_QSTR_characteristics), (mp_obj_t)&bt_srv_characteristics_obj },
2353};
2354STATIC MP_DEFINE_CONST_DICT(bt_service_locals_dict, bt_service_locals_dict_table);
2355
2356static const mp_obj_type_t mod_bt_service_type = {
2357 { &mp_type_type },
2358 .name = MP_QSTR_GATTCService,
2359 .locals_dict = (mp_obj_t)&bt_service_locals_dict,
2360};
2361
2362STATIC mp_obj_t bt_char_uuid(mp_obj_t self_in) {
2363 bt_char_obj_t *self = self_in;
2364
2365 if (self->characteristic.uuid.len == ESP_UUID_LEN_16) {
2366 return mp_obj_new_int(self->characteristic.uuid.uuid.uuid16);
2367 } else if (self->characteristic.uuid.len == ESP_UUID_LEN_32) {
2368 return mp_obj_new_int(self->characteristic.uuid.uuid.uuid32);
2369 } else {
2370 return mp_obj_new_bytes(self->characteristic.uuid.uuid.uuid128, ESP_UUID_LEN_128);
2371 }
2372}
2373STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_uuid_obj, bt_char_uuid);
2374
2375STATIC mp_obj_t bt_char_instance(mp_obj_t self_in) {
2376 return mp_obj_new_int(0);
2377}
2378STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_instance_obj, bt_char_instance);
2379
2380STATIC mp_obj_t bt_char_properties(mp_obj_t self_in) {
2381 bt_char_obj_t *self = self_in;
2382 return mp_obj_new_int(self->characteristic.properties);
2383}
2384STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_properties_obj, bt_char_properties);
2385
2386STATIC mp_obj_t bt_char_read(mp_obj_t self_in) {
2387 bt_char_obj_t *self = self_in;
2388 bt_event_result_t bt_event;
2389
2390 if (self->service->connection->conn_id >= 0) {
2391 xQueueReset(xScanQueue);
2392 bt_obj.busy = true;
2393
2394 if (ESP_OK != esp_ble_gattc_read_char (bt_obj.gattc_if, self->service->connection->conn_id,
2395 self->characteristic.char_handle,
2396 ESP_GATT_AUTH_REQ_NONE)) {
2397 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2398 }
2399 while (bt_obj.busy) {
2400 mp_hal_delay_ms(5);
2401 }
2402 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)5)) {
2403 memcpy(self->value, bt_event.read.value, bt_event.read.value_len);
2404 self->value_len = bt_event.read.value_len;
2405 return mp_obj_new_bytes(bt_event.read.value, bt_event.read.value_len);
2406 } else {
2407 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2408 }
2409 } else {
2410 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2411 }
2412}
2413STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_read_obj, bt_char_read);
2414
2415STATIC mp_obj_t bt_char_read_descriptor(mp_obj_t self_in, mp_obj_t uuid) {
2416 bt_char_obj_t *self = self_in;
2417 bt_event_result_t bt_event;
2418
2419 uint16_t descr_uuid_value = mp_obj_get_int(uuid);
2420
2421 if (self->service->connection->conn_id >= 0) {
2422 xQueueReset(xScanQueue);
2423
2424 esp_gattc_descr_elem_t format_descriptor;
2425 uint16_t count = 1;
2426 esp_bt_uuid_t descr_uuid = {.len = ESP_UUID_LEN_16, .uuid.uuid16 = descr_uuid_value};
2427 esp_gatt_status_t ret_val = esp_ble_gattc_get_descr_by_uuid(bt_obj.gattc_if,
2428 self->service->connection->conn_id,
2429 self->service->start_handle,
2430 self->service->end_handle,
2431 self->characteristic.uuid,
2432 descr_uuid,
2433 &format_descriptor,
2434 &count);
2435 if(ret_val == ESP_OK && count == 1) {
2436 bt_obj.busy = true;
2437
2438 if (ESP_OK != esp_ble_gattc_read_char_descr(bt_obj.gattc_if,
2439 self->service->connection->conn_id,
2440 format_descriptor.handle,
2441 ESP_GATT_AUTH_REQ_NONE)) {
2442 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2443 }
2444
2445 while (bt_obj.busy) {
2446 mp_hal_delay_ms(5);
2447 }
2448
2449 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)5)) {
2450 return mp_obj_new_bytes(bt_event.read.value, bt_event.read.value_len);
2451 } else {
2452 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2453 }
2454 } else {
2455 return mp_const_none; // Descriptor not found, no read
2456 }
2457 } else {
2458 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2459 }
2460}
2461STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_char_read_descriptor_obj, bt_char_read_descriptor);
2462
2463STATIC mp_obj_t bt_char_write(mp_obj_t self_in, mp_obj_t value) {
2464 bt_char_obj_t *self = self_in;
2465 bt_event_result_t bt_event;
2466
2467 mp_buffer_info_t bufinfo;
2468 mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ);
2469
2470 if (self->service->connection->conn_id >= 0) {
2471 xQueueReset(xScanQueue);
2472 bt_obj.busy = true;
2473
2474 if (ESP_OK != esp_ble_gattc_write_char (bt_obj.gattc_if, self->service->connection->conn_id,
2475 self->characteristic.char_handle,
2476 bufinfo.len,
2477 bufinfo.buf,
2478 ESP_GATT_WRITE_TYPE_RSP,
2479 ESP_GATT_AUTH_REQ_NONE)) {
2480 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2481 }
2482
2483 while (bt_obj.busy) {
2484 mp_hal_delay_ms(5);
2485 }
2486 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)5)) {
2487 if (bt_event.write.status != ESP_GATT_OK) {
2488 goto error;
2489 }
2490 } else {
2491 goto error;
2492 }
2493 } else {
2494 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2495 }
2496 return mp_const_none;
2497
2498error:
2499 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2500}
2501STATIC MP_DEFINE_CONST_FUN_OBJ_2(bt_char_write_obj, bt_char_write);
2502
2503/// \method callback(trigger, handler, arg)
2504STATIC mp_obj_t bt_char_callback(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
2505 STATIC const mp_arg_t allowed_args[] = {
2506 { MP_QSTR_trigger, MP_ARG_REQUIRED | MP_ARG_OBJ, },
2507 { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
2508 { MP_QSTR_arg, MP_ARG_OBJ, {.u_obj = mp_const_none} },
2509 };
2510
2511 // parse arguments
2512 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
2513 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
2514 bt_char_obj_t *self = pos_args[0];
2515 bt_event_result_t bt_event;
2516
2517 // enable the callback
2518 if (args[0].u_obj != mp_const_none && args[1].u_obj != mp_const_none) {
2519 uint32_t trigger = mp_obj_get_int(args[0].u_obj);
2520 if (trigger != MOD_BT_GATTC_NOTIFY_EVT) {
2521 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid trigger"));
2522 }
2523 self->trigger = trigger;
2524 self->handler = args[1].u_obj;
2525 if (args[2].u_obj == mp_const_none) {
2526 self->handler_arg = self;
2527 } else {
2528 self->handler_arg = args[2].u_obj;
2529 }
2530
2531 if (self->service->connection->conn_id >= 0) {
2532 if (ESP_OK != esp_ble_gattc_register_for_notify (self->service->connection->gatt_if,
2533 self->service->connection->srv_bda,
2534 self->characteristic.char_handle)) {
2535 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2536 }
2537
2538 if (xQueueReceive(xScanQueue, &bt_event, (TickType_t)(2500 / portTICK_RATE_MS))) {
2539 if (bt_event.register_for_notify.status != ESP_GATT_OK) {
2540 goto error;
2541 }
2542 } else {
2543 goto error;
2544 }
2545
2546 uint16_t attr_count = 0;
2547 uint16_t notify_en = 1;
2548 esp_ble_gattc_get_attr_count(bt_obj.gattc_if,
2549 self->service->connection->conn_id,
2550 ESP_GATT_DB_DESCRIPTOR,
2551 self->service->start_handle,
2552 self->service->end_handle,
2553 self->characteristic.char_handle,
2554 &attr_count);
2555 if (attr_count > 0) {
2556 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);
2557 if (!descr_elems) {
2558 mp_raise_OSError(MP_ENOMEM);
2559 } else {
2560 esp_ble_gattc_get_all_descr(bt_obj.gattc_if,
2561 self->service->connection->conn_id,
2562 self->characteristic.char_handle,
2563 descr_elems,
2564 &attr_count,
2565 0);
2566 for (int i = 0; i < attr_count; ++i) {
2567 if (descr_elems[i].uuid.len == ESP_UUID_LEN_16 && descr_elems[i].uuid.uuid.uuid16 == ESP_GATT_UUID_CHAR_CLIENT_CONFIG) {
2568 esp_ble_gattc_write_char_descr (bt_obj.gattc_if,
2569 self->service->connection->conn_id,
2570 descr_elems[i].handle,
2571 sizeof(notify_en),
2572 (uint8_t *)¬ify_en,
2573 ESP_GATT_WRITE_TYPE_RSP,
2574 ESP_GATT_AUTH_REQ_NONE);
2575
2576 break;
2577 }
2578 }
2579 free(descr_elems);
2580 }
2581 }
2582 } else {
2583 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "connection already closed"));
2584 }
2585 } else {
2586 self->trigger = 0;
2587 mp_irq_remove(self);
2588 INTERRUPT_OBJ_CLEAN(self);
2589 }
2590
2591 mp_irq_add(self, args[1].u_obj);
2592
2593 return mp_const_none;
2594
2595error:
2596 nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
2597}
2598STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bt_char_callback_obj, 1, bt_char_callback);
2599
2600STATIC mp_obj_t bt_char_value(mp_obj_t self_in) {
2601 bt_char_obj_t *self = self_in;
2602 return mp_obj_new_bytes(self->value, self->value_len);
2603}
2604STATIC MP_DEFINE_CONST_FUN_OBJ_1(bt_char_value_obj, bt_char_value);
2605
2606STATIC const mp_map_elem_t bt_characteristic_locals_dict_table[] = {
2607 // instance methods
2608 { MP_OBJ_NEW_QSTR(MP_QSTR_uuid), (mp_obj_t)&bt_char_uuid_obj },
2609 { MP_OBJ_NEW_QSTR(MP_QSTR_instance), (mp_obj_t)&bt_char_instance_obj },
2610 { MP_OBJ_NEW_QSTR(MP_QSTR_properties), (mp_obj_t)&bt_char_properties_obj },
2611 { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&bt_char_read_obj },
2612 { MP_OBJ_NEW_QSTR(MP_QSTR_read_descriptor), (mp_obj_t)&bt_char_read_descriptor_obj },
2613 { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&bt_char_write_obj },
2614 { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&bt_char_callback_obj },
2615 { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&bt_char_value_obj },
2616 // { MP_OBJ_NEW_QSTR(MP_QSTR_descriptors), (mp_obj_t)&bt_char_descriptors_obj },
2617};
2618STATIC MP_DEFINE_CONST_DICT(bt_characteristic_locals_dict, bt_characteristic_locals_dict_table);
2619
2620static const mp_obj_type_t mod_bt_characteristic_type = {
2621 { &mp_type_type },
2622 .name = MP_QSTR_GATTCCharacteristic,
2623 .locals_dict = (mp_obj_t)&bt_characteristic_locals_dict,
2624};
2625
2626// static const mp_obj_type_t mod_bt_descriptor_type = {
2627 // { &mp_type_type },
2628 // .name = MP_QSTR_BT_DESCRIPTOR,
2629 // .locals_dict = (mp_obj_t)&bt_descriptor_locals_dict,
2630// };