| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117 | /* * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */#include <string.h>#include "freertos/FreeRTOS.h"#include "esp_log.h"#include "ble_ota.h"#ifdef CONFIG_BT_BLUEDROID_ENABLED#include "esp_bt.h"#include "esp_gap_ble_api.h"#include "esp_gatts_api.h"#include "esp_bt_main.h"#endif#define TAG  "ESP_BLE_OTA"#define DEVICE_NAME  "ESP-C919"#ifdef CONFIG_BT_BLUEDROID_ENABLED#define OTA_PROFILE_NUM           2#define OTA_PROFILE_APP_IDX       0#define DIS_PROFILE_APP_IDX       1#define BUF_LENGTH                4098#define BLE_OTA_MAX_CHAR_VAL_LEN  600#define BLE_OTA_START_CMD         0x0001#define BLE_OTA_STOP_CMD          0x0002#define BLE_OTA_ACK_CMD           0x0003#define CHAR_DECLARATION_SIZE    (sizeof(uint8_t))typedef enum {    BLE_OTA_CMD_ACK = 0,        /*!< Command Ack */    BLE_OTA_FW_ACK  = 1,        /*!< Firmware Ack */} ble_ota_ack_type_t;typedef enum {    BLE_OTA_CMD_SUCCESS = 0x0000,       /*!< Success Ack */    BLE_OTA_REJECT      = 0x0001,       /*!< Reject Cmd Ack */} ble_ota_cmd_ack_status_t;typedef enum {    BLE_OTA_FW_SUCCESS = 0x0000,        /*!< Success */    BLE_OTA_FW_CRC_ERR = 0x0001,        /*!< CRC error */    BLE_OTA_FW_IND_ERR = 0x0002,        /*!< Sector Index error*/    BLE_OTA_FW_LEN_ERR = 0x0003,        /*!< Payload length error*/} ble_ota_fw_ack_statuc_t;struct gatts_profile_inst {    esp_gatts_cb_t gatts_cb;    uint16_t gatts_if;    uint16_t conn_id;    uint16_t mtu_size;};#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED#define EXT_ADV_HANDLE                            0#define NUM_EXT_ADV_SET                           1#define EXT_ADV_DURATION                          0#define EXT_ADV_MAX_EVENTS                        0static uint8_t ext_ota_adv_data[] = {    0x02, 0x01, 0x06,    0x03, 0x03, 0x18, 0x80, //UUID    0x09, 0x09, 0x45, 0x53, 0x50, 0x26, 0x43, 0x39, 0x31, 0x39, //ESP-C919    0x0d, 0xff, 0xe5, 0x02, 0x01, 0x01, 0x27, 0x95, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff};static esp_ble_gap_ext_adv_t ext_adv[1] = {    [0] = {EXT_ADV_HANDLE, EXT_ADV_DURATION, EXT_ADV_MAX_EVENTS},};esp_ble_gap_ext_adv_params_t ext_ota_adv_params = {    .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE,    .interval_min = 0x20,    .interval_max = 0x20,    .channel_map = ADV_CHNL_ALL,    .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,    .primary_phy = ESP_BLE_GAP_PHY_1M,    .max_skip = 0,    .secondary_phy = ESP_BLE_GAP_PHY_2M,    .sid = 0,    .scan_req_notif = false,    .own_addr_type = BLE_ADDR_TYPE_PUBLIC,    .tx_power = EXT_ADV_TX_PWR_NO_PREFERENCE,};#elsestatic esp_ble_adv_params_t ota_adv_params = {    .adv_int_min        = 0x20,    .adv_int_max        = 0x40,    .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,};static const uint8_t ota_adv_data[31] = {    0x02, 0x01, 0x06,    0x03, 0x03, 0x18, 0x80, //UUID    0x09, 0x09, 0x45, 0x53, 0x50, 0x26, 0x43, 0x39, 0x31, 0x39, //ESP-C919    0x0d, 0xff, 0xe5, 0x02, 0x01, 0x01, 0x27, 0x95, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff};static const uint8_t ota_scan_rsp_data[31] = {    0x02, 0x01, 0x06,    0x03, 0x03, 0x18, 0x80, //UUID    0x09, 0x09, 0x45, 0x53, 0x50, 0x26, 0x43, 0x39, 0x31, 0x39, //ESP-C919    0x0d, 0xff, 0xe5, 0x02, 0x01, 0x01, 0x27, 0x95, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff};#endifesp_ble_ota_callback_funs_t ota_cb_fun_t = {    .recv_fw_cb = NULL};esp_ble_ota_notification_check_t ota_notification = {    .recv_fw_ntf_enable = false,    .process_bar_ntf_enable = false,    .command_ntf_enable = false,    .customer_ntf_enable = false,};static void gatts_ota_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);static void gatts_dis_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);/** * @brief           This function is called to send notification to remote device * * @param[in]       ota_char: the characteristic index which to be send * @param[in]       value: the pointer to the send value * @param[in]       length: the value length * * @return *                  - ESP_OK : success *                  - other  : failed */esp_err_t esp_ble_ota_notification_data(esp_ble_ota_char_t ota_char, uint8_t *value, uint8_t length);/** * @brief           This function is called to set the attribute value by the application * * @param[in]       ota_char: the characteristic index which to be set * @param[in]       value: the pointer to the attribute value * @param[in]       length: the value length * * @return *                  - ESP_OK : success *                  - other  : failed */esp_err_t esp_ble_ota_set_value(esp_ble_ota_char_t ota_char, uint8_t *value, uint8_t length);static struct gatts_profile_inst ota_profile_tab[OTA_PROFILE_NUM] = {    [OTA_PROFILE_APP_IDX] = {        .gatts_cb = gatts_ota_profile_event_handler,        .gatts_if = ESP_GATT_IF_NONE,       /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */        .conn_id  = 0xff,        .mtu_size = 23,    },    [DIS_PROFILE_APP_IDX] = {        .gatts_cb = gatts_dis_profile_event_handler,        .gatts_if = ESP_GATT_IF_NONE,       /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */        .conn_id  = 0xff,        .mtu_size = 23,    },};static bool start_ota = false;static unsigned int ota_total_len = 0;static unsigned int cur_sector = 0;static unsigned int cur_packet = 0;static uint8_t *fw_buf = NULL;static unsigned int fw_buf_offset = 0;static uint8_t *temp_prep_write_buf = NULL;static unsigned int temp_buf_len = 0;static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ;static const uint8_t char_prop_read_indicate = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_INDICATE;static const uint8_t char_prop_write_indicate = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_INDICATE;static const uint16_t BLE_OTA_SERVICE_UUID              = 0x8018;static const uint16_t RECV_FW_UUID                      = 0x8020;static const uint16_t OTA_BAR_UUID                      = 0x8021;static const uint16_t COMMAND_UUID                      = 0x8022;static const uint16_t CUSTOMER_UUID                     = 0x8023;static uint8_t receive_fw_val[BLE_OTA_MAX_CHAR_VAL_LEN] = {0};static uint8_t receive_fw_val_ccc[2] = {0x00, 0x00};static uint8_t ota_status_val[20] = {0};static uint8_t ota_status_val_ccc[2] = {0x00, 0x00};static uint8_t command_val[20] = {0};static uint8_t command_val_ccc[2] = {0x00, 0x00};static uint8_t custom_val[20] = {0};static uint8_t custom_val_ccc[2] = {0x00, 0x00};static uint16_t ota_handle_table[OTA_IDX_NB];/* OTA Full Database Description - Used to add attributes into the database */static const esp_gatts_attr_db_t ota_gatt_db[OTA_IDX_NB] = {    // Service Declaration    [OTA_SVC_IDX]        =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &primary_service_uuid, ESP_GATT_PERM_READ,            sizeof(BLE_OTA_SERVICE_UUID), sizeof(BLE_OTA_SERVICE_UUID), (uint8_t *) &BLE_OTA_SERVICE_UUID        }    },    /* Characteristic Declaration */    [RECV_FW_CHAR_IDX]      =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_declaration_uuid, ESP_GATT_PERM_READ,            CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *) &char_prop_write_indicate        }    },    /* Characteristic Value */    [RECV_FW_CHAR_VAL_IDX]  =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &RECV_FW_UUID, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,            sizeof(receive_fw_val), sizeof(receive_fw_val), (uint8_t *)receive_fw_val        }    },    //data notify characteristic Declaration    [RECV_FW_CHAR_NTF_CFG]  =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,            sizeof(receive_fw_val_ccc), sizeof(receive_fw_val_ccc), (uint8_t *)receive_fw_val_ccc        }    },    //data receive characteristic Declaration    [OTA_STATUS_CHAR_IDX]            =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_declaration_uuid, ESP_GATT_PERM_READ,            CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *) &char_prop_read_indicate        }    },    //data receive characteristic Value    [OTA_STATUS_CHAR_VAL_IDX]               =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &OTA_BAR_UUID, ESP_GATT_PERM_READ,            sizeof(ota_status_val), sizeof(ota_status_val), (uint8_t *)ota_status_val        }    },    //data notify characteristic Declaration    [OTA_STATUS_NTF_CFG]  =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,            sizeof(ota_status_val_ccc), sizeof(ota_status_val_ccc), (uint8_t *)ota_status_val_ccc        }    },    //data receive characteristic Declaration    [CMD_CHAR_IDX]            =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_declaration_uuid, ESP_GATT_PERM_READ,            CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *) &char_prop_write_indicate        }    },    //data receive characteristic Value    [CMD_CHAR_VAL_IDX]              =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &COMMAND_UUID, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,            sizeof(command_val), sizeof(command_val), (uint8_t *)command_val        }    },    //data notify characteristic Declaration    [CMD_CHAR_NTF_CFG]  =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,            sizeof(command_val_ccc), sizeof(command_val_ccc), (uint8_t *)command_val_ccc        }    },    //data receive characteristic Declaration    [CUS_CHAR_IDX]            =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_declaration_uuid, ESP_GATT_PERM_READ,            CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *) &char_prop_write_indicate        }    },    //data receive characteristic Value    [CUS_CHAR_VAL_IDX]              =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &CUSTOMER_UUID, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,            sizeof(custom_val), sizeof(custom_val), (uint8_t *)custom_val        }    },    //data notify characteristic Declaration    [CUS_CHAR_NTF_CFG]  =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,            sizeof(custom_val_ccc), sizeof(custom_val_ccc), (uint8_t *)custom_val_ccc        }    },};static const uint16_t DIS_SERVICE_UUID    = 0x180A;static const uint16_t DIS_MODEL_CHAR_UUID = 0x2A24;static const uint16_t DIS_SN_CHAR_UUID    = 0x2A25;static const uint16_t DIS_FW_CHAR_UUID    = 0x2A26;static uint8_t dis_model_value[] = "Espressif";static uint8_t dis_sn_value[]    = "esp-ota";static uint8_t dis_fw_value[]    = "1.0";static uint16_t dis_handle_table[DIS_IDX_NB];/* DIS Full Database Description - Used to add attributes into the database */static const esp_gatts_attr_db_t dis_gatt_db[DIS_IDX_NB] = {    // Service Declaration    [DIS_SVC_IDX]        =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &primary_service_uuid, ESP_GATT_PERM_READ,            sizeof(DIS_SERVICE_UUID), sizeof(DIS_SERVICE_UUID), (uint8_t *) &DIS_SERVICE_UUID        }    },    /* Characteristic Declaration */    [DIS_MODEL_CHAR_IDX]      =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_declaration_uuid, ESP_GATT_PERM_READ,            CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *) &char_prop_read        }    },    /* Characteristic Value */    [DIS_MODEL_CHAR_VAL_IDX]  =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &DIS_MODEL_CHAR_UUID, ESP_GATT_PERM_READ,            sizeof(dis_model_value), sizeof(dis_model_value), (uint8_t *)dis_model_value        }    },    /* Characteristic Declaration */    [DIS_SN_CHAR_IDX]      =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_declaration_uuid, ESP_GATT_PERM_READ,            CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *) &char_prop_read        }    },    /* Characteristic Value */    [DIS_SN_CHAR_VAL_IDX]  =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &DIS_SN_CHAR_UUID, ESP_GATT_PERM_READ,            sizeof(dis_sn_value), sizeof(dis_sn_value), (uint8_t *)dis_sn_value        }    },    /* Characteristic Declaration */    [DIS_FW_CHAR_IDX]      =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &character_declaration_uuid, ESP_GATT_PERM_READ,            CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *) &char_prop_read        }    },    /* Characteristic Value */    [DIS_FW_CHAR_VAL_IDX]  =    {   {ESP_GATT_AUTO_RSP}, {            ESP_UUID_LEN_16, (uint8_t *) &DIS_FW_CHAR_UUID, ESP_GATT_PERM_READ,            sizeof(dis_fw_value), sizeof(dis_fw_value), (uint8_t *)dis_fw_value        }    },};static uint16_t crc16_ccitt(const unsigned char *buf, int len){    uint16_t crc16 = 0;    int32_t i;    while (len--) {        crc16 ^= *buf++ << 8;        for (i = 0; i < 8; i++) {            if (crc16 & 0x8000) {                crc16 = (crc16 << 1) ^ 0x1021;            } else {                crc16 = crc16 << 1;            }        }    }    return crc16;}void esp_ble_ota_set_fw_length(unsigned int length){    ota_total_len = length;}unsigned int esp_ble_ota_get_fw_length(void){    return ota_total_len;}static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param){    esp_bd_addr_t bd_addr;    ESP_LOGD(TAG, "GAP_EVT, event %d\n", event);    switch (event) {#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED    case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT:        esp_ble_gap_config_ext_adv_data_raw(EXT_ADV_HANDLE,  sizeof(ext_ota_adv_data), &ext_ota_adv_data[0]);        break;    case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:        esp_ble_gap_ext_adv_start(NUM_EXT_ADV_SET, &ext_adv[0]);        break;    case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:         ESP_LOGI(TAG, "Ext adv start, status = %d", param->ext_adv_data_set.status);        break;#else    case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:        esp_ble_gap_start_advertising(&ota_adv_params);        break;    case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:        //advertising start complete event to indicate advertising start successfully or failed        if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {            ESP_LOGE(TAG, "Advertising start failed\n");        }        break;#endif    case ESP_GAP_BLE_SEC_REQ_EVT:        for (int i = 0; i < ESP_BD_ADDR_LEN; i++) {            ESP_LOGI(TAG, "%x:", param->ble_security.ble_req.bd_addr[i]);        }        esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);        break;    case ESP_GAP_BLE_AUTH_CMPL_EVT:        memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));        ESP_LOGI(TAG, "remote BD_ADDR: %08x%04x", \                 (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],                 (bd_addr[4] << 8) + bd_addr[5]);        ESP_LOGI(TAG, "address type = %d", param->ble_security.auth_cmpl.addr_type);        ESP_LOGI(TAG, "pair status = %s", param->ble_security.auth_cmpl.success ? "success" : "fail");        if (!param->ble_security.auth_cmpl.success) {            ESP_LOGE(TAG, "fail reason = 0x%x", param->ble_security.auth_cmpl.fail_reason);        }        break;    case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:        ESP_LOGI(TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",                 param->update_conn_params.status,                 param->update_conn_params.min_int,                 param->update_conn_params.max_int,                 param->update_conn_params.conn_int,                 param->update_conn_params.latency,                 param->update_conn_params.timeout);        break;    default:        break;    }}static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){    // ESP_LOGI(TAG, "EVT %d, gatts if %d\n", event, gatts_if);    /* If event is register event, store the gatts_if for each profile */    if (event == ESP_GATTS_REG_EVT) {        if (param->reg.status == ESP_GATT_OK) {            ota_profile_tab[param->reg.app_id].gatts_if = gatts_if;        } else {            ESP_LOGE(TAG, "Reg app failed, app_id %04x, status %d\n", param->reg.app_id, param->reg.status);            return;        }    }    do {        int idx;        for (idx = 0; idx < OTA_PROFILE_NUM; idx++) {            if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */                    gatts_if == ota_profile_tab[idx].gatts_if) {                if (ota_profile_tab[idx].gatts_cb) {                    ota_profile_tab[idx].gatts_cb(event, gatts_if, param);                }            }        }    } while (0);}static void gatts_dis_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){    esp_err_t ret;    ESP_LOGD(TAG, "%s - event: %d", __func__, event);    switch (event) {    case ESP_GATTS_REG_EVT:        ret = esp_ble_gatts_create_attr_tab(dis_gatt_db, gatts_if, DIS_IDX_NB, DIS_PROFILE_APP_IDX);        if (ret) {            ESP_LOGE(TAG, "%s - create attr table failed, error code = %x", __func__, ret);        }        break;    case ESP_GATTS_READ_EVT:        ESP_LOGI(TAG, "DIS ESP_GATTS_READ_EVT");        break;    case ESP_GATTS_WRITE_EVT:        ESP_LOGI(TAG, "DIS ESP_GATTS_WRITE_EVT");        break;    case ESP_GATTS_EXEC_WRITE_EVT:        ESP_LOGI(TAG, "DIS ESP_GATTS_EXEC_WRITE_EVT");        break;    case ESP_GATTS_MTU_EVT:        ESP_LOGI(TAG, "DIS ESP_GATTS_MTU_EVT  mtu = %d", param->mtu.mtu);        break;    case ESP_GATTS_CONF_EVT:        break;    case ESP_GATTS_START_EVT:        ESP_LOGI(TAG, "DIS SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);        if (param->start.status != ESP_GATT_OK) {            ESP_LOGE(TAG, "SERVICE START FAIL, status %d", param->start.status);            break;        }        break;    case ESP_GATTS_CONNECT_EVT:        break;    case ESP_GATTS_DISCONNECT_EVT:        break;    case ESP_GATTS_CREAT_ATTR_TAB_EVT:        if (param->add_attr_tab.status != ESP_GATT_OK) {            ESP_LOGE(TAG, "dis create attribute table failed, error code=0x%x", param->add_attr_tab.status);        } else if (param->add_attr_tab.num_handle != DIS_IDX_NB) {            ESP_LOGE(TAG, "dis create attribute table abnormally, num_handle (%d) doesn't equal to DIS_IDX_NB(%d)", param->add_attr_tab.num_handle, DIS_IDX_NB);        } else {            ESP_LOGI(TAG, "dis create attribute table successfully, the number handle = %d\n", param->add_attr_tab.num_handle);            memcpy(dis_handle_table, param->add_attr_tab.handles, sizeof(dis_handle_table));            esp_ble_gatts_start_service(dis_handle_table[DIS_SVC_IDX]);        }        break;    case ESP_GATTS_STOP_EVT:        break;    case ESP_GATTS_OPEN_EVT:        break;    case ESP_GATTS_CANCEL_OPEN_EVT:        break;    case ESP_GATTS_CLOSE_EVT:        break;    case ESP_GATTS_LISTEN_EVT:        break;    case ESP_GATTS_CONGEST_EVT:        break;    case ESP_GATTS_UNREG_EVT:        break;    case ESP_GATTS_DELETE_EVT:        break;    default:        break;    }}static esp_ble_ota_char_t find_ota_char_and_desr_by_handle(uint16_t handle){    esp_ble_ota_char_t ret = INVALID_CHAR;    for (int i = 0; i < OTA_IDX_NB ; i++) {        if (handle == ota_handle_table[i]) {            switch (i) {            case RECV_FW_CHAR_VAL_IDX:                ret = RECV_FW_CHAR;                break;            case RECV_FW_CHAR_NTF_CFG:                ret = RECV_FW_CHAR_CCC;                break;            case OTA_STATUS_CHAR_VAL_IDX:                ret = OTA_STATUS_CHAR;                break;            case OTA_STATUS_NTF_CFG:                ret = OTA_STATUS_CHAR_CCC;                break;            case CMD_CHAR_VAL_IDX:                ret = CMD_CHAR;                break;            case CMD_CHAR_NTF_CFG:                ret = CMD_CHAR_CCC;                break;            case CUS_CHAR_VAL_IDX:                ret = CUS_CHAR;                break;            case CUS_CHAR_NTF_CFG:                ret = CUS_CHAR_CCC;                break;            default:                ret = INVALID_CHAR;                break;            }        }    }    return ret;}esp_err_t esp_ble_ota_recv_fw_handler(uint8_t *buf, unsigned int length){    if (ota_cb_fun_t.recv_fw_cb) {        ota_cb_fun_t.recv_fw_cb(buf, length);    }    return ESP_OK;}void esp_ble_ota_send_ack_data(ble_ota_ack_type_t ack_type, uint16_t ack_status, uint16_t ack_param){    uint8_t cmd_ack[20] = {0};    uint16_t crc16 = 0;    switch (ack_type) {    case BLE_OTA_CMD_ACK:        cmd_ack[0] = (BLE_OTA_ACK_CMD & 0xff);        cmd_ack[1] = (BLE_OTA_ACK_CMD & 0xff) >> 8;        cmd_ack[2] = (ack_param & 0xff);        cmd_ack[3] = (ack_param & 0xff00) >> 8;        cmd_ack[4] = (ack_status & 0xff);        cmd_ack[5] = (ack_status & 0xff00) >> 8;        crc16 = crc16_ccitt(cmd_ack, 18);        cmd_ack[18] = crc16 & 0xff;        cmd_ack[19] = (crc16 & 0xff00) >> 8;        esp_ble_ota_notification_data(CMD_CHAR, cmd_ack, 20);        break;    case BLE_OTA_FW_ACK:        cmd_ack[0] = (ack_param & 0xff);        cmd_ack[1] = (ack_param & 0xff) >> 8;        cmd_ack[2] = (ack_status & 0xff);        cmd_ack[3] = (ack_status & 0xff00) >> 8;        cmd_ack[4] = (cur_sector & 0xff);        cmd_ack[5] = (cur_sector & 0xff) >> 8;        crc16 = crc16_ccitt(cmd_ack, 18);        cmd_ack[18] = crc16 & 0xff;        cmd_ack[19] = (crc16 & 0xff00) >> 8;        esp_ble_ota_notification_data(RECV_FW_CHAR, cmd_ack, 20);        break;    default:        break;    }}void esp_ble_ota_process_recv_data(esp_ble_ota_char_t ota_char, uint8_t *val, uint16_t val_len){    unsigned int recv_sector = 0;    switch (ota_char) {    case CMD_CHAR:        // Start BLE OTA Process        if ((val[0] == 0x01) && (val[1] == 0x00)) {            if (start_ota) {                esp_ble_ota_send_ack_data(BLE_OTA_CMD_ACK, BLE_OTA_REJECT, BLE_OTA_START_CMD);            } else {                start_ota = true;                // Calculating Firmware Length                ota_total_len = (val[2]) +                                (val[3] * 256) +                                (val[4] * 256 * 256) +                                (val[5] * 256 * 256 * 256);                esp_ble_ota_set_fw_length(ota_total_len);                ESP_LOGI(TAG, "Recv ota start cmd, fw_length = %d", ota_total_len);                // Malloc buffer to store receive Firmware                fw_buf = (uint8_t *)malloc(BUF_LENGTH * sizeof(uint8_t));                if (fw_buf == NULL) {                    ESP_LOGE(TAG, "Malloc fail");                    break;                } else {                    memset(fw_buf, 0x0, BUF_LENGTH);                }                esp_ble_ota_send_ack_data(BLE_OTA_CMD_ACK, BLE_OTA_CMD_SUCCESS, BLE_OTA_START_CMD);            }        }        // Stop BLE OTA Process        else if ((val[0] == 0x02) && (val[1] == 0x00)) {            if (start_ota) {                start_ota = false;                esp_ble_ota_set_fw_length(0);                ESP_LOGI(TAG, "recv ota stop cmd");                esp_ble_ota_send_ack_data(BLE_OTA_CMD_ACK, BLE_OTA_CMD_SUCCESS, BLE_OTA_STOP_CMD);                if (fw_buf) {                    free(fw_buf);                    fw_buf = NULL;                }            } else {                esp_ble_ota_send_ack_data(BLE_OTA_CMD_ACK, BLE_OTA_REJECT, BLE_OTA_STOP_CMD);            }        } else {            ESP_LOGE(TAG, "Unknow Command [0x%02x%02x]", val[1], val[0]);        }        break;    case RECV_FW_CHAR:        if (start_ota) {            // Calculating the received sector index            recv_sector = (val[0] + (val[1] * 256));            if (recv_sector != cur_sector) { // sector error                if (recv_sector == 0xffff) { // last sector                    ESP_LOGI(TAG, "Laster sector");                } else {  // sector error                    ESP_LOGE(TAG, "Sector index error, cur: %d, recv: %d", cur_sector, recv_sector);                    esp_ble_ota_send_ack_data(BLE_OTA_FW_ACK, BLE_OTA_FW_IND_ERR, recv_sector);                }            }            if (val[2] != cur_packet) { // packet seq error                if (val[2] == 0xff) { // last packet                    ESP_LOGI(TAG, "laster packet");                    goto write_ota_data;                } else { // packet seq error                    ESP_LOGE(TAG, "Packet index error, cur: %d, recv: %d", cur_packet, val[2]);                }            }write_ota_data:            memcpy(fw_buf + fw_buf_offset, val + 3, val_len - 3);            fw_buf_offset += val_len - 3;            ESP_LOGI(TAG, "DEBUG: Sector:%d, total length:%d, length:%d", cur_sector, fw_buf_offset, val_len - 3);            if (val[2] == 0xff) {                cur_packet = 0;                cur_sector++;                ESP_LOGD(TAG, "DEBUG: recv %d sector", cur_sector);                goto sector_end;            } else {                cur_packet++;            }            break;sector_end:            esp_ble_ota_recv_fw_handler(fw_buf, 4096);            memset(fw_buf, 0x0, 4096);            fw_buf_offset = 0;            esp_ble_ota_send_ack_data(BLE_OTA_FW_ACK, BLE_OTA_FW_SUCCESS, recv_sector);        } else {            ESP_LOGE(TAG, "BLE OTA hasn't started yet");        }        break;    case OTA_STATUS_CHAR:        break;    case CUS_CHAR:        break;    default:        ESP_LOGW(TAG, "Invalid data was received, char[%d]", ota_char);        break;    }}static void gatts_ota_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){    esp_err_t ret;    esp_ble_ota_char_t ota_char;    ESP_LOGI(TAG, "%s - event: %d", __func__, event);    switch (event) {    case ESP_GATTS_REG_EVT:        ret = esp_ble_gap_set_device_name(DEVICE_NAME);        if (ret) {            ESP_LOGE(TAG, "set device name failed, error code = %x", ret);        }#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED        ret = esp_ble_gap_ext_adv_set_params(EXT_ADV_HANDLE, &ext_ota_adv_params);        if (ret) {            ESP_LOGE(TAG, "set ext adv params failed, error code = %x", ret);        }#else        ret = esp_ble_gap_config_adv_data_raw((uint8_t *)ota_adv_data, sizeof(ota_adv_data));        if (ret) {            ESP_LOGE(TAG, "set adv data failed, error code = %x", ret);        }        ret = esp_ble_gap_config_scan_rsp_data_raw((uint8_t *)ota_scan_rsp_data, sizeof(ota_scan_rsp_data));        if (ret) {            ESP_LOGE(TAG, "set scan rsp data failed, error code = %x", ret);        }#endif        ret = esp_ble_gatts_create_attr_tab(ota_gatt_db, gatts_if, OTA_IDX_NB, OTA_PROFILE_APP_IDX);        if (ret) {            ESP_LOGE(TAG, "Create attr table failed, error code = %x", ret);        }        break;    case ESP_GATTS_READ_EVT:        ota_char = find_ota_char_and_desr_by_handle(param->read.handle);        ESP_LOGI(TAG, "Read event - ota_char: %d", ota_char);        break;    case ESP_GATTS_WRITE_EVT:        ota_char = find_ota_char_and_desr_by_handle(param->write.handle);        ESP_LOGD(TAG, "Write event - ota_char: %d", ota_char);        // Enable indication        if ((param->write.len == 2) && (param->write.value[0] == 0x02) && (param->write.value[1] == 0x00)) {            if (ota_char == OTA_STATUS_CHAR_CCC) {                ota_notification.process_bar_ntf_enable = true;            }            if (ota_char == RECV_FW_CHAR_CCC) {                ota_notification.recv_fw_ntf_enable = true;            }            if (ota_char == CMD_CHAR_CCC) {                ota_notification.command_ntf_enable = true;            }            if (ota_char == CUS_CHAR_CCC) {                ota_notification.customer_ntf_enable = true;            }        }        // Disable indication        else if ((param->write.len == 2) && (param->write.value[0] == 0x00) && (param->write.value[1] == 0x00)) {            if (ota_char == OTA_STATUS_CHAR_CCC) {                ota_notification.process_bar_ntf_enable = false;            }            if (ota_char == RECV_FW_CHAR_CCC) {                ota_notification.recv_fw_ntf_enable = false;            }            if (ota_char == CMD_CHAR_CCC) {                ota_notification.command_ntf_enable = false;            }            if (ota_char == CUS_CHAR_CCC) {                ota_notification.customer_ntf_enable = false;            }        }        if (param->write.is_prep == false) {            esp_ble_ota_process_recv_data(ota_char, param->write.value, param->write.len);        } else {            if (temp_prep_write_buf == NULL) {                temp_prep_write_buf = (uint8_t *)malloc(BLE_OTA_MAX_CHAR_VAL_LEN * sizeof(uint8_t));                if (temp_prep_write_buf == NULL) {                    ESP_LOGE(TAG, "Malloc buffer for prep write fail");                    break;                }                memset(temp_prep_write_buf, 0x0, BLE_OTA_MAX_CHAR_VAL_LEN);                temp_buf_len = 0;            }            memcpy(temp_prep_write_buf + temp_buf_len, param->write.value, param->write.len);            temp_buf_len += param->write.len;        }        break;    case ESP_GATTS_EXEC_WRITE_EVT:        if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {            if (temp_prep_write_buf) {                esp_ble_ota_process_recv_data(RECV_FW_CHAR, temp_prep_write_buf, temp_buf_len);            }        } else {            if (temp_prep_write_buf) {                free(temp_prep_write_buf);                temp_prep_write_buf = NULL;            }            temp_buf_len = 0;        }        break;    case ESP_GATTS_MTU_EVT:        ESP_LOGI(TAG, "ESP_GATTS_MTU_EVT - mtu = %d", param->mtu.mtu);        ota_profile_tab[OTA_PROFILE_APP_IDX].mtu_size = param->mtu.mtu;        break;    case ESP_GATTS_CONF_EVT:        break;    case ESP_GATTS_START_EVT:        ESP_LOGI(TAG, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);        if (param->start.status != ESP_GATT_OK) {            ESP_LOGE(TAG, "SERVICE START FAIL, status %d", param->start.status);            break;        }        break;    case ESP_GATTS_CONNECT_EVT:        ota_profile_tab[OTA_PROFILE_APP_IDX].conn_id = param->connect.conn_id;        esp_ble_conn_update_params_t conn_params = {0};        memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));        /* For the IOS system, please reference the apple official documents about the ble connection parameters restrictions. */        conn_params.latency = 0;        conn_params.max_int = 0x06;    // max_int = 0x6*1.25ms = 7.5ms        conn_params.min_int = 0x06;    // min_int = 0x6*1.25ms = 7.5ms        conn_params.timeout = 400;     // timeout = 400*10ms = 4000ms        ESP_LOGI(TAG, "ESP_GATTS_CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:",                 param->connect.conn_id,                 param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2],                 param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]);        //start sent the update connection parameters to the peer device.        esp_ble_gap_update_conn_params(&conn_params);        break;    case ESP_GATTS_DISCONNECT_EVT:#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED        esp_ble_gap_ext_adv_start(NUM_EXT_ADV_SET, &ext_adv[0]);#else        esp_ble_gap_start_advertising(&ota_adv_params);#endif        ota_profile_tab[OTA_PROFILE_APP_IDX].mtu_size = 23;        break;    case ESP_GATTS_CREAT_ATTR_TAB_EVT:        if (param->add_attr_tab.status != ESP_GATT_OK) {            ESP_LOGE(TAG, "create attribute table failed, error code=0x%x", param->add_attr_tab.status);        } else if (param->add_attr_tab.num_handle != OTA_IDX_NB) {            ESP_LOGE(TAG, "create attribute table abnormally, num_handle (%d) doesn't equal to OTA_IDX_NB(%d)", param->add_attr_tab.num_handle, OTA_IDX_NB);        } else {            ESP_LOGI(TAG, "create attribute table successfully, the number handle = %d\n", param->add_attr_tab.num_handle);            memcpy(ota_handle_table, param->add_attr_tab.handles, sizeof(ota_handle_table));            esp_ble_gatts_start_service(ota_handle_table[OTA_SVC_IDX]);        }        break;    case ESP_GATTS_STOP_EVT:        break;    case ESP_GATTS_OPEN_EVT:        break;    case ESP_GATTS_CANCEL_OPEN_EVT:        break;    case ESP_GATTS_CLOSE_EVT:        break;    case ESP_GATTS_LISTEN_EVT:        break;    case ESP_GATTS_CONGEST_EVT:        break;    case ESP_GATTS_UNREG_EVT:        break;    case ESP_GATTS_DELETE_EVT:        break;    default:        break;    }}static esp_err_t esp_ble_ota_set_characteristic_value(esp_ble_ota_service_index_t index, uint8_t *value, uint8_t length){    esp_err_t ret;    ret = esp_ble_gatts_set_attr_value(ota_handle_table[index], length, value);    if (ret) {        ESP_LOGE(TAG, "%s set attribute value fail: %s\n", __func__, esp_err_to_name(ret));        return ESP_FAIL;    }    return ESP_OK;}esp_err_t esp_ble_ota_set_value(esp_ble_ota_char_t ota_char, uint8_t *value, uint8_t length){    esp_err_t ret;    switch (ota_char) {    case RECV_FW_CHAR:        ret = esp_ble_ota_set_characteristic_value(RECV_FW_CHAR_VAL_IDX, value, length);        break;    case OTA_STATUS_CHAR:        ret = esp_ble_ota_set_characteristic_value(OTA_STATUS_CHAR_VAL_IDX, value, length);        break;    case CMD_CHAR:        ret = esp_ble_ota_set_characteristic_value(CMD_CHAR_VAL_IDX, value, length);        break;    case CUS_CHAR:        ret = esp_ble_ota_set_characteristic_value(CUS_CHAR_VAL_IDX, value, length);        break;    default:        ret = ESP_FAIL;        break;    }    if (ret) {        ESP_LOGE(TAG, "%s set characteristic value fail: %s\n", __func__, esp_err_to_name(ret));        return ESP_FAIL;    }    return ESP_OK;}static esp_err_t esp_ble_ota_send_indication(esp_ble_ota_service_index_t index, uint8_t *value, uint8_t length, bool need_ack){    esp_err_t ret;    uint16_t offset = 0;    if (length <= (ota_profile_tab[OTA_PROFILE_APP_IDX].mtu_size - 3)) {        ret = esp_ble_gatts_send_indicate(ota_profile_tab[OTA_PROFILE_APP_IDX].gatts_if, ota_profile_tab[OTA_PROFILE_APP_IDX].conn_id, ota_handle_table[index], length, value, need_ack);        if (ret) {            ESP_LOGE(TAG, "%s send notification fail: %s\n", __func__, esp_err_to_name(ret));            return ESP_FAIL;        }    } else {        while ((length - offset) > (ota_profile_tab[OTA_PROFILE_APP_IDX].mtu_size - 3)) {            ret = esp_ble_gatts_send_indicate(ota_profile_tab[OTA_PROFILE_APP_IDX].gatts_if, ota_profile_tab[OTA_PROFILE_APP_IDX].conn_id, ota_handle_table[index], (ota_profile_tab[OTA_PROFILE_APP_IDX].mtu_size - 3), value + offset, need_ack);            if (ret) {                ESP_LOGE(TAG, "%s send notification fail: %s\n", __func__, esp_err_to_name(ret));                return ESP_FAIL;            }            offset += (ota_profile_tab[OTA_PROFILE_APP_IDX].mtu_size - 3);        }        if ((length - offset) > 0) {            ret = esp_ble_gatts_send_indicate(ota_profile_tab[OTA_PROFILE_APP_IDX].gatts_if, ota_profile_tab[OTA_PROFILE_APP_IDX].conn_id, ota_handle_table[index], (length - offset), value + offset, need_ack);            if (ret) {                ESP_LOGE(TAG, "%s send notification fail: %s\n", __func__, esp_err_to_name(ret));                return ESP_FAIL;            }        }    }    return ESP_OK;}esp_err_t esp_ble_ota_notification_data(esp_ble_ota_char_t ota_char, uint8_t *value, uint8_t length){    esp_err_t ret = ESP_FAIL;    switch (ota_char) {    case RECV_FW_CHAR:        if (ota_notification.recv_fw_ntf_enable) {            ret = esp_ble_ota_send_indication(RECV_FW_CHAR_VAL_IDX, value, length, false);        } else {            ESP_LOGE(TAG, "notify isn't enable");        }        break;    case OTA_STATUS_CHAR:        if (ota_notification.process_bar_ntf_enable) {            ret = esp_ble_ota_send_indication(OTA_STATUS_CHAR_VAL_IDX, value, length, false);        } else {            ESP_LOGE(TAG, "notify isn't enable");        }        break;    case CMD_CHAR:        if (ota_notification.command_ntf_enable) {            ret = esp_ble_ota_send_indication(CMD_CHAR_VAL_IDX, value, length, false);        } else {            ESP_LOGE(TAG, "notify isn't enable");        }        break;    case CUS_CHAR:        if (ota_notification.customer_ntf_enable) {            ret = esp_ble_ota_send_indication(CUS_CHAR_VAL_IDX, value, length, false);        } else {            ESP_LOGE(TAG, "notify isn't enable");        }        break;    default:        ret = ESP_FAIL;        break;    }    if (ret) {        ESP_LOGE(TAG, "%s notification fail: %s\n", __func__, esp_err_to_name(ret));        return ESP_FAIL;    }    return ESP_OK;}esp_err_t esp_ble_ota_recv_fw_data_callback(esp_ble_ota_recv_fw_cb_t callback){    ota_cb_fun_t.recv_fw_cb = callback;    return ESP_OK;}esp_err_t esp_ble_ota_host_init(void){    esp_err_t ret;    ret = esp_bluedroid_init();    if (ret) {        ESP_LOGE(TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));        return ret;    }    ret = esp_bluedroid_enable();    if (ret) {        ESP_LOGE(TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));        return ret;    }    // ESP_LOGI(TAG, "ble ota Version[%d.%d.%d]\n", BLE_OTA_VER_MAJOR, BLE_OTA_VER_MINOR, BLE_OTA_VER_PATCH);    esp_ble_gatts_register_callback(gatts_event_handler);    esp_ble_gap_register_callback(gap_event_handler);    esp_ble_gatts_app_register(OTA_PROFILE_APP_IDX);    esp_ble_gatts_app_register(DIS_PROFILE_APP_IDX);    /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/    esp_ble_auth_req_t auth_req = ESP_LE_AUTH_BOND;     //bonding with peer device after authentication    esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;           //set the IO capability to No output No input    uint8_t key_size = 16;      //the key size should be 7~16 bytes    uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;    uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;    esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));    esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));    esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));    /* If your BLE device act as a Slave, the init_key means you hope which types of key of the master should distribute to you,    and the response key means which key you can distribute to the Master;    If your BLE device act as a master, the response key means you hope which types of key of the slave should distribute to you,    and the init key means which key you can distribute to the slave. */    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));    return ESP_OK;}#endif
 |