Files
M5Stack_MicroPython/MicroPython_BUILD/components/micropython/esp32/bluetooth_le.c
T
sakabin 070e06db00 update micropython
add m5stack.py
add m5ui.py
2018-12-04 14:06:15 +08:00

1205 lines
42 KiB
C

/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// Free RTOS
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
// Generic
#include <string.h>
#include <unistd.h>
// MicroPython
#include "py/runtime.h"
#include "py/obj.h"
#include "py/objstr.h"
#include "py/runtime0.h"
// IDF
#include "esp_bt.h"
#include "api/esp_bt_main.h"
#include "api/esp_gap_ble_api.h"
#include "api/esp_gatts_api.h"
#include "api/esp_gattc_api.h"
//extern bool bluetooth_enabled;
static bool bluetooth_enabled = false;
#define EVENT_DEBUG
#ifdef EVENT_DEBUG
# define EVENT_DEBUG_GATTC
# define EVENT_DEBUG_GATTS
# define EVENT_DEBUG_GAP
#endif
#define MSEC_0_625_TO_UNIT(time) ((time) * 1000 / (625))
#define MALLOC(x) pvPortMalloc(x)
#define FREE(x) vPortFree(x)
#define UUID_LEN 16
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define BAD_UUID(name) mp_raise_ValueError(name "must be bytearray(" TOSTRING(UUID_LEN) ")");
#define BAD_PEER(name) mp_raise_ValueError(name "must be bytearray(" TOSTRING(ESP_BD_ADDR_LEN) ")");
#define MP_OBJ_IS_BYTEARRAY_OR_BYTES(O) (MP_OBJ_IS_TYPE(O, &mp_type_bytes) || MP_OBJ_IS_TYPE(O, &mp_type_bytearray))
#define NETWORK_BLUETOOTH_DEBUG_PRINTF(args...) printf(args)
#define CALLBACK_QUEUE_SIZE 10
typedef enum {
// GATTS
BTLE_GATTS_CONNECT,
BTLE_GATTS_DISCONNECT,
BTLE_GATTS_CREATE,
BTLE_GATTS_START,
BTLE_GATTS_STOP,
BTLE_GATTS_ADD_CHAR, // Add char
BTLE_GATTS_ADD_CHAR_DESCR, // Add descriptor
// GAP / GATTC events
BTLE_GATTC_SCAN_RES,
BTLE_GATTC_SCAN_CMPL, // Found GATT servers
BTLE_GATTC_SEARCH_RES, // Found GATTS services
BTLE_GATTC_GET_CHAR,
BTLE_GATTC_GET_DESCR,
BTLE_GATTC_OPEN,
BTLE_GATTC_CLOSE,
// characteristic events
BTLE_READ,
BTLE_WRITE,
BTLE_NOTIFY,
} btle_event_t;
typedef struct {
btle_event_t event;
union {
struct {
uint16_t handle;
esp_gatt_srvc_id_t service_id;
} gatts_create;
/*
struct {
uint16_t service_handle;
} gatts_start_stop;
struct {
uint16_t service_handle;
uint16_t handle;
esp_bt_uuid_t uuid;
} gatts_add_char_descr;
struct {
uint16_t conn_id;
esp_bd_addr_t bda;
} gatts_connect_disconnect;
struct {
esp_bd_addr_t bda;
uint8_t* adv_data; // Need to free this!
uint8_t adv_data_len;
int rssi;
} gattc_scan_res;
struct {
uint16_t conn_id;
esp_gatt_id_t service_id;
} gattc_search_res;
struct {
uint16_t conn_id;
esp_gatt_srvc_id_t service_id;
esp_gatt_id_t char_id;
esp_gatt_char_prop_t props;
} gattc_get_char;
struct {
uint16_t conn_id;
esp_gatt_srvc_id_t service_id;
esp_gatt_id_t char_id;
esp_gatt_id_t descr_id;
} gattc_get_descr;
struct {
uint16_t conn_id;
uint16_t mtu;
esp_bd_addr_t bda;
} gattc_open_close;
struct {
uint16_t conn_id;
uint16_t handle;
uint32_t trans_id;
bool need_rsp;
} read;
struct {
uint16_t conn_id;
uint16_t handle;
uint32_t trans_id;
bool need_rsp;
// Following fields _must_
// come after the first four above,
// which _must_ match the read struct
uint8_t* value; // Need to free this!
size_t value_len;
} write;
struct {
uint16_t conn_id;
esp_bd_addr_t remote_bda;
uint16_t handle;
bool need_rsp;
uint8_t* value; // Need to free this!
size_t value_len;
} notify;
*/
};
} callback_data_t;
typedef struct {
uint8_t* value; // Need to free this!
size_t value_len;
} read_write_data_t;
const mp_obj_type_t btle_type;
STATIC SemaphoreHandle_t item_mut;
STATIC QueueHandle_t callback_q = NULL;
STATIC QueueHandle_t read_write_q = NULL;
STATIC void dumpBuf(const uint8_t *buf, size_t len) {
while (len--) {
printf("%02X ", *buf++);
}
}
typedef struct {
mp_obj_base_t base;
enum {
BTLE_STATE_DEINIT,
BTLE_STATE_INIT
} state;
bool advertising;
bool scanning;
bool gatts_connected;
uint16_t conn_id;
esp_gatt_if_t gatts_interface;
esp_gatt_if_t gattc_interface;
esp_ble_adv_params_t adv_params;
esp_ble_adv_data_t adv_data;
mp_obj_t services; // GATTS, implemented as a list
mp_obj_t connections; // GATTC, implemented as a list
mp_obj_t callback;
mp_obj_t callback_userdata;
} btle_obj_t;
// Singleton
STATIC btle_obj_t* btle_singleton = NULL;
STATIC btle_obj_t* btle_get_singleton() {
if (btle_singleton == NULL) {
btle_singleton = m_new_obj(btle_obj_t);
btle_singleton->base.type = &btle_type;
btle_singleton->state = BTLE_STATE_DEINIT;
btle_singleton->advertising = false;
btle_singleton->scanning = false;
btle_singleton->gatts_connected = false;
btle_singleton->conn_id = 0;
btle_singleton->gatts_interface = ESP_GATT_IF_NONE;
btle_singleton->gattc_interface = ESP_GATT_IF_NONE;
btle_singleton->adv_params.adv_int_min = 1280 * 1.6;
btle_singleton->adv_params.adv_int_max = 1280 * 1.6;
btle_singleton->adv_params.adv_type = ADV_TYPE_IND;
btle_singleton->adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
btle_singleton->adv_params.peer_addr_type = BLE_ADDR_TYPE_PUBLIC;
btle_singleton->adv_params.channel_map = ADV_CHNL_ALL;
btle_singleton->adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
btle_singleton->adv_data.set_scan_rsp = false;
btle_singleton->adv_data.include_name = false;
btle_singleton->adv_data.include_txpower = false;
btle_singleton->adv_data.min_interval = 1280 * 1.6;
btle_singleton->adv_data.max_interval = 1280 * 1.6;
btle_singleton->adv_data.appearance = 0;
btle_singleton->adv_data.p_manufacturer_data = NULL;
btle_singleton->adv_data.manufacturer_len = 0;
btle_singleton->adv_data.p_service_data = NULL;
btle_singleton->adv_data.service_data_len = 0;
btle_singleton->adv_data.p_service_uuid = 0;
btle_singleton->adv_data.service_uuid_len = 0;
btle_singleton->adv_data.flag = 0;
btle_singleton->callback = mp_const_none;
btle_singleton->callback_userdata = mp_const_none;
btle_singleton->services = mp_obj_new_list(0, NULL);
btle_singleton->connections = mp_obj_new_list(0, NULL);
memset(btle_singleton->adv_params.peer_addr, 0, sizeof(btle_singleton->adv_params.peer_addr));
}
return btle_singleton;
}
#if CONFIG_GATTS_ENABLE
STATIC void btle_gatts_event_handler(
esp_gatts_cb_event_t event,
esp_gatt_if_t gatts_if,
esp_ble_gatts_cb_param_t *param) {
btle_obj_t* bluetooth = btle_get_singleton();
if (bluetooth->state != BTLE_STATE_INIT) {
return;
}
#ifdef EVENT_DEBUG_GATTS
//gatts_event_dump(event, gatts_if, param);
#endif
}
#endif
#if CONFIG_GATTC_ENABLE
STATIC void btle_gattc_event_handler(
esp_gattc_cb_event_t event,
esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) {
btle_obj_t* bluetooth = btle_get_singleton();
if (bluetooth->state != BTLE_STATE_INIT) {
return;
}
#ifdef EVENT_DEBUG_GATTC
//gattc_event_dump(event, gattc_if, param);
#endif
}
#endif
#ifdef EVENT_DEBUG_GAP
typedef struct {
uint8_t id;
const char * name;
} gatt_status_name_t;
STATIC const gatt_status_name_t gatt_status_names[] = {
{0x00, "OK"},
{0x01, "INVALID_HANDLE"},
{0x02, "READ_NOT_PERMIT"},
{0x03, "WRITE_NOT_PERMIT"},
{0x04, "INVALID_PDU"},
{0x05, "INSUF_AUTHENTICATION"},
{0x06, "REQ_NOT_SUPPORTED"},
{0x07, "INVALID_OFFSET"},
{0x08, "INSUF_AUTHORIZATION"},
{0x09, "PREPARE_Q_FULL"},
{0x0a, "NOT_FOUND"},
{0x0b, "NOT_LONG"},
{0x0c, "INSUF_KEY_SIZE"},
{0x0d, "INVALID_ATTR_LEN"},
{0x0e, "ERR_UNLIKELY"},
{0x0f, "INSUF_ENCRYPTION"},
{0x10, "UNSUPPORT_GRP_TYPE"},
{0x11, "INSUF_RESOURCE"},
{0x80, "NO_RESOURCES"},
{0x81, "INTERNAL_ERROR"},
{0x82, "WRONG_STATE"},
{0x83, "DB_FULL"},
{0x84, "BUSY"},
{0x85, "ERROR"},
{0x86, "CMD_STARTED"},
{0x87, "ILLEGAL_PARAMETER"},
{0x88, "PENDING"},
{0x89, "AUTH_FAIL"},
{0x8a, "MORE"},
{0x8b, "INVALID_CFG"},
{0x8c, "SERVICE_STARTED"},
{0x8d, "ENCRYPED_NO_MITM"},
{0x8e, "NOT_ENCRYPTED"},
{0x8f, "CONGESTED"},
{0x90, "DUP_REG"},
{0x91, "ALREADY_OPEN"},
{0x92, "CANCEL"},
{0xfd, "CCC_CFG_ERR"},
{0xfe, "PRC_IN_PROGRESS"},
{0xff, "OUT_OF_RANGE"},
{0x00, NULL},
};
#define PRINT_STATUS(STATUS) { \
bool found = false; \
NETWORK_BLUETOOTH_DEBUG_PRINTF("status = %02X / ", (STATUS)); \
for(int i = 0; gatt_status_names[i].name != NULL; i++) { \
if (gatt_status_names[i].id == (STATUS)) { \
found = true; \
NETWORK_BLUETOOTH_DEBUG_PRINTF("%s", gatt_status_names[i].name); \
break; \
} \
} \
if (!found) { \
NETWORK_BLUETOOTH_DEBUG_PRINTF("???"); \
} \
}
STATIC void gap_event_dump(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
const char * event_names[] = {
"ADV_DATA_SET_COMPLETE",
"SCAN_RSP_DATA_SET_COMPLETE",
"SCAN_PARAM_SET_COMPLETE",
"SCAN_RESULT",
"ADV_DATA_RAW_SET_COMPLETE",
"SCAN_RSP_DATA_RAW_SET_COMPLETE",
"ADV_START_COMPLETE",
"SCAN_START_COMPLETE",
"AUTH_CMPL",
"KEY",
"SEC_REQ",
"PASSKEY_NOTIF",
"PASSKEY_REQ",
"OOB_REQ",
"LOCAL_IR",
"LOCAL_ER",
"NC_REQ",
"ADV_STOP_COMPLETE",
"SCAN_STOP_COMPLETE",
"SET_STATIC_RAND_ADDR_EVT",
"UPDATE_CONN_PARAMS_EVT",
"SET_PKT_LENGTH_COMPLETE_EVT"
};
NETWORK_BLUETOOTH_DEBUG_PRINTF("network_bluetooth_gap_event_handler(event = %02X / %s", event, event_names[event]);
NETWORK_BLUETOOTH_DEBUG_PRINTF(", param = (");
switch (event) {
case ESP_GAP_BLE_EVT_MAX:
break;
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
case ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT:
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
case ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT:
case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT:
{
PRINT_STATUS(param->adv_data_cmpl.status);
}
break;
case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
{
PRINT_STATUS(param->adv_data_cmpl.status);
NETWORK_BLUETOOTH_DEBUG_PRINTF(
", rssi = %d, bda = %02X:%02X:%02X:%02X:%02X:%02X",
param->read_rssi_cmpl.rssi,
param->read_rssi_cmpl.remote_addr[0],
param->read_rssi_cmpl.remote_addr[1],
param->read_rssi_cmpl.remote_addr[2],
param->read_rssi_cmpl.remote_addr[3],
param->read_rssi_cmpl.remote_addr[4],
param->read_rssi_cmpl.remote_addr[5]);
}
break;
case ESP_GAP_BLE_ADD_WHITELIST_COMPLETE_EVT:
{
PRINT_STATUS(param->adv_data_cmpl.status);
NETWORK_BLUETOOTH_DEBUG_PRINTF(
", wl_opration = %s",
param->update_whitelist_cmpl.wl_opration == ESP_BLE_WHITELIST_ADD
? "ADD" : "REMOVE");
}
break;
case ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT:
{
PRINT_STATUS(param->adv_data_cmpl.status);
NETWORK_BLUETOOTH_DEBUG_PRINTF(
", dev_num = %d, bond_dev = <print not impl>",
param->get_bond_dev_cmpl.dev_num);
}
break;
case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT:
{
PRINT_STATUS(param->adv_data_cmpl.status);
NETWORK_BLUETOOTH_DEBUG_PRINTF(
", bda = %02X:%02X:%02X:%02X:%02X:%02X",
param->remove_bond_dev_cmpl.bd_addr[0],
param->remove_bond_dev_cmpl.bd_addr[1],
param->remove_bond_dev_cmpl.bd_addr[2],
param->remove_bond_dev_cmpl.bd_addr[3],
param->remove_bond_dev_cmpl.bd_addr[4],
param->remove_bond_dev_cmpl.bd_addr[5]);
}
break;
case ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT:
{
PRINT_STATUS(param->pkt_data_lenth_cmpl.status);
NETWORK_BLUETOOTH_DEBUG_PRINTF(
", rx_len = %04X"
", tx_len = %04X",
param->pkt_data_lenth_cmpl.params.rx_len,
param->pkt_data_lenth_cmpl.params.tx_len
);
}
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
{
PRINT_STATUS(param->update_conn_params.status);
NETWORK_BLUETOOTH_DEBUG_PRINTF(
", bda = %02X:%02X:%02X:%02X:%02X:%02X"
", min_int = %04X"
", max_int = %04X"
", latency = %04X"
", conn_int = %04X"
", timeout = %04X",
param->update_conn_params.bda[0],
param->update_conn_params.bda[1],
param->update_conn_params.bda[2],
param->update_conn_params.bda[3],
param->update_conn_params.bda[4],
param->update_conn_params.bda[5],
param->update_conn_params.min_int,
param->update_conn_params.max_int,
param->update_conn_params.latency,
param->update_conn_params.conn_int,
param->update_conn_params.timeout
);
}
break;
case ESP_GAP_BLE_SCAN_RESULT_EVT:
{
const char * search_events[7] = {
"INQ_RES",
"INQ_CMPL",
"DISC_RES",
"DISC_BLE_RES",
"DISC_CMPL",
"DI_DISC_CMPL",
"SEARCH_CANCEL_CMPL"
};
const char * dev_types[] = { "", "BREDR", "BLE", "DUMO" };
const char * addr_types[] = { "PUBLIC", "RANDOM", "RPA_PUBLIC", "RPA_RANDOM" };
NETWORK_BLUETOOTH_DEBUG_PRINTF(
"search_evt = %s",
search_events[param->scan_rst.search_evt]);
if (param->scan_rst.dev_type <= 3 && param->scan_rst.ble_addr_type <= 3) {
NETWORK_BLUETOOTH_DEBUG_PRINTF(
", dev_type = %s"
", ble_addr_type = %s"
", rssi = %d" ,
dev_types[param->scan_rst.dev_type],
addr_types[param->scan_rst.ble_addr_type],
param->scan_rst.rssi
);
}
if (param->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
NETWORK_BLUETOOTH_DEBUG_PRINTF(
", bda = %02X:%02X:%02X:%02X:%02X:%02X"
", adv_data_len = %u"
", scan_rsp_len = %u" ,
param->scan_rst.bda[0],
param->scan_rst.bda[1],
param->scan_rst.bda[2],
param->scan_rst.bda[3],
param->scan_rst.bda[4],
param->scan_rst.bda[5],
param->scan_rst.adv_data_len,
param->scan_rst.scan_rsp_len);
uint8_t * adv_name;
uint8_t adv_name_len = 0;
adv_name = esp_ble_resolve_adv_data(param->scan_rst.ble_adv,
ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
NETWORK_BLUETOOTH_DEBUG_PRINTF(", adv_name = ");
for (int j = 0; j < adv_name_len; j++) {
NETWORK_BLUETOOTH_DEBUG_PRINTF("%c", adv_name[j]);
}
NETWORK_BLUETOOTH_DEBUG_PRINTF("(%d bytes)", adv_name_len);
}
}
break;
case ESP_GAP_BLE_AUTH_CMPL_EVT:
break;
case ESP_GAP_BLE_KEY_EVT:
break;
case ESP_GAP_BLE_SEC_REQ_EVT:
break;
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:
break;
case ESP_GAP_BLE_PASSKEY_REQ_EVT:
break;
case ESP_GAP_BLE_OOB_REQ_EVT:
break;
case ESP_GAP_BLE_LOCAL_IR_EVT:
break;
case ESP_GAP_BLE_LOCAL_ER_EVT:
break;
case ESP_GAP_BLE_NC_REQ_EVT:
break;
}
NETWORK_BLUETOOTH_DEBUG_PRINTF(")\n");
}
#endif // EVENT_DEBUG
//--------------------------------
STATIC void btle_gap_event_handler
(
esp_gap_ble_cb_event_t event,
esp_ble_gap_cb_param_t *param) {
#ifdef EVENT_DEBUG_GAP
gap_event_dump(event, param);
#endif
btle_obj_t* bluetooth = btle_get_singleton();
if (bluetooth->state != BTLE_STATE_INIT) {
return;
}
}
//---------------------------------------------------------------------------------------
STATIC void btle_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
btle_obj_t *self = MP_OBJ_TO_PTR(self_in);
//#define BTLE_LF "\n"
#define BTLE_LF
mp_printf(print,
"Bluetooth(params=(conn_id=%04X" BTLE_LF
", gatts_connected=%s" BTLE_LF
", gatts_if=%u" BTLE_LF
", gattc_if=%u" BTLE_LF
", adv_params=("
"adv_int_min=%u, " BTLE_LF
"adv_int_max=%u, " BTLE_LF
"adv_type=%u, " BTLE_LF
"own_addr_type=%u, " BTLE_LF
"peer_addr=%02X:%02X:%02X:%02X:%02X:%02X, " BTLE_LF
"peer_addr_type=%u, " BTLE_LF
"channel_map=%u, " BTLE_LF
"adv_filter_policy=%u" BTLE_LF
"state=%d" BTLE_LF
")"
,
self->conn_id,
self->gatts_connected ? "True" : "False",
self->gatts_interface,
self->gattc_interface,
(unsigned int)(self->adv_params.adv_int_min / 1.6),
(unsigned int)(self->adv_params.adv_int_max / 1.6),
self->adv_params.adv_type,
self->adv_params.own_addr_type,
self->adv_params.peer_addr[0],
self->adv_params.peer_addr[1],
self->adv_params.peer_addr[2],
self->adv_params.peer_addr[3],
self->adv_params.peer_addr[4],
self->adv_params.peer_addr[5],
self->adv_params.peer_addr_type,
self->adv_params.channel_map,
self->adv_params.adv_filter_policy,
self->state
);
mp_printf(print,
", data=("
"set_scan_rsp=%s, " BTLE_LF
"include_name=%s, " BTLE_LF
"include_txpower=%s, " BTLE_LF
"min_interval=%d, " BTLE_LF
"max_interval=%d, " BTLE_LF
"appearance=%d, " BTLE_LF
"manufacturer_len=%d, " BTLE_LF
"p_manufacturer_data=%s, " BTLE_LF
"service_data_len=%d, " BTLE_LF
"p_service_data=",
self->adv_data.set_scan_rsp ? "True" : "False",
self->adv_data.include_name ? "True" : "False",
self->adv_data.include_txpower ? "True" : "False",
self->adv_data.min_interval,
self->adv_data.max_interval,
self->adv_data.appearance,
self->adv_data.manufacturer_len,
self->adv_data.p_manufacturer_data ? (const char *)self->adv_data.p_manufacturer_data : "nil",
self->adv_data.service_data_len);
if (self->adv_data.p_service_data != NULL) {
dumpBuf(self->adv_data.p_service_data, self->adv_data.service_data_len);
}
mp_printf(print, ", " BTLE_LF "flag=%d" BTLE_LF , self->adv_data.flag);
mp_printf(print, ")");
}
// bluetooth.init(...)
//-----------------------------------------
STATIC mp_obj_t btle_init(mp_obj_t self_in)
{
btle_obj_t * self = (btle_obj_t*)self_in;
if (bluetooth_enabled) return mp_const_none;
if (item_mut == NULL) {
item_mut = xSemaphoreCreateMutex();
xSemaphoreGive(item_mut);
}
if (callback_q == NULL) {
callback_q = xQueueCreate(CALLBACK_QUEUE_SIZE, sizeof(callback_data_t));
if (callback_q == NULL) {
mp_raise_msg(&mp_type_OSError, "unable to create callback queue");
}
} else {
xQueueReset(callback_q);
}
if (read_write_q == NULL) {
read_write_q = xQueueCreate(1, sizeof(read_write_data_t));
if (read_write_q == NULL) {
mp_raise_msg(&mp_type_OSError, "unable to create read queue");
}
} else {
xQueueReset(read_write_q);
}
if (self->state == BTLE_STATE_DEINIT) {
self->state = BTLE_STATE_INIT;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_bt_controller_init() failed");
}
// Enable Bluetooth dual mode
if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_bt_controller_enable() failed");
}
if (esp_bluedroid_init() != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_bluedroid_init() failed");
}
if (esp_bluedroid_enable() != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_bluedroid_enable() failed");
}
#if CONFIG_GATTS_ENABLE
if (esp_ble_gatts_register_callback(btle_gatts_event_handler) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_ble_gatts_register_callback() failed");
}
#endif
#if CONFIG_GATTC_ENABLE
if (esp_ble_gattc_register_callback(btle_gattc_event_handler) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_ble_gattc_register_callback() failed");
}
#endif
if (esp_ble_gap_register_callback(btle_gap_event_handler) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_ble_gap_register_callback() failed");
}
#if CONFIG_GATTS_ENABLE
if (esp_ble_gatts_app_register(0) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_ble_gatts_app_register() failed");
}
#endif
#if CONFIG_GATTC_ENABLE
if (esp_ble_gattc_app_register(1) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, "esp_ble_gattc_app_register() failed");
}
#endif
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(btle_init_obj, btle_init);
STATIC mp_obj_t btle_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
printf("enter btle_make_new\n");
btle_obj_t *self = btle_get_singleton();
if (n_args != 0 || n_kw != 0) {
mp_raise_TypeError("Constructor takes no arguments");
}
btle_init(self);
return MP_OBJ_FROM_PTR(self);
}
STATIC void btle_adv_updated() {
btle_obj_t* self = btle_get_singleton();
esp_ble_gap_stop_advertising();
esp_ble_gap_config_adv_data(&self->adv_data);
// Restart will be handled in btle_gap_event_handler
}
STATIC mp_obj_t btle_adv_params(size_t n_args, const mp_obj_t *pos_args, mp_map_t * kw_args) {
btle_obj_t *bluetooth = btle_get_singleton();
if (bluetooth->state != BTLE_STATE_INIT) {
mp_raise_msg(&mp_type_OSError, "bluetooth is deinit");
}
bool changed = false;
enum {
// params
ARG_int_min,
ARG_int_max,
ARG_type,
ARG_own_addr_type,
ARG_peer_addr,
ARG_peer_addr_type,
ARG_channel_map,
ARG_filter_policy
};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_int_min, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_int_max, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_adv_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 }},
{ MP_QSTR_own_addr_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 }},
{ MP_QSTR_peer_addr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = NULL }},
{ MP_QSTR_peer_addr_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 }},
{ MP_QSTR_channel_map, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 }},
{ MP_QSTR_filter_policy, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 }},
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(0, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_buffer_info_t peer_addr_buf = { 0 };
// pre-check complex types
// peer_addr
if (args[ARG_peer_addr].u_obj != NULL) {
if (!MP_OBJ_IS_TYPE(args[ARG_peer_addr].u_obj, &mp_type_bytearray)) {
BAD_PEER("peer addr ");
}
mp_get_buffer(args[ARG_peer_addr].u_obj, &peer_addr_buf, MP_BUFFER_READ);
if (peer_addr_buf.len != ESP_BD_ADDR_LEN) {
BAD_PEER("peer addr ");
}
}
// update esp_ble_adv_params_t
if (args[ARG_int_min].u_int != -1) {
bluetooth->adv_params.adv_int_min = args[ARG_int_min].u_int * 1.6; // 0.625 msec per count
changed = true;
}
if (args[ARG_int_max].u_int != -1) {
bluetooth->adv_params.adv_int_max = args[ARG_int_max].u_int * 1.6;
changed = true;
}
if (args[ARG_type].u_int != -1) {
bluetooth->adv_params.adv_type = args[ARG_type].u_int;
changed = true;
}
if (args[ARG_own_addr_type].u_int != -1) {
bluetooth->adv_params.own_addr_type = args[ARG_own_addr_type].u_int;
changed = true;
}
if (peer_addr_buf.buf != NULL) {
memcpy(bluetooth->adv_params.peer_addr, peer_addr_buf.buf, ESP_BD_ADDR_LEN);
changed = true;
}
if (args[ARG_peer_addr_type].u_int != -1) {
bluetooth->adv_params.peer_addr_type = args[ARG_peer_addr_type].u_int;
changed = true;
}
if (args[ARG_channel_map].u_int != -1) {
bluetooth->adv_params.channel_map = args[ARG_channel_map].u_int;
changed = true;
}
if (args[ARG_filter_policy].u_int != -1) {
bluetooth->adv_params.adv_filter_policy = args[ARG_filter_policy].u_int;
changed = true;
}
if (changed) {
btle_adv_updated();
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(btle_adv_params_obj, 1, btle_adv_params);
STATIC mp_obj_t btle_adv_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t * kw_args) {
btle_obj_t *bluetooth = btle_get_singleton();
if (bluetooth->state != BTLE_STATE_INIT) {
mp_raise_msg(&mp_type_OSError, "bluetooth is deinit");
}
bool changed = false;
bool unset_man_name = false;
bool unset_dev_name = false;
bool unset_uuid = false;
enum {
// data
ARG_is_scan_rsp,
ARG_dev_name,
ARG_man_name,
ARG_inc_txpower,
ARG_int_min,
ARG_int_max,
ARG_appearance,
ARG_uuid,
ARG_flags
};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_is_scan_rsp, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = NULL}},
{ MP_QSTR_dev_name, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = NULL }},
{ MP_QSTR_man_name, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = NULL }},
{ MP_QSTR_inc_tx_power, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = NULL }},
{ MP_QSTR_int_min, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 }},
{ MP_QSTR_int_max, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 }},
{ MP_QSTR_appearance, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 }},
{ MP_QSTR_uuid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = NULL }},
{ MP_QSTR_flags, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NULL }},
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(0, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_buffer_info_t man_name_buf = { 0 };
mp_buffer_info_t dev_name_buf = { 0 };
mp_buffer_info_t uuid_buf = { 0 };
// pre-check complex types
// man_name
if (args[ARG_man_name].u_obj != NULL) {
if (mp_obj_get_type(args[ARG_man_name].u_obj) == mp_const_none) {
unset_man_name = true;
} else if (!MP_OBJ_IS_STR_OR_BYTES(args[ARG_man_name].u_obj)) {
mp_raise_ValueError("man_name must be type str or bytes");
}
mp_obj_str_get_buffer(args[ARG_man_name].u_obj, &man_name_buf, MP_BUFFER_READ);
}
// dev_name
if (args[ARG_dev_name].u_obj != NULL) {
if (mp_obj_get_type(args[ARG_dev_name].u_obj) == mp_const_none) {
unset_dev_name = true;
} else if (!MP_OBJ_IS_STR_OR_BYTES(args[ARG_dev_name].u_obj)) {
mp_raise_ValueError("dev_name must be type str or bytes");
}
mp_obj_str_get_buffer(args[ARG_dev_name].u_obj, &dev_name_buf, MP_BUFFER_READ);
}
// uuid
if (args[ARG_uuid].u_obj != NULL) {
if (mp_obj_get_type(args[ARG_uuid].u_obj) == mp_const_none) {
unset_uuid = true;
} else if (!MP_OBJ_IS_TYPE(mp_obj_get_type(args[ARG_uuid].u_obj), &mp_type_bytearray)) {
BAD_UUID("uuid ");
}
mp_get_buffer(args[ARG_uuid].u_obj, &uuid_buf, MP_BUFFER_READ);
if (uuid_buf.len != UUID_LEN) {
// FIXME: Is length really a fixed amount?
BAD_UUID("uuid ");
}
}
// update esp_ble_data_t
if (args[ARG_is_scan_rsp].u_obj != NULL) {
bluetooth->adv_data.set_scan_rsp = mp_obj_is_true(args[ARG_is_scan_rsp].u_obj);
changed = true;
}
if (unset_dev_name) {
esp_ble_gap_set_device_name("");
bluetooth->adv_data.include_name = false;
} else if (dev_name_buf.buf != NULL) {
esp_ble_gap_set_device_name(dev_name_buf.buf);
bluetooth->adv_data.include_name = dev_name_buf.len > 0;
changed = true;
}
if (unset_man_name || man_name_buf.buf != NULL) {
if (bluetooth->adv_data.p_manufacturer_data != NULL) {
FREE(bluetooth->adv_data.p_manufacturer_data);
bluetooth->adv_data.p_manufacturer_data = NULL;
}
bluetooth->adv_data.manufacturer_len = man_name_buf.len;
if (man_name_buf.len > 0) {
bluetooth->adv_data.p_manufacturer_data = MALLOC(man_name_buf.len);
memcpy(bluetooth->adv_data.p_manufacturer_data, man_name_buf.buf, man_name_buf.len);
}
changed = true;
}
if (args[ARG_inc_txpower].u_obj != NULL) {
bluetooth->adv_data.include_txpower = mp_obj_is_true(args[ARG_inc_txpower].u_obj);
changed = true;
}
if (args[ARG_int_min].u_int != -1) {
bluetooth->adv_data.min_interval = args[ARG_int_min].u_int;
changed = true;
}
if (args[ARG_int_max].u_int != -1) {
bluetooth->adv_data.max_interval = args[ARG_int_max].u_int;
changed = true;
}
if (args[ARG_appearance].u_int != -1) {
bluetooth->adv_data.appearance = args[ARG_appearance].u_int;
changed = true;
}
if (unset_uuid || uuid_buf.buf != NULL) {
if (bluetooth->adv_data.p_service_uuid != NULL) {
FREE(bluetooth->adv_data.p_service_uuid);
bluetooth->adv_data.p_service_uuid = NULL;
}
bluetooth->adv_data.service_uuid_len = uuid_buf.len;
if (uuid_buf.len > 0) {
bluetooth->adv_data.p_service_uuid = MALLOC(uuid_buf.len);
bluetooth->adv_data.service_uuid_len = uuid_buf.len;
memcpy(bluetooth->adv_data.p_service_uuid, uuid_buf.buf, uuid_buf.len);
}
changed = true;
}
if (args[ARG_flags].u_int != -1) {
bluetooth->adv_data.flag = args[ARG_flags].u_int;
changed = true;
}
if (changed) {
btle_adv_updated();
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(btle_adv_data_obj, 1, btle_adv_data);
STATIC mp_obj_t btle_ble_adv_enable(mp_obj_t self_in, mp_obj_t enable_in) {
btle_obj_t * self = MP_OBJ_TO_PTR(self_in);
bool enable = mp_obj_is_true(enable_in);
if (enable) {
esp_ble_adv_params_t params = {
.adv_int_min = MSEC_0_625_TO_UNIT(100), // 100ms
.adv_int_max = MSEC_0_625_TO_UNIT(100), // 100ms
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
esp_ble_gap_start_advertising(&params);
} else {
esp_ble_gap_stop_advertising();
}
self->advertising = enable;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(btle_ble_adv_enable_obj, btle_ble_adv_enable);
STATIC const mp_rom_map_elem_t btle_locals_dict_table[] = {
// instance methods
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&btle_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_adv_params), MP_ROM_PTR(&btle_adv_params_obj) },
{ MP_ROM_QSTR(MP_QSTR_adv_data), MP_ROM_PTR(&btle_adv_data_obj) },
{ MP_ROM_QSTR(MP_QSTR_ble_adv_enable), MP_ROM_PTR(&btle_ble_adv_enable_obj) },
/*
{ MP_ROM_QSTR(MP_QSTR_ble_settings), MP_ROM_PTR(&btle_ble_settings_obj) },
{ MP_ROM_QSTR(MP_QSTR_ble_adv_enable), MP_ROM_PTR(&btle_ble_adv_enable_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&btle_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&btle_connect_obj) },
{ MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&btle_gatts_service_type) },
{ MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&btle_services_obj) },
{ MP_ROM_QSTR(MP_QSTR_conns), MP_ROM_PTR(&btle_conns_obj) },
{ MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&btle_callback_obj) },
{ MP_ROM_QSTR(MP_QSTR_scan_start), MP_ROM_PTR(&btle_scan_start_obj) },
{ MP_ROM_QSTR(MP_QSTR_scan_stop), MP_ROM_PTR(&btle_scan_stop_obj) },
{ MP_ROM_QSTR(MP_QSTR_is_scanning), MP_ROM_PTR(&btle_is_scanning_obj) },
// class constants
// Callback types
{ MP_ROM_QSTR(MP_QSTR_CONNECT), MP_ROM_INT(BTLE_GATTS_CONNECT) },
{ MP_ROM_QSTR(MP_QSTR_DISCONNECT), MP_ROM_INT(BTLE_GATTS_DISCONNECT) },
{ MP_ROM_QSTR(MP_QSTR_READ), MP_ROM_INT(BTLE_READ) },
{ MP_ROM_QSTR(MP_QSTR_WRITE), MP_ROM_INT(BTLE_WRITE) },
{ MP_ROM_QSTR(MP_QSTR_NOTIFY), MP_ROM_INT(BTLE_NOTIFY) },
{ MP_ROM_QSTR(MP_QSTR_SCAN_RES), MP_ROM_INT(BTLE_GATTC_SCAN_RES) },
{ MP_ROM_QSTR(MP_QSTR_SCAN_CMPL), MP_ROM_INT(BTLE_GATTC_SCAN_CMPL) },
// esp_ble_adv_type_t
{ MP_ROM_QSTR(MP_QSTR_ADV_TYPE_IND), MP_ROM_INT(ADV_TYPE_IND) },
{ MP_ROM_QSTR(MP_QSTR_ADV_TYPE_DIRECT_IND_HIGH), MP_ROM_INT(ADV_TYPE_DIRECT_IND_HIGH) },
{ MP_ROM_QSTR(MP_QSTR_ADV_TYPE_SCAN_IND), MP_ROM_INT(ADV_TYPE_SCAN_IND) },
{ MP_ROM_QSTR(MP_QSTR_ADV_TYPE_NONCONN_IND), MP_ROM_INT(ADV_TYPE_NONCONN_IND) },
{ MP_ROM_QSTR(MP_QSTR_ADV_TYPE_DIRECT_IND_LOW), MP_ROM_INT(ADV_TYPE_DIRECT_IND_LOW) },
// esp_ble_addr_type_t
{ MP_ROM_QSTR(MP_QSTR_BLE_ADDR_TYPE_PUBLIC), MP_ROM_INT(BLE_ADDR_TYPE_PUBLIC) },
{ MP_ROM_QSTR(MP_QSTR_BLE_ADDR_TYPE_RANDOM), MP_ROM_INT(BLE_ADDR_TYPE_RANDOM) },
{ MP_ROM_QSTR(MP_QSTR_BLE_ADDR_TYPE_RPA_PUBLIC), MP_ROM_INT(BLE_ADDR_TYPE_RPA_PUBLIC) },
{ MP_ROM_QSTR(MP_QSTR_BLE_ADDR_TYPE_RPA_RANDOM), MP_ROM_INT(BLE_ADDR_TYPE_RPA_RANDOM) },
// esp_ble_adv_channel_t
{ MP_ROM_QSTR(MP_QSTR_ADV_CHNL_37), MP_ROM_INT(ADV_CHNL_37) },
{ MP_ROM_QSTR(MP_QSTR_ADV_CHNL_38), MP_ROM_INT(ADV_CHNL_38) },
{ MP_ROM_QSTR(MP_QSTR_ADV_CHNL_39), MP_ROM_INT(ADV_CHNL_39) },
{ MP_ROM_QSTR(MP_QSTR_ADV_CHNL_ALL), MP_ROM_INT(ADV_CHNL_ALL) },
// BLE_ADV_DATA_FLAG
{ MP_ROM_QSTR(MP_QSTR_BLE_ADV_FLAG_LIMIT_DISC), MP_ROM_INT(ESP_BLE_ADV_FLAG_LIMIT_DISC) },
{ MP_ROM_QSTR(MP_QSTR_BLE_ADV_FLAG_GEN_DISC), MP_ROM_INT(ESP_BLE_ADV_FLAG_GEN_DISC) },
{ MP_ROM_QSTR(MP_QSTR_BLE_ADV_FLAG_BREDR_NOT_SPT), MP_ROM_INT(ESP_BLE_ADV_FLAG_BREDR_NOT_SPT) },
{ MP_ROM_QSTR(MP_QSTR_BLE_ADV_FLAG_DMT_CONTROLLER_SPT), MP_ROM_INT(ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT) },
{ MP_ROM_QSTR(MP_QSTR_BLE_ADV_FLAG_DMT_HOST_SPT), MP_ROM_INT(ESP_BLE_ADV_FLAG_DMT_HOST_SPT) },
{ MP_ROM_QSTR(MP_QSTR_BLE_ADV_FLAG_NON_LIMIT_DISC), MP_ROM_INT(ESP_BLE_ADV_FLAG_NON_LIMIT_DISC) },
// Scan param constants
{ MP_ROM_QSTR(MP_QSTR_SCAN_TYPE_PASSIVE), MP_ROM_INT(BLE_SCAN_TYPE_PASSIVE) },
{ MP_ROM_QSTR(MP_QSTR_SCAN_TYPE_ACTIVE), MP_ROM_INT(BLE_SCAN_TYPE_ACTIVE) },
{ MP_ROM_QSTR(MP_QSTR_SCAN_FILTER_ALLOW_ALL), MP_ROM_INT(BLE_SCAN_FILTER_ALLOW_ALL) },
{ MP_ROM_QSTR(MP_QSTR_SCAN_FILTER_ALLOW_ONLY_WLST), MP_ROM_INT(BLE_SCAN_FILTER_ALLOW_ONLY_WLST) },
{ MP_ROM_QSTR(MP_QSTR_SCAN_FILTER_ALLOW_UND_RPA_DIR), MP_ROM_INT(BLE_SCAN_FILTER_ALLOW_UND_RPA_DIR) },
{ MP_ROM_QSTR(MP_QSTR_SCAN_FILTER_ALLOW_WLIST_PRA_DIR), MP_ROM_INT(BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR) },
// exp_gatt_perm_t
{ MP_ROM_QSTR(MP_QSTR_PERM_READ), MP_ROM_INT(ESP_GATT_PERM_READ) },
{ MP_ROM_QSTR(MP_QSTR_PERM_READ_ENCRYPTED), MP_ROM_INT(ESP_GATT_PERM_READ_ENCRYPTED) },
{ MP_ROM_QSTR(MP_QSTR_PERM_READ_ENC_MITM), MP_ROM_INT(ESP_GATT_PERM_READ_ENC_MITM) },
{ MP_ROM_QSTR(MP_QSTR_PERM_WRITE), MP_ROM_INT(ESP_GATT_PERM_WRITE) },
{ MP_ROM_QSTR(MP_QSTR_PERM_WRITE_ENCRYPTED), MP_ROM_INT(ESP_GATT_PERM_WRITE_ENCRYPTED) },
{ MP_ROM_QSTR(MP_QSTR_PERM_WRITE_ENC_MITM), MP_ROM_INT(ESP_GATT_PERM_WRITE_ENC_MITM) },
{ MP_ROM_QSTR(MP_QSTR_PERM_WRITE_SIGNED), MP_ROM_INT(ESP_GATT_PERM_WRITE_SIGNED) },
{ MP_ROM_QSTR(MP_QSTR_PERM_WRITE_SIGNED_MITM), MP_ROM_INT(ESP_GATT_PERM_WRITE_SIGNED_MITM) },
// esp_gatt_char_prop_t
{ MP_ROM_QSTR(MP_QSTR_PROP_BROADCAST), MP_ROM_INT(ESP_GATT_CHAR_PROP_BIT_BROADCAST) },
{ MP_ROM_QSTR(MP_QSTR_PROP_READ), MP_ROM_INT(ESP_GATT_CHAR_PROP_BIT_READ) },
{ MP_ROM_QSTR(MP_QSTR_PROP_WRITE_NR), MP_ROM_INT(ESP_GATT_CHAR_PROP_BIT_WRITE_NR) },
{ MP_ROM_QSTR(MP_QSTR_PROP_WRITE), MP_ROM_INT(ESP_GATT_CHAR_PROP_BIT_WRITE) },
{ MP_ROM_QSTR(MP_QSTR_PROP_NOTIFY), MP_ROM_INT(ESP_GATT_CHAR_PROP_BIT_NOTIFY) },
{ MP_ROM_QSTR(MP_QSTR_PROP_INDICATE), MP_ROM_INT(ESP_GATT_CHAR_PROP_BIT_INDICATE) },
{ MP_ROM_QSTR(MP_QSTR_PROP_AUTH), MP_ROM_INT(ESP_GATT_CHAR_PROP_BIT_AUTH) },
{ MP_ROM_QSTR(MP_QSTR_PROP_EXT_PROP), MP_ROM_INT(ESP_GATT_CHAR_PROP_BIT_EXT_PROP) },
// esp_ble_adv_filter_t
{ MP_ROM_QSTR(MP_QSTR_ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY),
MP_ROM_INT(ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY)
},
{ MP_ROM_QSTR(MP_QSTR_ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY),
MP_ROM_INT(ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY)
},
{ MP_ROM_QSTR(MP_QSTR_ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST),
MP_ROM_INT(ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST)
},
{ MP_ROM_QSTR(MP_QSTR_ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST),
MP_ROM_INT(ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST)
},
*/
};
STATIC MP_DEFINE_CONST_DICT(btle_locals_dict, btle_locals_dict_table);
const mp_obj_type_t btle_type = {
{ &mp_type_type },
.name = MP_QSTR_Bluetooth,
.print = btle_print,
.make_new = btle_make_new,
.locals_dict = (mp_obj_dict_t*)&btle_locals_dict,
};