ESP-32S做BLE透传模块日志

        本次项目是用ESP_32S做一个低功耗蓝牙BLE的透传模块,模块将扫描到的蓝牙名称以及设备地址通过USB口(串口)传出,上位机通过串口输入要连接的蓝牙名称后,模块进行连接配对,配对成功后就将USB口收到的数据通过蓝牙发送到配对端。

       硬件:ESP-32S模块,以及必要的外围电路。

      软件系统:FreeRTOS,接口代码采用乐鑫提供的ESP32模块BSP包

1、串口初始化

static void Uart_init(void)
{
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_RTS,
        .rx_flow_ctrl_thresh = 122,
    };

    //Set UART parameters
    uart_param_config(UART_NUM_0, &uart_config);
    //Set UART pins
    uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    //Install UART driver, and get the queue.
    uart_driver_install(UART_NUM_0, 4096, 8192, 10,&spp_uart_queue,0);
    xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL);
}

2、蓝牙功能初始化

void ble_client_appRegister(void)
{
    esp_err_t status;
    char err_msg[20];

    ESP_LOGI(GATTC_TAG, "register callback");

    //register the scan callback function to the gap module
    if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {
        ESP_LOGE(GATTC_TAG, "gap register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg)));
        return;
    }

    //register the callback function to the gattc module
    if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) {
        ESP_LOGE(GATTC_TAG, "gattc register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg)));
        return;
    }
    esp_ble_gattc_app_register(PROFILE_APP_ID);

    esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(200); //设置MTU最大为200
    if (local_mtu_ret){
        ESP_LOGE(GATTC_TAG, "set local  MTU failed: %s", esp_err_to_name_r(local_mtu_ret, err_msg, sizeof(err_msg)));
    }
    cmd_reg_queue = xQueueCreate(10, sizeof(uint32_t));
    xTaskCreate(spp_client_reg_task, "spp_client_reg_task", 2048, NULL, 10, NULL);

}

void BLE_init()
{
    esp_err_t ret;

    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();

    memcpy(g_BLE_name, "TestBluetooth", 13);
    nvs_flash_init();
    ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
        ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
    if (ret) {
        ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ESP_LOGI(GATTC_TAG, "%s init bluetooth\n", __func__);
    ret = esp_bluedroid_init();
    if (ret) {
        ESP_LOGE(GATTC_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }
    ret = esp_bluedroid_enable();
    if (ret) {
        ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ble_client_appRegister();
    
}

3、启动扫描

 调用ESP接口 esp_ble_gap_start_scanning(0xff);

 扫描到蓝牙设备后会触发事件 ESP_GAP_BLE_SCAN_RESULT_EVT,在事件触发时,回去扫描到的设备名称以及地址信息,通过串口将设备信息输出,

adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
if(adv_name==NULL)
adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_SHORT, &adv_name_len);
Uart_Send_ScanDevInfo(scan_result->scan_rst.bda,adv_name,adv_name_len);

4、收到上位机通过串口输入连接设备名称后,将扫描到的设备名称与目标名称进行对比,如果相符就停止扫描

if (adv_name != NULL) 
{   
     if(g_device_nameFlag && (strncmp((char *)adv_name, g_BLE_name, adv_name_len) == 0)) 
     {
          memcpy(&(scan_rst), scan_result, sizeof(esp_ble_gap_cb_param_t));
           esp_ble_gap_stop_scanning();
     }
}

停止扫描后会触发 ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT事件,在事件触发时启动连接

esp_ble_gattc_open(gl_profile_tab[PROFILE_APP_ID].gattc_if, scan_rst.scan_rst.bda, scan_rst.scan_rst.ble_addr_type, true);

5、连接成功后会触发gattc_profile_event_handler()中的 ESP_GATTC_CONNECT_EVT事件。

连接事件处理:设置数据长度

is_connect = true;
gl_profile_tab[PROFILE_APP_ID].conn_id = p_data->connect.conn_id;
memcpy(gl_profile_tab[PROFILE_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_APP_ID].remote_bda, sizeof(esp_bd_addr_t));
     
 esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req(gattc_if, spp_conn_id);
 if (mtu_ret){
     ESP_LOGE(GATTC_TAG, "config MTU error, error code = %x", mtu_ret);
 }

6、设置成功后触发ESP_GATTC_CFG_MTU_EVT事件。在此事件中获取设备信息

        if(p_data->cfg_mtu.status != ESP_OK){
            break;
        }
        ESP_LOGI(GATTC_TAG,"+MTU:%d\n", p_data->cfg_mtu.mtu);
        spp_mtu_size = p_data->cfg_mtu.mtu;
        
        spp_conn_id = p_data->connect.conn_id;
        spp_gattc_if = gattc_if;
        esp_ble_gattc_search_service(spp_gattc_if, spp_conn_id, &spp_service_uuid);

7、获取成功后触发ESP_GATTC_SEARCH_RES_EVT事件,然后设置通讯需要的队列、数据通道等,就可以进行通讯了,

8、当串口收到数据后,调用

 esp_ble_gattc_write_char( spp_gattc_if,spp_conn_id,
                           (db+SPP_IDX_SPP_DATA_RECV_VAL)->attribute_handle,
                           event.size,
                           pBuf,
                           ESP_GATT_WRITE_TYPE_RSP,
                           ESP_GATT_AUTH_REQ_NONE);

将数据传输给BLE服务端。

9、当模块收到BLE服务端的数据,会触发通知事件:ESP_GATTC_NOTIFY_EVT,在该事件出发时,调用

 notify_event_handler(p_data);将数据通过串口发送出去

static void notify_event_handler(esp_ble_gattc_cb_param_t * p_data)
{
    uint8_t handle = 0;

    if(p_data->notify.is_notify == true){
        ESP_LOGI(GATTC_TAG,"+NOTIFY:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len);
    }else{
        ESP_LOGI(GATTC_TAG,"+INDICATE:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len);
    }
    handle = p_data->notify.handle;
    if(handle == db[SPP_IDX_SPP_DATA_NTY_VAL].attribute_handle){
        if((p_data->notify.value[0] == '#')&&(p_data->notify.value[1] == '#')){   //配置数据
            if((++notify_value_count) != p_data->notify.value[3]){
                if(notify_value_p != NULL){
                    free(notify_value_p);
                }
                notify_value_count = 0;
                notify_value_p = NULL;
                notify_value_offset = 0;
                ESP_LOGE(GATTC_TAG,"notify value count is not continuous,%s\n",__func__);
                return;
            }
            if(p_data->notify.value[3] == 1){
                notify_value_p = (char *)malloc(((spp_mtu_size-7)*(p_data->notify.value[2]))*sizeof(char));
                if(notify_value_p == NULL){
                    ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
                    notify_value_count = 0;
                    return;
                }
                memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4));
                if(p_data->notify.value[2] == p_data->notify.value[3]){
                    uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
                    free(notify_value_p);
                    notify_value_p = NULL;
                    notify_value_offset = 0;
                    return;
                }
                notify_value_offset += (p_data->notify.value_len - 4);
            }else if(p_data->notify.value[3] <= p_data->notify.value[2]){
                memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4));
                if(p_data->notify.value[3] == p_data->notify.value[2]){
                    uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
                    free(notify_value_p);
                    notify_value_count = 0;
                    notify_value_p = NULL;
                    notify_value_offset = 0;
                    return;
                }
                notify_value_offset += (p_data->notify.value_len - 4);
            }
        }else{
            uart_write_bytes(UART_NUM_0, (char *)(p_data->notify.value), p_data->notify.value_len);
        }
    }else if(handle == ((db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle)){

    }else{

    }
}

大体流程就是这样的,具体数据细节处理业务就不细述了。

猜你喜欢

转载自blog.csdn.net/ggggyj/article/details/85259492