一、介绍
物联网设备中,蓝牙功能的经常搭配wifi使用。在设备首次使用阶段中,给无网络连接状态下的设备,传输wifi的连接信息和相关证书等。而s3模块就搭配了蓝牙模块,并且内置了蓝牙协议栈。
二、BluFi 简介
官网有详细的蓝牙协议的讲解,这里就不做铺开讲解。可以看看
https://docs.espressif.com/projects/esp-idf/zh_CN/release-v4.4/esp32s3/api-guides/blufi.html
本次教程参考例程的是 gatt_server,结合此例程做快速的配置和解析。蓝牙协议交互流程如下(图片引用esp官网)
三、例程解析
(一)蓝牙名称和UUID初始化
1.注销默认值service uuid 和 device name
static uint8_t raw_adv_data[] = {
/* flags */
0x02, 0x01, 0x06,
/* tx power*/
0x02, 0x0a, 0xeb,
/* service uuid */
// 0x03, 0x03, 0xFF, 0x00,
/* device name */
//0x0f, 0x09, 'E', 'S', 'P', '_', 'G', 'A', 'T', 'T', 'S', '_', 'D','E', 'M', 'O'
// 0x15, 0x09, 'X','W','_','H','_','X', '_', '2','2','0','4','2','0','_','0','0','0','0','0','2'
};
static uint8_t raw_scan_rsp_data[] = {
/* flags */
0x02, 0x01, 0x06,
/* tx power */
0x02, 0x0a, 0xeb,
/* service uuid */
// 0x03, 0x03, 0xFF,0x00
};
1.UUID设置(例程实现)
//默认值
static esp_bt_uuid_t service_uuid_main = {
.len = ESP_UUID_LEN_128,
.uuid = {.uuid128 ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBB, 0x23, 0xB1, 0x00, 0x63, 0x01, 0x00, 0x40, 0x6E},},
};
static esp_bt_uuid_t service_uuid_rx = {
.len = ESP_UUID_LEN_128,
.uuid = {.uuid128 ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBB, 0x23, 0xB1, 0x00, 0x63, 0x02, 0x00, 0x40, 0x6E},},
};
static esp_bt_uuid_t service_uuid_tx = {
.len = ESP_UUID_LEN_128,
.uuid = {.uuid128 ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBB, 0x23, 0xB1, 0x00, 0x63, 0x03, 0x00, 0x40, 0x6E},},
};
2.设置UUID的函数
void set_ble_udid(){
uint8_t baseMac[6]={0};
esp_read_mac(baseMac, ESP_MAC_WIFI_STA);//将wifi的mac设置给蓝牙,也可以自行构造
for(int i=0;i<6;i++){
service_uuid_main.uuid.uuid128[i]=mmac[i];
service_uuid_rx.uuid.uuid128[i]=mmac[i];
service_uuid_tx.uuid.uuid128[i]=mmac[i];
}
}
3.uuid和特征值生效代码(例程实现)
//
//特征值使用默认设置
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_write = ESP_GATT_CHAR_PROP_BIT_WRITE ;
//static const uint8_t char_prop_read_write_notify = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE;
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t heart_measurement_ccc[2] = {0x00, 0x00};
static const uint8_t char_value[4] = {0x11, 0x22, 0x33, 0x44};
static const esp_gatts_attr_db_t gatt_db[HRS_IDX_NB] =
{
// Service Declaration
[IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
ESP_UUID_LEN_128, ESP_UUID_LEN_128, (uint8_t *)service_uuid_main.uuid.uuid128}},
/* Characteristic Declaration */
[IDX_CHAR_B] =
{{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}},
/* Characteristic Value */
[IDX_CHAR_VAL_B] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)service_uuid_rx.uuid.uuid128, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},
/* Characteristic Declaration */
[IDX_CHAR_A] =
{{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_notify}},
/* Characteristic Value */
[IDX_CHAR_VAL_A] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)&service_uuid_tx.uuid.uuid128, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},
/* Client Characteristic Configuration Descriptor */
[IDX_CHAR_CFG_A] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},
};
4.设置蓝牙名称后传入gatts_profile_event_handler
static char ble_name[16] = {0};
void set_ble_name(){
char ble_name[16] = "test_ble";
memcpy(ble_name,ble_name,strlen(ble_name));
}
//此次代码不全,具体参考例程
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
switch (event) {
case ESP_GATTS_REG_EVT:{
..........................
esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(ble_name, strlen(ble_name)+1);
if (raw_adv_ret){
ESP_LOGE(GATTS_TABLE_TAG, "config raw adv data failed, error code = %x ", raw_adv_ret);
}
adv_config_done |= ADV_CONFIG_FLAG;
..........................
}
(二)蓝牙功能初始化
直接参考例程,设置相关模式,并打开蓝牙
void ble_init(){
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_ble_gatts_register_callback(gatts_event_handler);
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gatts register error, error code = %x", ret);
return;
}
ret = esp_ble_gap_register_callback(gap_event_handler);
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gap register error, error code = %x", ret);
return;
}
ret = esp_ble_gatts_app_register(ESP_APP_ID);
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gatts app register error, error code = %x", ret);
return;
}
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);
if (local_mtu_ret){
ESP_LOGE(GATTS_TABLE_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
}
/* 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_REQ_SC_MITM_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;
uint8_t oob_support = ESP_BLE_OOB_DISABLE;
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));
esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, 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));
}
(三)蓝牙消息发送函数
//参数在蓝牙连接成功后,在gatts_event_handler回调函数里更新
static esp_gatt_if_t ble_gatts_if = 0;
static uint16_t ble_conn_id=0xFF;//本次代码只采用notify方式发送消息
static uint16_t ble_attr_handle;
nt ble_send_msg(char *send_buf){
esp_ble_gatts_send_indicate(ble_gatts_if, ble_conn_id, ble_attr_handle,strlen(send_buf)+1, send_buf, false);
}
(四)蓝牙消息接收函数
static char ble_rec_buf[256] = {0};
static void ble_data_rec(uint8_t* data,int len){
ESP_LOGI(GATTS_TABLE_TAG,"ble_data_cb %s",data);
memcpy(ble_rec_buf,data,len);
}
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){
..............................
..............................
..............................
case ESP_GATTS_WRITE_EVT:
if (!param->write.is_prep){
..........
if (heart_rate_handle_table[IDX_CHAR_CFG_A] == param->write.handle && param->write.len == 2){
uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0];
if (descr_value == 0x0001){ // notify 建立连接,并更新连接值
ESP_LOGI(GATTS_TABLE_TAG, "notify enable");
ble_gatts_if = gatts_if;
ble_conn_id = param->write.conn_id;
ble_attr_handle = heart_rate_handle_table[IDX_CHAR_VAL_A];
}
........
}else{
ble_data_rec(param->write.value,param->write.len); //接收回调
}
/* send response when param->write.need_rsp is true*/
if (param->write.need_rsp){
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
}
}
.........................
.........................
.........................
}
(五)关闭蓝牙使用
void bledeInit()
{
esp_ble_gatts_app_unregister(ESP_APP_ID);
esp_bluedroid_disable();
esp_bluedroid_deinit();
esp_bt_controller_disable();
esp_bt_controller_deinit();
}
四、总结
以上是esp32的ble简单使用,如果是传输证书等机密信息,esp32官方还提高ble信息加密传输,有兴趣可以去官方了解一下,纯项目技术分享,更新不易,如有帮助,点赞一下。