1007|2

26

帖子

2

TA的资源

一粒金砂(中级)

楼主
 

小熊派BearPi-Pico H2821星闪开发板测评(五)——BLE串口透传测试 [复制链接]

本帖最后由 FuShenxiao 于 2024-8-27 09:14 编辑

官方案例实现

官方案例两块开发板实现BLE数据传输测试,A开发板通过串口接收数据,然后通过BLE传输给B开发板,B开发板通过串口将接收到的数据打印出来;同样,B开发板通过串口接收数据,然后通过BLE传输给A开发板,A开发板通过串口将接收到的数据打印出来。在测试中需要一块开发板做为Server端,另外一块开发板做为Client端,两块开发板配对后即可互发消息。连接方式如下

 

配置BLE UART Server

选择BLE UART Server样例

 

 

选择协议

 

 

完成配置,退出配置环境进行编译

配置BLE UART Client

选择BLE UART Client样例

 

选择协议

 

完成配置,退出配置环境进行编译

Server初始化

首先进行SDK初始化

 

初始化并启动BLE任务

 

配置并启动ADV,最终开启BLE服务

 

Client初始化

首先进行SDK初始化

 

交换mtu信息,并与Server建立联系

 

Client发现特征

 

Client发现特征描述符

 

Client收到读响应

 

Client初始化完成后Server的日志显示

可以看到mtu交换

 

发送测试

Server发送Client接收

 

Client发送Server接收

 

代码实现

ble_uart_server代码

#include "osal_addr.h"
#include "osal_debug.h"
#include "product.h"
#include "securec.h"
#include "errcode.h"
#include "uart.h"
#include "bts_def.h"
#include "bts_device_manager.h"
#include "bts_gatt_stru.h"
#include "bts_gatt_server.h"
#include "bts_le_gap.h"
#include "ble_uart_server_adv.h"
#include "ble_uart_server.h"

/* uart gatt server id */
#define BLE_UART_SERVER_ID 			1
/* uart ble connect id */
#define BLE_SINGLE_LINK_CONNECT_ID 	1
/* octets of 16 bits uart */
#define UART16_LEN 					2
/* invalid attribute handle */
#define INVALID_ATT_HDL 			0
/* invalid server ID */
#define INVALID_SERVER_ID 			0

#define BLE_UART_SERVER_LOG "[ble uart server]"
#define BLE_UART_SERVER_ERROR "[ble uart server error]"
#define BLE_UART_SERVICE_NUM 3

static uint16_t g_ble_uart_conn_id;
static uint8_t g_ble_uart_name_value[] = { 'b', 'l', 'e', '_', 'u', 'a', 'r', 't', '\0' };
static uint8_t g_uart_server_app_uuid[] = { 0x00, 0x00 };
static uint8_t g_ble_uart_server_addr[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
static uint8_t g_server_id = INVALID_SERVER_ID;
static uint8_t g_connection_state = 0;
static uint16_t g_notify_indicate_handle = 0;
static uint8_t g_service_num = 0;

/* 将uint16的uuid数字转化为bt_uuid_t */
static void bts_data_to_uuid_len2(uint16_t uuid_data, bt_uuid_t *out_uuid)
{
    out_uuid->uuid_len = UART16_LEN;
    out_uuid->uuid[0] = (uint8_t)(uuid_data >> 8); /* 8: octet bit num */
    out_uuid->uuid[1] = (uint8_t)(uuid_data);
}

/* 设置注册服务时的name */
void ble_uart_set_device_name_value(const uint8_t *name, const uint8_t len)
{
    size_t len_name = sizeof(g_ble_uart_name_value);
    if (memcpy_s(g_ble_uart_name_value, len_name, name, len) != EOK) {
        osal_printk("%s memcpy name fail\n", BLE_UART_SERVER_ERROR);
    }
}

/* 创建服务 */
static void ble_uart_add_service(void)
{
    bt_uuid_t uart_service_uuid = { 0 };
    bts_data_to_uuid_len2(BLE_UART_UUID_SERVER_SERVICE, &uart_service_uuid);
    gatts_add_service(BLE_UART_SERVER_ID, &uart_service_uuid, true);
}

/* 添加uart发送服务的所有特征和描述符 */
static void ble_uart_add_tx_characters_and_descriptors(uint8_t server_id, uint16_t srvc_handle)
{
    osal_printk("%s TX characters:%d srv_handle:%d \n", BLE_UART_SERVER_LOG, server_id, srvc_handle);
    bt_uuid_t characters_uuid = { 0 };
    uint8_t characters_value[] = { 0x12, 0x34 };
    bts_data_to_uuid_len2(BLE_UART_CHARACTERISTIC_UUID_TX, &characters_uuid);
    gatts_add_chara_info_t character;
    character.chara_uuid = characters_uuid;
    character.properties = GATT_CHARACTER_PROPERTY_BIT_NOTIFY | GATT_CHARACTER_PROPERTY_BIT_READ;
    character.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE;
    character.value_len = sizeof(characters_value);
    character.value = characters_value;
    gatts_add_characteristic(server_id, srvc_handle, &character);
    osal_printk("%s characters_uuid:%2x %2x\n", BLE_UART_SERVER_LOG, characters_uuid.uuid[0], characters_uuid.uuid[1]);

    static uint8_t ccc_val[] = { 0x01, 0x00 }; // notify
    bt_uuid_t ccc_uuid = { 0 };
    bts_data_to_uuid_len2(BLE_UART_CLIENT_CHARACTERISTIC_CONFIGURATION, &ccc_uuid);
    gatts_add_desc_info_t descriptor;
    descriptor.desc_uuid = ccc_uuid;
    descriptor.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_CHARACTER_PROPERTY_BIT_WRITE |
        GATT_ATTRIBUTE_PERMISSION_WRITE;
    descriptor.value_len = sizeof(ccc_val);
    descriptor.value = ccc_val;
    gatts_add_descriptor(server_id, srvc_handle, &descriptor);
    osal_printk("%s ccc_uuid:%2x %2x\n", BLE_UART_SERVER_LOG, characters_uuid.uuid[0], characters_uuid.uuid[1]);
}

/* 添加uart接收服务的所有特征和描述符 */
static void ble_uart_add_rx_characters_and_descriptors(uint8_t server_id, uint16_t srvc_handle)
{
    osal_printk("%s RX characters:%d srv_handle: %d \n", BLE_UART_SERVER_LOG, server_id, srvc_handle);
    bt_uuid_t characters_uuid = { 0 };
    uint8_t characters_value[] = { 0x12, 0x34 };
    bts_data_to_uuid_len2(BLE_UART_CHARACTERISTIC_UUID_RX, &characters_uuid);
    gatts_add_chara_info_t character;
    character.chara_uuid = characters_uuid;
    character.properties = GATT_CHARACTER_PROPERTY_BIT_READ | GATT_CHARACTER_PROPERTY_BIT_WRITE_NO_RSP;
    character.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE;
    character.value_len = sizeof(characters_value);
    character.value = characters_value;
    gatts_add_characteristic(server_id, srvc_handle, &character);
    osal_printk("%s characters_uuid:%2x %2x\n", BLE_UART_SERVER_LOG, characters_uuid.uuid[0], characters_uuid.uuid[1]);

    bt_uuid_t ccc_uuid = { 0 };
    /* uart client characteristic configuration value for test */
    static uint8_t ccc_val[] = { 0x00, 0x00 };
    bts_data_to_uuid_len2(BLE_UART_CLIENT_CHARACTERISTIC_CONFIGURATION, &ccc_uuid);
    gatts_add_desc_info_t descriptor;
    descriptor.desc_uuid = ccc_uuid;
    descriptor.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE;
    descriptor.value_len = sizeof(ccc_val);
    descriptor.value = ccc_val;
    gatts_add_descriptor(server_id, srvc_handle, &descriptor);
    osal_printk("%s ccc_uuid:%2x %2x\n", BLE_UART_SERVER_LOG, characters_uuid.uuid[0], characters_uuid.uuid[1]);
}

bool bts_uart_compare_uuid(bt_uuid_t *uuid1, bt_uuid_t *uuid2)
{
    if (uuid1->uuid_len != uuid2->uuid_len) {
        return false;
    }
    if (memcmp(uuid1->uuid, uuid2->uuid, uuid1->uuid_len) != 0) {
        return false;
    }
    return true;
}

/* 服务添加回调 */
static void ble_uart_server_service_add_cbk(uint8_t server_id, bt_uuid_t *uuid, uint16_t handle, errcode_t status)
{
    osal_printk("%s add characters_and_descriptors cbk service:%d, srv_handle:%d, uuid_len:%d, status:%d, uuid:",
                BLE_UART_SERVER_LOG, server_id, handle, uuid->uuid_len, status);
    for (int8_t i = 0; i < uuid->uuid_len; i++) {
        osal_printk("%02x ", uuid->uuid[i]);
    }
    osal_printk("\n");
    ble_uart_add_tx_characters_and_descriptors(server_id, handle);
    ble_uart_add_rx_characters_and_descriptors(server_id, handle);
    gatts_start_service(server_id, handle);
}

/* 特征添加回调 */
static void ble_uart_server_characteristic_add_cbk(uint8_t server_id, bt_uuid_t *uuid, uint16_t service_handle,
                                                   gatts_add_character_result_t *result, errcode_t status)
{
    osal_printk("%s add character cbk service:%d service_hdl: %d char_hdl: %d char_val_hdl: %d uuid_len: %d \n",
                BLE_UART_SERVER_LOG, server_id, service_handle, result->handle, result->value_handle, uuid->uuid_len);
    osal_printk("uuid:");
    for (int8_t i = 0; i < uuid->uuid_len; i++) {
        osal_printk("%02x ", uuid->uuid[i]);
    }
    bt_uuid_t characters_cbk_uuid = { 0 };
    bts_data_to_uuid_len2(BLE_UART_CHARACTERISTIC_UUID_TX, &characters_cbk_uuid);
    characters_cbk_uuid.uuid_len = uuid->uuid_len;
    if (bts_uart_compare_uuid(uuid, &characters_cbk_uuid)) {
        g_notify_indicate_handle = result->value_handle;
    }
    osal_printk("%s status:%d indicate_handle:%d\n", BLE_UART_SERVER_LOG, status, g_notify_indicate_handle);
}

/* 描述符添加回调 */
static void ble_uart_server_descriptor_add_cbk(uint8_t server_id, bt_uuid_t *uuid, uint16_t service_handle,
                                               uint16_t handle, errcode_t status)
{
    osal_printk("%s service:%d service_hdl: %d desc_hdl: %d uuid_len: %d \n",
                BLE_UART_SERVER_LOG, server_id, service_handle, handle, uuid->uuid_len);
    osal_printk("uuid:");
    for (int8_t i = 0; i < uuid->uuid_len; i++) {
        osal_printk("%02x ", (uint8_t)uuid->uuid[i]);
    }
    osal_printk("%s status:%d\n", BLE_UART_SERVER_LOG, status);
}

/* 开始服务回调 */
static void ble_uart_server_service_start_cbk(uint8_t server_id, uint16_t handle, errcode_t status)
{
    g_service_num++;
    if ((g_service_num == BLE_UART_SERVICE_NUM) && (status == 0)) {
        osal_printk("%s start service cbk , start adv\n", BLE_UART_SERVER_LOG);
        ble_uart_set_adv_data();
        ble_uart_start_adv();
    }
    osal_printk("%s start service:%2d service_hdl: %d status: %d\n",
                BLE_UART_SERVER_LOG, server_id, handle, status);
}

static void ble_uart_receive_write_req_cbk(uint8_t server_id, uint16_t conn_id, gatts_req_write_cb_t *write_cb_para,
                                           errcode_t status)
{
    osal_printk("%s ble uart write cbk server_id:%d, conn_id:%d, status%d\n",
        BLE_UART_SERVER_LOG, server_id, conn_id, status);
    osal_printk("%s ble uart write cbk len:%d, data:%s\n",
                BLE_UART_SERVER_LOG, write_cb_para->length, write_cb_para->value);
    if ((write_cb_para->length > 0) && write_cb_para->value) {
        uapi_uart_write(CONFIG_BLE_UART_BUS, (uint8_t *)(write_cb_para->value), write_cb_para->length, 0);
    }
}

static void ble_uart_receive_read_req_cbk(uint8_t server_id, uint16_t conn_id, gatts_req_read_cb_t *read_cb_para,
    errcode_t status)
{
    osal_printk("%s ReceiveReadReq--server_id:%d conn_id:%d\n", BLE_UART_SERVER_LOG, server_id, conn_id);
    osal_printk("%s request_id:%d, att_handle:%d offset:%d, need_rsp:%d, is_long:%d\n",
                BLE_UART_SERVER_LOG, read_cb_para->request_id, read_cb_para->handle, read_cb_para->offset,
                read_cb_para->need_rsp, read_cb_para->is_long);
    osal_printk("%s status:%d\n", BLE_UART_SERVER_LOG, status);
}

static void ble_uart_mtu_changed_cbk(uint8_t server_id, uint16_t conn_id, uint16_t mtu_size, errcode_t status)
{
    osal_printk("%s MtuChanged--server_id:%d conn_id:%d\n", BLE_UART_SERVER_LOG, server_id, conn_id);
    osal_printk("%s mtusize:%d, status:%d\n", BLE_UART_SERVER_LOG, mtu_size, status);
}

static void ble_uart_server_adv_enable_cbk(uint8_t adv_id, adv_status_t status)
{
    osal_printk("%s adv enable cbk adv_id:%d status:%d\n", BLE_UART_SERVER_LOG, adv_id, status);
}

static void ble_uart_server_adv_disable_cbk(uint8_t adv_id, adv_status_t status)
{
    osal_printk("%s adv disable adv_id: %d, status:%d\n", BLE_UART_SERVER_LOG, adv_id, status);
}

void ble_uart_server_connect_change_cbk(uint16_t conn_id, bd_addr_t *addr, gap_ble_conn_state_t conn_state,
                                        gap_ble_pair_state_t pair_state, gap_ble_disc_reason_t disc_reason)
{
    g_ble_uart_conn_id = conn_id;
    g_connection_state = (uint8_t)conn_state;
    osal_printk("%s connect state change conn_id: %d, status: %d, pair_status:%d, addr %x disc_reason %x\n",
                BLE_UART_SERVER_LOG, conn_id, conn_state, pair_state, addr[0], disc_reason);
    if (conn_state == GAP_BLE_STATE_CONNECTED) {
        return;
    } else if (conn_state == GAP_BLE_STATE_DISCONNECTED) {
        ble_uart_set_adv_data();
        ble_uart_start_adv();
    }
}
void ble_uart_server_pair_result_cb(uint16_t conn_id, const bd_addr_t *addr, errcode_t status)
{
    osal_printk("%s pair result conn_id: %d, status: %d, addr %x \n",
                BLE_UART_SERVER_LOG, conn_id, status, addr[0]);
}

void ble_uart_server_power_on_cbk(uint8_t status)
{
    osal_printk("ble power on: %d\n", status);
    enable_ble();
}

void ble_uart_server_enable_cbk(uint8_t status)
{
    osal_printk("ble enable: %d\n", status);
    errcode_t ret = 0;
    bt_uuid_t app_uuid = { 0 };
    bd_addr_t ble_addr = { 0 };
    app_uuid.uuid_len = sizeof(g_uart_server_app_uuid);
    if (memcpy_s(app_uuid.uuid, app_uuid.uuid_len, g_uart_server_app_uuid, sizeof(g_uart_server_app_uuid)) != EOK) {
        osal_printk("%s add server app uuid memcpy failed\n", BLE_UART_SERVER_ERROR);
        return;
    }
    ble_addr.type = BLE_PUBLIC_DEVICE_ADDRESS;
    if (memcpy_s(ble_addr.addr, BD_ADDR_LEN, g_ble_uart_server_addr, sizeof(g_ble_uart_server_addr)) != EOK) {
        osal_printk("%s add server app addr memcpy failed\n", BLE_UART_SERVER_ERROR);
        return;
    }
    gap_ble_set_local_name(g_ble_uart_name_value, sizeof(g_ble_uart_name_value));
    gap_ble_set_local_addr(&ble_addr);
    ret = gatts_register_server(&app_uuid, &g_server_id);
    if ((ret != ERRCODE_BT_SUCCESS) || (g_server_id == INVALID_SERVER_ID)) {
        osal_printk("%s add server failed\r\n", BLE_UART_SERVER_ERROR);
        return;
    }
    ble_uart_add_service(); /* 添加uart服务 */
    osal_printk("%s beginning add service\r\n", BLE_UART_SERVER_LOG);
    bth_ota_init();
}

static errcode_t ble_uart_server_register_callbacks(void)
{
    bts_dev_manager_callbacks_t dev_mgr_cb = { 0 };
    gap_ble_callbacks_t gap_cb = { 0 };
    gatts_callbacks_t service_cb = { 0 };

    dev_mgr_cb.power_on_cb = ble_uart_server_power_on_cbk;
    dev_mgr_cb.ble_enable_cb = ble_uart_server_enable_cbk;
    gap_cb.start_adv_cb = ble_uart_server_adv_enable_cbk;
    gap_cb.conn_state_change_cb = ble_uart_server_connect_change_cbk;
    gap_cb.stop_adv_cb = ble_uart_server_adv_disable_cbk;
    gap_cb.pair_result_cb = ble_uart_server_pair_result_cb;
    errcode_t ret = gap_ble_register_callbacks(&gap_cb);
    ret |= bts_dev_manager_register_callbacks(&dev_mgr_cb);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s reg gap cbk failed ret = %d\n", BLE_UART_SERVER_ERROR, ret);
        return ret;
    }

    service_cb.add_service_cb = ble_uart_server_service_add_cbk;
    service_cb.add_characteristic_cb = ble_uart_server_characteristic_add_cbk;
    service_cb.add_descriptor_cb = ble_uart_server_descriptor_add_cbk;
    service_cb.start_service_cb = ble_uart_server_service_start_cbk;
    service_cb.read_request_cb = ble_uart_receive_read_req_cbk;
    service_cb.write_request_cb = ble_uart_receive_write_req_cbk;
    service_cb.mtu_changed_cb = ble_uart_mtu_changed_cbk;
    ret = gatts_register_callbacks(&service_cb);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s reg service cbk failed ret = %d\n", BLE_UART_SERVER_ERROR, ret);
        return ret;
    }
#if (CORE_NUMS < 2)
    enable_ble();
#endif
    return ret;
}

void ble_uart_server_init(void)
{
    ble_uart_server_register_callbacks();
}

/* device向host发送数据:input report */
errcode_t ble_uart_server_send_input_report(uint8_t *data, uint16_t len)
{
    gatts_ntf_ind_t param = { 0 };
    uint16_t conn_id = g_ble_uart_conn_id;
    param.attr_handle = g_notify_indicate_handle;
    param.value_len = len;
    param.value = data;
    osal_printk("%s send input report indicate_handle:%d\n", BLE_UART_SERVER_LOG, g_notify_indicate_handle);
    gatts_notify_indicate(BLE_UART_SERVER_ID, conn_id, ¶m);
    return ERRCODE_BT_SUCCESS;
}

uint8_t ble_uart_get_connection_state(void)
{
    return g_connection_state;
}

ble_uart_server_adv代码

#include "osal_addr.h"
#include "securec.h"
#include "errcode.h"
#include "osal_debug.h"
#include "bts_def.h"
#include "bts_le_gap.h"
#include "ble_uart_server_adv.h"


/* Ble Adv type Flag length */
#define BLE_ADV_FLAG_LEN 0x03
/* Ble Adv data length */
#define BLE_GENERAL_BYTE_1 1
/* Ble Adv appearance length */
#define BLE_ADV_APPEARANCE_LENGTH 4
/* Ble Adv appearance type */
#define BLE_ADV_APPEARANCE_DATA_TYPE 0x19
/* Ble uart appearance type */
#define BLE_ADV_CATEGORY_UART_VALUE 0x0080
/* Ble uart categorylength */
#define BLE_ADV_CATEGORY_LEN 2
/* Ble name adv param type length */
#define BLE_ADV_PARAM_DATATYPE_LENGTH 1
/* Ble name adv name type */
#define BLE_ADV_LOCAL_NAME_DATA_TYPE 0x09
/* Ble name adv tx power type */
#define BLE_ADV_TX_POWER_LEVEL       0x0A
/* Ble name adv tx power response type */
#define BLE_SCAN_RSP_TX_POWER_LEVEL_LEN 0x03
/* Ble adv flag data */
#define BLE_ADV_FLAG_DATA 0x05

/* Ble adv min interval */
#define BLE_ADV_MIN_INTERVAL 0x30
/* Ble adv max interval */
#define BLE_ADV_MAX_INTERVAL 0x60
/* Ble adv handle */
#define BTH_GAP_BLE_ADV_HANDLE_DEFAULT 0x01
/* Ble adv duration */
#define BTH_GAP_BLE_ADV_FOREVER_DURATION 0

#define MAX_NAME_LENGTH 15
#define EXT_ADV_OR_SCAN_RSP_DATA_LEN 251
#define ADV_APPEA_CATOGORY_HIGH 8

#define BLE_UART_ADV_LOG "[ble uart adv]"

typedef enum ble_adv_filter_policy {
    BLE_ADV_FILTER_POLICY_SCAN_ANY_CONNECT_ANY =                     0x00,
    BLE_ADV_FILTER_POLICY_SCAN_WHITE_LIST_CONNECT_ANY =              0x01,
    BLE_ADV_FILTER_POLICY_SCAN_ANY_CONNECT_WHITE_LIST =              0x02,
    BLE_ADV_FILTER_POLICY_SCAN_WHITE_LIST_CONNECT_WHITE_LIST =       0x03
} ble_adv_filter_policy_t;

typedef enum ble_adverting_type {
    BLE_ADV_TYPE_CONNECTABLE_UNDIRECTED =                            0x00,
    BLE_ADV_TYPE_CONNECTABLE_HIGH_DUTY_CYCLE_DIRECTED =              0x01,
    BLE_ADV_TYPE_SCANNABLE_UNDIRECTED =                              0x02,
    BLE_ADV_TYPE_NON_CONNECTABLE_UNDIRECTED =                        0x03,
    BLE_ADV_TYPE_CONNECTABLE_LOW_DUTY_CYCLE_DIRECTED =               0x04
} ble_adverting_type_t;

typedef enum ble_adv_channel_map {
    BLE_ADV_CHANNEL_MAP_CH_37 =                      0x01,
    BLE_ADV_CHANNEL_MAP_CH_38 =                      0x02,
    BLE_ADV_CHANNEL_MAP_CH_39 =                      0x04,
    BLE_ADV_CHANNEL_MAP_CH_37_CH_38 =                0x03,
    BLE_ADV_CHANNEL_MAP_CH_37_CH_39 =                0x05,
    BLE_ADV_CHANNEL_MAP_CH_38_CH_39 =                0x06,
    BLE_ADV_CHANNEL_MAP_CH_DEFAULT =                 0x07
} ble_adv_channel_map_t;

typedef struct {
    uint8_t length;             /* 广播数据类型长度 */
    uint8_t adv_data_type;      /* 广播数据类型 */
    uint8_t flags;              /* 广播数据标志 */
} ble_adv_flag;

typedef struct {
    uint8_t length;                             /* 设备外观数据类型长度 */
    uint8_t adv_data_type;                      /* 设备外观数据类型 */
    uint8_t catogory_id[BLE_ADV_CATEGORY_LEN];  /* 设备外观数据 */
} ble_appearance_t;

typedef struct {
    uint8_t length;             /* 广播设备名称类型长度 */
    uint8_t adv_data_type;      /* 设备名称类型 */
    int8_t *name;               /* 设备名称数据指针 */
} ble_local_name_t;

typedef struct {
    uint8_t length;             /* 广播发送功率长度 */
    uint8_t adv_data_type;      /* 广播发送数据类型 */
    uint8_t tx_power_value;     /* 广播发送数据 */
} ble_tx_power_level_t;

uint8_t g_uart_local_name[ MAX_NAME_LENGTH] = { 'b', 'l', 'e', '_', 'u', 'a', 'r', 't', '_', 's',
    'e', 'r', 'v', 'e', 'r' };

static inline uint8_t u16_low_u8(uint16_t val)
{
    return (uint8_t)((uint16_t)(val) & 0xff);
}

static inline uint8_t u16_high_u8(uint16_t val)
{
    return (uint8_t)(((uint16_t)(val) >> ADV_APPEA_CATOGORY_HIGH) & 0xff);
}

static uint8_t ble_set_adv_flag_data(uint8_t *set_adv_data_position, uint8_t max_len)
{
    ble_adv_flag adv_flags = {
        .length = BLE_ADV_FLAG_LEN - BLE_GENERAL_BYTE_1,
        .adv_data_type = 1,
        .flags = BLE_ADV_FLAG_DATA
    };
    if (memcpy_s(set_adv_data_position, max_len, &adv_flags, BLE_ADV_FLAG_LEN) != EOK) {
        return 0;
    }
    return BLE_ADV_FLAG_LEN;
}

static uint8_t ble_set_adv_appearance(uint8_t *set_adv_data_position, uint8_t max_len)
{
    ble_appearance_t adv_appearance_data = {
        .length = BLE_ADV_APPEARANCE_LENGTH - BLE_GENERAL_BYTE_1,
        .adv_data_type = BLE_ADV_APPEARANCE_DATA_TYPE,
        .catogory_id = { u16_low_u8(BLE_ADV_CATEGORY_UART_VALUE), u16_high_u8(BLE_ADV_CATEGORY_UART_VALUE) }
    };
    if (memcpy_s(set_adv_data_position, max_len, &adv_appearance_data, BLE_ADV_APPEARANCE_LENGTH) != EOK) {
        return 0;
    }
    return BLE_ADV_APPEARANCE_LENGTH;
}

static uint8_t ble_set_adv_name(uint8_t *set_adv_data_position, uint8_t max_len)
{
    uint8_t len = BLE_ADV_PARAM_DATATYPE_LENGTH + BLE_ADV_PARAM_DATATYPE_LENGTH;
    ble_local_name_t adv_local_name_data = {
        .length = (uint8_t)(BLE_ADV_PARAM_DATATYPE_LENGTH + sizeof(g_uart_local_name)),
        .adv_data_type = BLE_ADV_LOCAL_NAME_DATA_TYPE
    };

    if (memcpy_s(set_adv_data_position, max_len, &adv_local_name_data, len) != EOK) {
        return 0;
    }
    if (memcpy_s((set_adv_data_position+len), (size_t)(max_len-len),
                 g_uart_local_name, sizeof(g_uart_local_name)) != EOK) {
        return 0;
    }
    len = (uint8_t)(len + sizeof(g_uart_local_name));
    return len;
}

static uint8_t ble_set_adv_appearance_data(uint8_t *set_adv_data_position, uint8_t max_len)
{
    uint8_t idx = 0;

    idx += ble_set_adv_appearance(set_adv_data_position, max_len);
    idx += ble_set_adv_name(set_adv_data_position + idx, (max_len - idx));
    return idx;
}

static uint16_t ble_uart_server_set_adv_data(uint8_t *set_adv_data, uint8_t adv_data_max_len)
{
    uint8_t idx = 0;

    if ((set_adv_data == NULL) || (adv_data_max_len == 0)) {
        return 0;
    }

    idx += ble_set_adv_flag_data(set_adv_data, adv_data_max_len);
    idx += ble_set_adv_appearance_data(&set_adv_data[idx], adv_data_max_len - idx);
    return idx;
}

static uint16_t ble_set_scan_response_data(uint8_t *scan_rsp_data, uint8_t scan_rsp_data_max_len)
{
    uint8_t idx = 0;

    if (scan_rsp_data == NULL || scan_rsp_data_max_len == 0) {
        return 0;
    }

    /* tx power level */
    ble_tx_power_level_t tx_power_level = {
        .length = BLE_SCAN_RSP_TX_POWER_LEVEL_LEN - BLE_GENERAL_BYTE_1,
        .adv_data_type = BLE_ADV_TX_POWER_LEVEL,
        .tx_power_value = 0
    };

    if (memcpy_s(scan_rsp_data, scan_rsp_data_max_len, &tx_power_level, sizeof(ble_tx_power_level_t)) != EOK) {
        return 0;
    }

    idx += BLE_SCAN_RSP_TX_POWER_LEVEL_LEN;

    /* set local name */
    scan_rsp_data[idx++] = sizeof(g_uart_local_name) + BLE_GENERAL_BYTE_1;
    scan_rsp_data[idx++] = BLE_ADV_LOCAL_NAME_DATA_TYPE;
    if ((idx + sizeof(g_uart_local_name)) > scan_rsp_data_max_len) {
        return 0;
    }
    if (memcpy_s(&scan_rsp_data[idx], scan_rsp_data_max_len - idx, g_uart_local_name,
                 sizeof(g_uart_local_name)) != EOK) {
        return 0;
    }
    idx += sizeof(g_uart_local_name);
    return idx;
}

uint8_t ble_uart_set_adv_data(void)
{
    uint8_t set_adv_data[EXT_ADV_OR_SCAN_RSP_DATA_LEN] = { 0 };
    uint8_t set_scan_rsp_data[EXT_ADV_OR_SCAN_RSP_DATA_LEN] = { 0 };
    gap_ble_config_adv_data_t cfg_adv_data;

    /* set adv data */
    uint16_t adv_data_len = ble_uart_server_set_adv_data(set_adv_data, EXT_ADV_OR_SCAN_RSP_DATA_LEN);
    if ((adv_data_len > EXT_ADV_OR_SCAN_RSP_DATA_LEN) || (adv_data_len == 0)) {
        return 0;
    }
    /* set scan response data */
    uint16_t scan_rsp_data_len = ble_set_scan_response_data(set_scan_rsp_data, EXT_ADV_OR_SCAN_RSP_DATA_LEN);
    if ((scan_rsp_data_len > EXT_ADV_OR_SCAN_RSP_DATA_LEN) || (scan_rsp_data_len == 0)) {
        return 0;
    }
    cfg_adv_data.adv_data = set_adv_data;
    cfg_adv_data.adv_length = adv_data_len;

    cfg_adv_data.scan_rsp_data = set_scan_rsp_data;
    cfg_adv_data.scan_rsp_length = scan_rsp_data_len;
    osal_printk("%s ble_uart_set_adv_data adv_handle %d, len:%d, data:%s\n",
                BLE_UART_ADV_LOG, BTH_GAP_BLE_ADV_HANDLE_DEFAULT, adv_data_len, set_adv_data);
    return gap_ble_set_adv_data(BTH_GAP_BLE_ADV_HANDLE_DEFAULT, &cfg_adv_data);
}

uint8_t ble_uart_start_adv(void)
{
    errcode_t ret = ERRCODE_BT_SUCCESS;
    int adv_id = BTH_GAP_BLE_ADV_HANDLE_DEFAULT;

    gap_ble_adv_params_t adv_para = {
        .min_interval = BLE_ADV_MIN_INTERVAL,
        .max_interval = BLE_ADV_MAX_INTERVAL,
        .duration = BTH_GAP_BLE_ADV_FOREVER_DURATION,
        .peer_addr.type = BLE_PUBLIC_DEVICE_ADDRESS,
        /* 广播通道选择bitMap, 可参考BleAdvChannelMap */
        .channel_map = BLE_ADV_CHANNEL_MAP_CH_DEFAULT,
        .adv_type = BLE_ADV_TYPE_CONNECTABLE_UNDIRECTED,
        .adv_filter_policy = BLE_ADV_FILTER_POLICY_SCAN_ANY_CONNECT_ANY
    };

    (void)memset_s(&adv_para.peer_addr.addr, BD_ADDR_LEN, 0, BD_ADDR_LEN);
    osal_printk("%s ble_uart_start_adv adv_id %d\n", BLE_UART_ADV_LOG, adv_id);
    ret |= gap_ble_set_adv_param(adv_id, &adv_para);
    ret |= gap_ble_start_adv(adv_id);
    return ret;
}

ble_uart_client代码

#include "securec.h"
#include "product.h"
#include "osal_debug.h"
#include "osal_addr.h"
#include "uart.h"
#include "bts_le_gap.h"
#include "bts_device_manager.h"
#include "bts_gatt_client.h"
#include "ble_uart_client_scan.h"
#include "ble_uart_client.h"

#define UUID16_LEN 2
/* Characteristic UUID */
#define BLE_UART_CHARACTER_CLIENT_UUID_TX                  0xEFEF
#define BLE_UART_CLIENT_LOG "[ble uart client]"
#define BLE_UART_CLIENT_ERROR "[ble uart client error]"

/* client id, invalid client id is "0" */
static uint8_t g_uart_client_id = 0;
/* connection id, invalid client id is "0" */
static uint16_t g_uart_conn_id = 0;
/* max transport unit, default is 100 */
static uint16_t g_uart_mtu = 100;
/* characteristic handle */
static uint16_t g_ble_uart_chara_hanle_write_value = 0;

/* uart client app uuid for test */
static bt_uuid_t g_client_app_uuid = { UUID16_LEN, { 0 } };

/* server address for client connect */
static uint8_t g_ble_server_addr_connect[] = { 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 };

static void bts_data_to_uuid_len2(uint16_t uuid_data, bt_uuid_t *out_uuid)
{
    out_uuid->uuid_len = UUID16_LEN;
    out_uuid->uuid[0] = (uint8_t)(uuid_data >> 8); /* 8: octet bit num */
    out_uuid->uuid[1] = (uint8_t)(uuid_data);
}

/* ble client discover all service */
errcode_t ble_uart_client_discover_all_service(uint16_t conn_id)
{
    bt_uuid_t service_uuid = { 0 }; /* uuid length is zero, discover all service */
    return gattc_discovery_service(g_uart_client_id, conn_id, &service_uuid);
}

/* ble client write data to server */
errcode_t ble_uart_client_write_cmd(uint8_t *data, uint16_t len, uint16_t handle)
{
    gattc_handle_value_t uart_handle_value = { 0 };
    uart_handle_value.handle = handle;
    uart_handle_value.data_len = len;
    uart_handle_value.data = data;
    osal_printk("%s ble_uart_client_write_cmd len: %d, g_uart_client_id: %x\n",
                BLE_UART_CLIENT_LOG, len, g_uart_client_id);
    for (uint16_t i = 0; i < len; i++) {
        osal_printk("%02x", data[i]);
    }
    osal_printk("\n");
    errcode_t ret = gattc_write_cmd(g_uart_client_id, g_uart_conn_id, &uart_handle_value);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s gattc_write_cmd failed\n", BLE_UART_CLIENT_LOG);
        return ERRCODE_BT_FAIL;
    }
    return ERRCODE_BT_SUCCESS;
}

/* ble client set scan param callback */
void ble_uart_client_set_scan_param_cbk(errcode_t status)
{
    osal_printk("%s set scan param status: %d\n", BLE_UART_CLIENT_LOG, status);
    gap_ble_remove_all_pairs();
    ble_uart_start_scan();
}

/* ble client scan result callback */
void ble_uart_client_scan_result_cbk(gap_scan_result_data_t *scan_result_data)
{
    if (memcmp(g_ble_server_addr_connect, scan_result_data->addr.addr, sizeof(g_ble_server_addr_connect)) == 0) {
        gap_ble_stop_scan();
        osal_printk("\naddr:");
        for (uint8_t i = 0; i < BD_ADDR_LEN; i++) {
            osal_printk(" %02x: ", scan_result_data->addr.addr[i]);
        }
        bd_addr_t bt_uart_client_addr = { 0 };
        bt_uart_client_addr.type = scan_result_data->addr.type;
        if (memcpy_s(bt_uart_client_addr.addr, BD_ADDR_LEN, scan_result_data->addr.addr, BD_ADDR_LEN) != EOK) {
            osal_printk("%s add server app addr memcpy failed\r\n", BLE_UART_CLIENT_ERROR);
            return;
        }
        gap_ble_connect_remote_device(&bt_uart_client_addr);
    }
}

/* ble client connect state change callback */
void ble_uart_client_connect_change_cbk(uint16_t conn_id, bd_addr_t *addr, gap_ble_conn_state_t conn_state,
                                        gap_ble_pair_state_t pair_state, gap_ble_disc_reason_t disc_reason)
{
    bd_addr_t bt_uart_client_addr = { 0 };
    bt_uart_client_addr.type = addr->type;
    g_uart_conn_id = conn_id;
    if (memcpy_s(bt_uart_client_addr.addr, BD_ADDR_LEN, addr->addr, BD_ADDR_LEN) != EOK) {
        osal_printk("%s add server app addr memcpy failed\r\n", BLE_UART_CLIENT_ERROR);
        return;
    }
    osal_printk("%s connect state change conn_id: %d, status: %d, pair_status:%d, disc_reason %x\n",
                BLE_UART_CLIENT_LOG, conn_id, conn_state, pair_state, disc_reason);

    if (conn_state == GAP_BLE_STATE_CONNECTED  &&  pair_state == GAP_BLE_PAIR_NONE) {
        osal_printk("%s connect change cbk conn_id =%d \n", BLE_UART_CLIENT_LOG, conn_id);
        gattc_exchange_mtu_req(g_uart_client_id, g_uart_conn_id, g_uart_mtu);
    } else if (conn_state == GAP_BLE_STATE_DISCONNECTED) {
        osal_printk("%s connect change cbk conn disconnected \n", BLE_UART_CLIENT_LOG);
        ble_uart_start_scan();
        return;
    }
}

/* ble client pair result callback */
void ble_uart_client_pair_result_cb(uint16_t conn_id, const bd_addr_t *addr, errcode_t status)
{
    osal_printk("%s pair result conn_id: %d,status: %d \n", BLE_UART_CLIENT_LOG, conn_id, status);
    osal_printk("addr:\n");
    for (uint8_t i = 0; i < BD_ADDR_LEN; i++) {
        osal_printk("%2x", addr->addr[i]);
    }
    osal_printk("\n");
    gattc_exchange_mtu_req(g_uart_client_id, g_uart_conn_id, g_uart_mtu);
}

void ble_uart_client_power_on_cbk(uint8_t status)
{
    osal_printk("ble power on: %d\n", status);
    enable_ble();
}

/* ble client bt stack enable callback */
void ble_uart_client_enable_cbk(uint8_t status)
{
    osal_printk("ble enable: %d\n", status);
    gattc_register_client(&g_client_app_uuid, &g_uart_client_id);
    ble_uart_set_scan_parameters();
}

/* ble client service discovery callback */
static void ble_uart_client_discover_service_cbk(uint8_t client_id, uint16_t conn_id,
                                                 gattc_discovery_service_result_t *service, errcode_t status)
{
    gattc_discovery_character_param_t param = { 0 };
    osal_printk("%s Discovery service callback client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s start handle:%d end handle:%d uuid_len:%d uuid:\n",
                BLE_UART_CLIENT_LOG, service->start_hdl, service->end_hdl, service->uuid.uuid_len);
    for (uint8_t i = 0; i < service->uuid.uuid_len; i++) {
        osal_printk("%02x", service->uuid.uuid[i]);
    }
    osal_printk("\n %s status:%d\n", BLE_UART_CLIENT_LOG, status);
    param.service_handle = service->start_hdl;
    param.uuid.uuid_len = service->uuid.uuid_len; /* uuid length is zero, discover all character */
    if (memcpy_s(param.uuid.uuid, param.uuid.uuid_len, service->uuid.uuid, service->uuid.uuid_len) != 0) {
        osal_printk("%s memcpy error\n", BLE_UART_CLIENT_ERROR);
    }
    gattc_discovery_character(g_uart_client_id, conn_id, ¶m);
}

/* ble client character discovery callback */
static void ble_uart_client_discover_character_cbk(uint8_t client_id, uint16_t conn_id,
                                                   gattc_discovery_character_result_t *character, errcode_t status)
{
    for (uint8_t i = 0; i < character->uuid.uuid_len; i++) {
        osal_printk("%02x", character->uuid.uuid[i]);
    }
    osal_printk("\n%s discover character declare_handle:%d, value_handle:%d, properties:%2x\n",
                BLE_UART_CLIENT_LOG, character->declare_handle, character->value_handle, character->properties);
    osal_printk("%s client_id:%d, conn_id = %d, status:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id, status);
    bt_uuid_t write_uuid = { 0 };
    bts_data_to_uuid_len2(BLE_UART_CHARACTER_CLIENT_UUID_TX, &write_uuid);
    write_uuid.uuid_len = BT_UUID_MAX_LEN;
    if (memcmp(character->uuid.uuid, write_uuid.uuid, character->uuid.uuid_len) == 0) {
        g_ble_uart_chara_hanle_write_value = character->value_handle;
        osal_printk("%s write declare_handle:%d, value_handle:%d, properties:%2x\n",
                    BLE_UART_CLIENT_LOG, character->declare_handle, character->value_handle, character->properties);
    }
    gattc_discovery_descriptor(g_uart_client_id, conn_id, character->declare_handle);
}

/* ble client descriptor discovery callback */
static void ble_uart_client_discover_descriptor_cbk(uint8_t client_id, uint16_t conn_id,
    gattc_discovery_descriptor_result_t *descriptor, errcode_t status)
{
    osal_printk("%s Discovery descriptor----client:%d conn_id:%d uuid len:%d, uuid:\n",
                BLE_UART_CLIENT_LOG, client_id, conn_id, descriptor->uuid.uuid_len);
    for (uint8_t i = 0; i < descriptor->uuid.uuid_len; i++) {
        osal_printk("%02x", descriptor->uuid.uuid[i]);
    }
    osal_printk("\n%s descriptor handle:%d, status:%d\n", BLE_UART_CLIENT_LOG, descriptor->descriptor_hdl, status);

    gattc_read_req_by_uuid_param_t paramsss = { 0 };
    paramsss.uuid = descriptor->uuid;
    paramsss.start_hdl = descriptor->descriptor_hdl;
    paramsss.end_hdl = descriptor->descriptor_hdl;
    gattc_read_req_by_uuid(client_id, conn_id, ¶msss);
}

/* ble client compare service uuid */
static void ble_uart_client_discover_service_compl_cbk(uint8_t client_id, uint16_t conn_id, bt_uuid_t *uuid,
                                                       errcode_t status)
{
    osal_printk("%s Discovery service complete----client:%d conn_id:%d uuid len:%d uuid:\n",
                BLE_UART_CLIENT_LOG, client_id, conn_id, uuid->uuid_len);
    for (uint8_t i = 0; i < uuid->uuid_len; i++) {
        osal_printk("%02x", uuid->uuid[i]);
    }
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

/* ble client character discovery complete callback */
static void ble_uart_client_discover_character_compl_cbk(uint8_t client_id, uint16_t conn_id,
                                                         gattc_discovery_character_param_t *param, errcode_t status)
{
    osal_printk("%s Discovery character complete----client:%d conn_id:%d uuid len:%d uuid: \n",
                BLE_UART_CLIENT_LOG, client_id, conn_id, param->uuid.uuid_len);
    for (uint8_t i = 0; i < param->uuid.uuid_len; i++) {
        osal_printk("%02x", param->uuid.uuid[i]);
    }
    osal_printk("\n%s service handle:%d status:%d\n", BLE_UART_CLIENT_LOG, param->service_handle, status);
}

/* ble client descriptor discovery complete callback */
static void ble_uart_client_discover_descriptor_compl_cbk(uint8_t client_id, uint16_t conn_id,
                                                          uint16_t character_handle, errcode_t status)
{
    osal_printk("%s Discovery descriptor complete----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s charatcer handle:%d, status:%d\n", BLE_UART_CLIENT_LOG, character_handle, status);
}

/* Callback invoked when receive read response */
static void ble_uart_client_read_cfm_cbk(uint8_t client_id, uint16_t conn_id, gattc_handle_value_t *read_result,
                                         gatt_status_t status)
{
    osal_printk("%s Read result client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, read_result->handle, read_result->data_len);
    for (uint8_t i = 0; i < read_result->data_len; i++) {
        osal_printk("%02x", read_result->data[i]);
    }
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

/* Callback invoked when read complete */
static void ble_uart_client_read_compl_cbk(uint8_t client_id, uint16_t conn_id, gattc_read_req_by_uuid_param_t *param,
                                           errcode_t status)
{
    osal_printk("%s Read by uuid complete----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s start handle:%d end handle:%d uuid len:%d uuid:\n",
                BLE_UART_CLIENT_LOG, param->start_hdl, param->end_hdl, param->uuid.uuid_len);
    for (uint8_t i = 0; i < param->uuid.uuid_len; i++) {
        osal_printk("%02x", param->uuid.uuid[i]);
    }
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

/* Callback invoked when receive write response */
static void ble_uart_client_write_cfm_cbk(uint8_t client_id, uint16_t conn_id, uint16_t handle, gatt_status_t status)
{
    osal_printk("%s Write result----client:%d conn_id:%d handle:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id, handle);
    osal_printk("%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

/* Callback invoked when change MTU complete */
static void ble_uart_client_mtu_changed_cbk(uint8_t client_id, uint16_t conn_id, uint16_t mtu_size, errcode_t status)
{
    osal_printk("%s Mtu changed----client:%d conn_id:%d, mtu size:%d, status:%d\n",
                BLE_UART_CLIENT_LOG, client_id, conn_id, mtu_size, status);
    ble_uart_client_discover_all_service(conn_id);
}

/* Callback invoked when receive server notification */
static void ble_uart_client_notification_cbk(uint8_t client_id, uint16_t conn_id, gattc_handle_value_t *data,
                                             errcode_t status)
{
    osal_printk("%s Receive notification----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, data->handle, data->data_len);
    osal_printk("%s ble_uart_client_notification_cbk %s", BLE_UART_CLIENT_LOG, data->data);
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
    uapi_uart_write(CONFIG_BLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0);
}

/* Callback invoked when receive server indication */
static void ble_uart_client_indication_cbk(uint8_t client_id, uint16_t conn_id, gattc_handle_value_t *data,
                                           errcode_t status)
{
    osal_printk("%s Receive indication----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, data->handle, data->data_len);
    for (uint8_t i = 0; i < data->data_len; i++) {
        osal_printk("%02x", data->data[i]);
    }
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

/* register gatt and gap callback */
errcode_t ble_uart_client_callback_register(void)
{
    errcode_t ret = 0;
    bts_dev_manager_callbacks_t dev_cb = { 0 };
    gap_ble_callbacks_t gap_cb = { 0 };
    gattc_callbacks_t cb = { 0 };

    gap_cb.set_scan_param_cb = ble_uart_client_set_scan_param_cbk;
    gap_cb.scan_result_cb = ble_uart_client_scan_result_cbk;
    gap_cb.conn_state_change_cb = ble_uart_client_connect_change_cbk;
    gap_cb.pair_result_cb = ble_uart_client_pair_result_cb;
    dev_cb.power_on_cb = ble_uart_client_power_on_cbk;
    dev_cb.ble_enable_cb = ble_uart_client_enable_cbk;
    ret |= bts_dev_manager_register_callbacks(&dev_cb);
    ret |= gap_ble_register_callbacks(&gap_cb);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s reg gap cbk failed ret = %d\n", BLE_UART_CLIENT_ERROR, ret);
    }

    cb.discovery_svc_cb = ble_uart_client_discover_service_cbk;
    cb.discovery_svc_cmp_cb = ble_uart_client_discover_service_compl_cbk;
    cb.discovery_chara_cb = ble_uart_client_discover_character_cbk;
    cb.discovery_chara_cmp_cb = ble_uart_client_discover_character_compl_cbk;
    cb.discovery_desc_cb = ble_uart_client_discover_descriptor_cbk;
    cb.discovery_desc_cmp_cb = ble_uart_client_discover_descriptor_compl_cbk;
    cb.read_cb = ble_uart_client_read_cfm_cbk;
    cb.read_cmp_cb = ble_uart_client_read_compl_cbk;
    cb.write_cb = ble_uart_client_write_cfm_cbk;
    cb.mtu_changed_cb = ble_uart_client_mtu_changed_cbk;
    cb.notification_cb = ble_uart_client_notification_cbk;
    cb.indication_cb = ble_uart_client_indication_cbk;
    ret = gattc_register_callbacks(&cb);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s reg gatt cbk failed ret = %d\n", BLE_UART_CLIENT_ERROR, ret);
    }
#if (CORE_NUMS < 2)
    enable_ble();
#endif
    return ret;
}

/* ble uart client init */
errcode_t ble_uart_client_init(void)
{
    errcode_t ret = ble_uart_client_callback_register();
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s init failed ret = %d\n", BLE_UART_CLIENT_ERROR, ret);
    }
    return ret;
}

uint16_t ble_uart_get_write_vlaue_handle(void)
{
    return g_ble_uart_chara_hanle_write_value;
}

ble_uart_client_scan代码

#include "errcode.h"
#include "bts_def.h"
#include "bts_le_gap.h"
#include "ble_uart_client_scan.h"

static uint16_t g_uart_scan_interval = 0x48;
static uint16_t g_uart_scan_window = 0x48;
static uint8_t g_uart_scan_type = 0x00;
static uint8_t g_uart_scan_phy = 0x01;
static uint8_t g_uart_scan_filter_policy = 0x00;

errcode_t ble_uart_set_scan_parameters(void)
{
    gap_ble_scan_params_t ble_uart_scan_params = { 0 };
    ble_uart_scan_params.scan_interval = g_uart_scan_interval;
    ble_uart_scan_params.scan_window = g_uart_scan_window;
    ble_uart_scan_params.scan_type = g_uart_scan_type;
    ble_uart_scan_params.scan_phy = g_uart_scan_phy;
    ble_uart_scan_params.scan_filter_policy = g_uart_scan_filter_policy;
    return gap_ble_set_scan_parameters(&ble_uart_scan_params);
}

errcode_t ble_uart_start_scan(void)
{
    return gap_ble_start_scan();
}

ble_uart代码

#include "securec.h"
#include "common_def.h"
#include "soc_osal.h"
#include "app_init.h"
#include "uart.h"
#if defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER)
#include "bts_gatt_server.h"
#include "ble_uart_server.h"
#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT)
#include "bts_gatt_client.h"
#include "ble_uart_client.h"
#endif /* CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT */

#define BLE_UART_BT_STACK_POWER_MS      10000

typedef struct {
    uint8_t *value;
    uint16_t value_len;
} msg_data_t;
unsigned long mouse_msg_queue = 0;
unsigned int msg_rev_size = sizeof(msg_data_t);

#if defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER)
static void ble_uart_read_int_handler(const void *buffer, uint16_t length, bool error)
{
    osal_printk("ble_uart_read_int_handler server.\r\n");
    unused(error);
    if (ble_uart_get_connection_state() != 0) {
        msg_data_t msg_data = { 0 };
        void* buffer_cpy = osal_vmalloc(length);
        if (memcpy_s(buffer_cpy, length, buffer, length) != EOK) {
            osal_vfree(buffer_cpy);
            return;
        }
        msg_data.value = (uint8_t *)buffer_cpy;
        msg_data.value_len = length;
        osal_msg_queue_write_copy(mouse_msg_queue, (void *)&msg_data, msg_rev_size, 0);
    }
}

static void *ble_uart_server_task(const char *arg)
{
    unused(arg);
    ble_uart_server_init();
    errcode_t ret = uapi_uart_register_rx_callback(CONFIG_BLE_UART_BUS,
                                                   UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE,
                                                   1, ble_uart_read_int_handler);
    if (ret != ERRCODE_SUCC) {
        osal_printk("Register uart callback fail.");
        return NULL;
    }
    while (1) {
        msg_data_t msg_data = { 0 };
        int msg_ret = osal_msg_queue_read_copy(mouse_msg_queue, &msg_data, &msg_rev_size, OSAL_WAIT_FOREVER);
        if (msg_ret != OSAL_SUCCESS) {
            osal_printk("msg queue read copy fail.");
            if (msg_data.value != NULL) {
                osal_vfree(msg_data.value);
            }
            continue;
        }
        if (msg_data.value != NULL) {
            ble_uart_server_send_input_report(msg_data.value, msg_data.value_len);
            osal_vfree(msg_data.value);
        }
    }
    return NULL;
}
#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT)
static void ble_uart_read_int_handler(const void *buffer, uint16_t length, bool error)
{
    osal_printk("ble_uart_read_int_handler client.\r\n");
    unused(error);
    msg_data_t msg_data = { 0 };
    void* buffer_cpy = osal_vmalloc(length);
    if (memcpy_s(buffer_cpy, length, buffer, length) != EOK) {
        osal_vfree(buffer_cpy);
        return;
    }
    msg_data.value = (uint8_t *)buffer_cpy;
    msg_data.value_len = length;
    osal_msg_queue_write_copy(mouse_msg_queue, (void *)&msg_data, msg_rev_size, 0);
}

static void *ble_uart_client_task(const char *arg)
{
    unused(arg);
    ble_uart_client_init();
    errcode_t ret = uapi_uart_register_rx_callback(CONFIG_BLE_UART_BUS,
                                                   UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE,
                                                   1, ble_uart_read_int_handler);
    if (ret != ERRCODE_SUCC) {
        osal_printk("Register uart callback fail.");
        return NULL;
    }
    while (1) {
        msg_data_t msg_data = { 0 };
        int msg_ret = osal_msg_queue_read_copy(mouse_msg_queue, &msg_data, &msg_rev_size, OSAL_WAIT_FOREVER);
        if (msg_ret != OSAL_SUCCESS) {
            osal_printk("msg queue read copy fail.");
            if (msg_data.value != NULL) {
                osal_vfree(msg_data.value);
            }
            continue;
        }
        if (msg_data.value != NULL) {
            uint16_t write_handle = ble_uart_get_write_vlaue_handle();
            ble_uart_client_write_cmd(msg_data.value, msg_data.value_len, write_handle);
            osal_vfree(msg_data.value);
        }
    }
    return NULL;
}
#endif  /* CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT */

static void ble_uart_entry(void)
{
    char *arg = NULL;
    int msg_ret = osal_msg_queue_create("task_msg", msg_rev_size, &mouse_msg_queue, 0, msg_rev_size);
    if (msg_ret != OSAL_SUCCESS) {
        osal_printk("msg queue create fail.");
        return;
    }
#if defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER)
    ble_uart_server_task(arg);
#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT)
    ble_uart_client_task(arg);
#endif /* CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT */
}

/* Run the ble_uart_entry. */
app_run(ble_uart_entry);

代码解读

代码首先进入ble_uart.c的ble_uart_entry任务入口,代码如下

static void ble_uart_entry(void)
{
    char *arg = NULL;
    int msg_ret = osal_msg_queue_create("task_msg", msg_rev_size, &mouse_msg_queue, 0, msg_rev_size);
    if (msg_ret != OSAL_SUCCESS) {
        osal_printk("msg queue create fail.");
        return;
    }
#if defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER)
    ble_uart_server_task(arg);
#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT)
    ble_uart_client_task(arg);
#endif /* CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT */
}

/* Run the ble_uart_entry. */
app_run(ble_uart_entry);

在其中分别创建Server任务和Client任务

Server任务

对于Server任务,需要完成初始化,并定义接收信息时的中断回调函数,具体代码实现如下

#if defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER)
static void ble_uart_read_int_handler(const void *buffer, uint16_t length, bool error)
{
    osal_printk("ble_uart_read_int_handler server.\r\n");
    unused(error);
    if (ble_uart_get_connection_state() != 0) {
        msg_data_t msg_data = { 0 };
        void* buffer_cpy = osal_vmalloc(length);
        if (memcpy_s(buffer_cpy, length, buffer, length) != EOK) {
            osal_vfree(buffer_cpy);
            return;
        }
        msg_data.value = (uint8_t *)buffer_cpy;
        msg_data.value_len = length;
        osal_msg_queue_write_copy(mouse_msg_queue, (void *)&msg_data, msg_rev_size, 0);
    }
}

static void *ble_uart_server_task(const char *arg)
{
    unused(arg);
    ble_uart_server_init();
    errcode_t ret = uapi_uart_register_rx_callback(CONFIG_BLE_UART_BUS,
                                                   UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE,
                                                   1, ble_uart_read_int_handler);
    if (ret != ERRCODE_SUCC) {
        osal_printk("Register uart callback fail.");
        return NULL;
    }
    while (1) {
        msg_data_t msg_data = { 0 };
        int msg_ret = osal_msg_queue_read_copy(mouse_msg_queue, &msg_data, &msg_rev_size, OSAL_WAIT_FOREVER);
        if (msg_ret != OSAL_SUCCESS) {
            osal_printk("msg queue read copy fail.");
            if (msg_data.value != NULL) {
                osal_vfree(msg_data.value);
            }
            continue;
        }
        if (msg_data.value != NULL) {
            ble_uart_server_send_input_report(msg_data.value, msg_data.value_len);
            osal_vfree(msg_data.value);
        }
    }
    return NULL;
}
#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT)

对于Server初始化,具体代码如下:

static errcode_t ble_uart_server_register_callbacks(void)
{
    bts_dev_manager_callbacks_t dev_mgr_cb = { 0 };
    gap_ble_callbacks_t gap_cb = { 0 };
    gatts_callbacks_t service_cb = { 0 };

    dev_mgr_cb.power_on_cb = ble_uart_server_power_on_cbk;
    dev_mgr_cb.ble_enable_cb = ble_uart_server_enable_cbk;
    gap_cb.start_adv_cb = ble_uart_server_adv_enable_cbk;
    gap_cb.conn_state_change_cb = ble_uart_server_connect_change_cbk;
    gap_cb.stop_adv_cb = ble_uart_server_adv_disable_cbk;
    gap_cb.pair_result_cb = ble_uart_server_pair_result_cb;
    errcode_t ret = gap_ble_register_callbacks(&gap_cb);
    ret |= bts_dev_manager_register_callbacks(&dev_mgr_cb);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s reg gap cbk failed ret = %d\n", BLE_UART_SERVER_ERROR, ret);
        return ret;
    }

    service_cb.add_service_cb = ble_uart_server_service_add_cbk;
    service_cb.add_characteristic_cb = ble_uart_server_characteristic_add_cbk;
    service_cb.add_descriptor_cb = ble_uart_server_descriptor_add_cbk;
    service_cb.start_service_cb = ble_uart_server_service_start_cbk;
    service_cb.read_request_cb = ble_uart_receive_read_req_cbk;
    service_cb.write_request_cb = ble_uart_receive_write_req_cbk;
    service_cb.mtu_changed_cb = ble_uart_mtu_changed_cbk;
    ret = gatts_register_callbacks(&service_cb);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s reg service cbk failed ret = %d\n", BLE_UART_SERVER_ERROR, ret);
        return ret;
    }
#if (CORE_NUMS < 2)
    enable_ble();
#endif
    return ret;
}

设备初始化

1. 使用ble_uart_server_power_on_cbk使能BLE协议栈

void ble_uart_server_power_on_cbk(uint8_t status)
{
    osal_printk("ble power on: %d\n", status);
    enable_ble();
}

2. 使用ble_uart_server_enable_cbk使能Server

void ble_uart_server_enable_cbk(uint8_t status)
{
    osal_printk("ble enable: %d\n", status);
    errcode_t ret = 0;
    bt_uuid_t app_uuid = { 0 };
    bd_addr_t ble_addr = { 0 };
    app_uuid.uuid_len = sizeof(g_uart_server_app_uuid);
    if (memcpy_s(app_uuid.uuid, app_uuid.uuid_len, g_uart_server_app_uuid, sizeof(g_uart_server_app_uuid)) != EOK) {
        osal_printk("%s add server app uuid memcpy failed\n", BLE_UART_SERVER_ERROR);
        return;
    }
    ble_addr.type = BLE_PUBLIC_DEVICE_ADDRESS;
    if (memcpy_s(ble_addr.addr, BD_ADDR_LEN, g_ble_uart_server_addr, sizeof(g_ble_uart_server_addr)) != EOK) {
        osal_printk("%s add server app addr memcpy failed\n", BLE_UART_SERVER_ERROR);
        return;
    }
    gap_ble_set_local_name(g_ble_uart_name_value, sizeof(g_ble_uart_name_value));
    gap_ble_set_local_addr(&ble_addr);
    ret = gatts_register_server(&app_uuid, &g_server_id);
    if ((ret != ERRCODE_BT_SUCCESS) || (g_server_id == INVALID_SERVER_ID)) {
        osal_printk("%s add server failed\r\n", BLE_UART_SERVER_ERROR);
        return;
    }
    ble_uart_add_service(); /* 添加uart服务 */
    osal_printk("%s beginning add service\r\n", BLE_UART_SERVER_LOG);
    bth_ota_init();
}

在这一步中,需要完成的内容如下:

  • 使用gap_ble_set_local_name设置本地设备名称
  • 使用gap_ble_set_local_addr设置本地设备地址
  • 使用gatts_register_server注册GATT服务端
  • 使用GATT创建uart服务
  • 使用bth_ota_init初始化bth ota通道

3. 使用bts_dev_manager_register_callbacks注册BT device manager回调函数

GAP参数初始化

1. 使用ble_uart_server_adv_enable_cbk使能Server的ADV

static void ble_uart_server_adv_enable_cbk(uint8_t adv_id, adv_status_t status)
{
    osal_printk("%s adv enable cbk adv_id:%d status:%d\n", BLE_UART_SERVER_LOG, adv_id, status);
}

2. 使用ble_uart_server_connect_change_cbk初始化ADV

void ble_uart_server_connect_change_cbk(uint16_t conn_id, bd_addr_t *addr, gap_ble_conn_state_t conn_state,
                                        gap_ble_pair_state_t pair_state, gap_ble_disc_reason_t disc_reason)
{
    g_ble_uart_conn_id = conn_id;
    g_connection_state = (uint8_t)conn_state;
    osal_printk("%s connect state change conn_id: %d, status: %d, pair_status:%d, addr %x disc_reason %x\n",
                BLE_UART_SERVER_LOG, conn_id, conn_state, pair_state, addr[0], disc_reason);
    if (conn_state == GAP_BLE_STATE_CONNECTED) {
        return;
    } else if (conn_state == GAP_BLE_STATE_DISCONNECTED) {
        ble_uart_set_adv_data();
        ble_uart_start_adv();
    }
}

其中,需要完成设置ADV信息->设置扫描反馈信息->启动ADV

uint8_t ble_uart_set_adv_data(void)
{
    uint8_t set_adv_data[EXT_ADV_OR_SCAN_RSP_DATA_LEN] = { 0 };
    uint8_t set_scan_rsp_data[EXT_ADV_OR_SCAN_RSP_DATA_LEN] = { 0 };
    gap_ble_config_adv_data_t cfg_adv_data;

    /* set adv data */
    uint16_t adv_data_len = ble_uart_server_set_adv_data(set_adv_data, EXT_ADV_OR_SCAN_RSP_DATA_LEN);
    if ((adv_data_len > EXT_ADV_OR_SCAN_RSP_DATA_LEN) || (adv_data_len == 0)) {
        return 0;
    }
    /* set scan response data */
    uint16_t scan_rsp_data_len = ble_set_scan_response_data(set_scan_rsp_data, EXT_ADV_OR_SCAN_RSP_DATA_LEN);
    if ((scan_rsp_data_len > EXT_ADV_OR_SCAN_RSP_DATA_LEN) || (scan_rsp_data_len == 0)) {
        return 0;
    }
    cfg_adv_data.adv_data = set_adv_data;
    cfg_adv_data.adv_length = adv_data_len;

    cfg_adv_data.scan_rsp_data = set_scan_rsp_data;
    cfg_adv_data.scan_rsp_length = scan_rsp_data_len;
    osal_printk("%s ble_uart_set_adv_data adv_handle %d, len:%d, data:%s\n",
                BLE_UART_ADV_LOG, BTH_GAP_BLE_ADV_HANDLE_DEFAULT, adv_data_len, set_adv_data);
    return gap_ble_set_adv_data(BTH_GAP_BLE_ADV_HANDLE_DEFAULT, &cfg_adv_data);
}

uint8_t ble_uart_start_adv(void)
{
    errcode_t ret = ERRCODE_BT_SUCCESS;
    int adv_id = BTH_GAP_BLE_ADV_HANDLE_DEFAULT;

    gap_ble_adv_params_t adv_para = {
        .min_interval = BLE_ADV_MIN_INTERVAL,
        .max_interval = BLE_ADV_MAX_INTERVAL,
        .duration = BTH_GAP_BLE_ADV_FOREVER_DURATION,
        .peer_addr.type = BLE_PUBLIC_DEVICE_ADDRESS,
        /* 广播通道选择bitMap, 可参考BleAdvChannelMap */
        .channel_map = BLE_ADV_CHANNEL_MAP_CH_DEFAULT,
        .adv_type = BLE_ADV_TYPE_CONNECTABLE_UNDIRECTED,
        .adv_filter_policy = BLE_ADV_FILTER_POLICY_SCAN_ANY_CONNECT_ANY
    };

    (void)memset_s(&adv_para.peer_addr.addr, BD_ADDR_LEN, 0, BD_ADDR_LEN);
    osal_printk("%s ble_uart_start_adv adv_id %d\n", BLE_UART_ADV_LOG, adv_id);
    ret |= gap_ble_set_adv_param(adv_id, &adv_para);
    ret |= gap_ble_start_adv(adv_id);
    return ret;
}

3. 使用ble_uart_server_pair_result_cb初始化配对成功后的输出信息

void ble_uart_server_pair_result_cb(uint16_t conn_id, const bd_addr_t *addr, errcode_t status)
{
    osal_printk("%s pair result conn_id: %d, status: %d, addr %x \n",
                BLE_UART_SERVER_LOG, conn_id, status, addr[0]);
}

4. 使用gap_ble_register_callbacks注册BLE GAP回调函数

创建任务回调函数初始化

1. 使用ble_uart_server_service_add_cbk创建服务添加回调函数,使用ble_uart_server_characteristics_add_cbk创建特征添加回调函数,使用ble_uart_server_descriptor_add_cbk创建描述符添加回调函数,使用ble_uart_service_start_cbk创建开始服务回调函数

/* 服务添加回调 */
static void ble_uart_server_service_add_cbk(uint8_t server_id, bt_uuid_t *uuid, uint16_t handle, errcode_t status)
{
    osal_printk("%s add characters_and_descriptors cbk service:%d, srv_handle:%d, uuid_len:%d, status:%d, uuid:",
                BLE_UART_SERVER_LOG, server_id, handle, uuid->uuid_len, status);
    for (int8_t i = 0; i < uuid->uuid_len; i++) {
        osal_printk("%02x ", uuid->uuid[i]);
    }
    osal_printk("\n");
    ble_uart_add_tx_characters_and_descriptors(server_id, handle);
    ble_uart_add_rx_characters_and_descriptors(server_id, handle);
    gatts_start_service(server_id, handle);
}

/* 特征添加回调 */
static void ble_uart_server_characteristic_add_cbk(uint8_t server_id, bt_uuid_t *uuid, uint16_t service_handle,
                                                   gatts_add_character_result_t *result, errcode_t status)
{
    osal_printk("%s add character cbk service:%d service_hdl: %d char_hdl: %d char_val_hdl: %d uuid_len: %d \n",
                BLE_UART_SERVER_LOG, server_id, service_handle, result->handle, result->value_handle, uuid->uuid_len);
    osal_printk("uuid:");
    for (int8_t i = 0; i < uuid->uuid_len; i++) {
        osal_printk("%02x ", uuid->uuid[i]);
    }
    bt_uuid_t characters_cbk_uuid = { 0 };
    bts_data_to_uuid_len2(BLE_UART_CHARACTERISTIC_UUID_TX, &characters_cbk_uuid);
    characters_cbk_uuid.uuid_len = uuid->uuid_len;
    if (bts_uart_compare_uuid(uuid, &characters_cbk_uuid)) {
        g_notify_indicate_handle = result->value_handle;
    }
    osal_printk("%s status:%d indicate_handle:%d\n", BLE_UART_SERVER_LOG, status, g_notify_indicate_handle);
}

/* 描述符添加回调 */
static void ble_uart_server_descriptor_add_cbk(uint8_t server_id, bt_uuid_t *uuid, uint16_t service_handle,
                                               uint16_t handle, errcode_t status)
{
    osal_printk("%s service:%d service_hdl: %d desc_hdl: %d uuid_len: %d \n",
                BLE_UART_SERVER_LOG, server_id, service_handle, handle, uuid->uuid_len);
    osal_printk("uuid:");
    for (int8_t i = 0; i < uuid->uuid_len; i++) {
        osal_printk("%02x ", (uint8_t)uuid->uuid[i]);
    }
    osal_printk("%s status:%d\n", BLE_UART_SERVER_LOG, status);
}

/* 开始服务回调 */
static void ble_uart_server_service_start_cbk(uint8_t server_id, uint16_t handle, errcode_t status)
{
    g_service_num++;
    if ((g_service_num == BLE_UART_SERVICE_NUM) && (status == 0)) {
        osal_printk("%s start service cbk , start adv\n", BLE_UART_SERVER_LOG);
        ble_uart_set_adv_data();
        ble_uart_start_adv();
    }
    osal_printk("%s start service:%2d service_hdl: %d status: %d\n",
                BLE_UART_SERVER_LOG, server_id, handle, status);
}

2. 创建接收读信息/接收写信息时日志信息

static void ble_uart_receive_write_req_cbk(uint8_t server_id, uint16_t conn_id, gatts_req_write_cb_t *write_cb_para,
                                           errcode_t status)
{
    osal_printk("%s ble uart write cbk server_id:%d, conn_id:%d, status%d\n",
        BLE_UART_SERVER_LOG, server_id, conn_id, status);
    osal_printk("%s ble uart write cbk len:%d, data:%s\n",
                BLE_UART_SERVER_LOG, write_cb_para->length, write_cb_para->value);
    if ((write_cb_para->length > 0) && write_cb_para->value) {
        uapi_uart_write(CONFIG_BLE_UART_BUS, (uint8_t *)(write_cb_para->value), write_cb_para->length, 0);
    }
}

static void ble_uart_receive_read_req_cbk(uint8_t server_id, uint16_t conn_id, gatts_req_read_cb_t *read_cb_para,
    errcode_t status)
{
    osal_printk("%s ReceiveReadReq--server_id:%d conn_id:%d\n", BLE_UART_SERVER_LOG, server_id, conn_id);
    osal_printk("%s request_id:%d, att_handle:%d offset:%d, need_rsp:%d, is_long:%d\n",
                BLE_UART_SERVER_LOG, read_cb_para->request_id, read_cb_para->handle, read_cb_para->offset,
                read_cb_para->need_rsp, read_cb_para->is_long);
    osal_printk("%s status:%d\n", BLE_UART_SERVER_LOG, status);
}

3. 创建mtu交换日志信息

static void ble_uart_mtu_changed_cbk(uint8_t server_id, uint16_t conn_id, uint16_t mtu_size, errcode_t status)
{
    osal_printk("%s MtuChanged--server_id:%d conn_id:%d\n", BLE_UART_SERVER_LOG, server_id, conn_id);
    osal_printk("%s mtusize:%d, status:%d\n", BLE_UART_SERVER_LOG, mtu_size, status);
}

4. 使用gatts_register_callbacks注册回调函数

完成以上Server初始化步骤后,使用uapi_uart_register_rx_callback注册接收回调函数,就完成了Server的任务创建。

Client任务

对于Client任务,也需要完成初始化,并定义接收信息时的中断回调函数,具体代码实现如下

#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT)
static void ble_uart_read_int_handler(const void *buffer, uint16_t length, bool error)
{
    osal_printk("ble_uart_read_int_handler client.\r\n");
    unused(error);
    msg_data_t msg_data = { 0 };
    void* buffer_cpy = osal_vmalloc(length);
    if (memcpy_s(buffer_cpy, length, buffer, length) != EOK) {
        osal_vfree(buffer_cpy);
        return;
    }
    msg_data.value = (uint8_t *)buffer_cpy;
    msg_data.value_len = length;
    osal_msg_queue_write_copy(mouse_msg_queue, (void *)&msg_data, msg_rev_size, 0);
}

static void *ble_uart_client_task(const char *arg)
{
    unused(arg);
    ble_uart_client_init();
    errcode_t ret = uapi_uart_register_rx_callback(CONFIG_BLE_UART_BUS,
                                                   UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE,
                                                   1, ble_uart_read_int_handler);
    if (ret != ERRCODE_SUCC) {
        osal_printk("Register uart callback fail.");
        return NULL;
    }
    while (1) {
        msg_data_t msg_data = { 0 };
        int msg_ret = osal_msg_queue_read_copy(mouse_msg_queue, &msg_data, &msg_rev_size, OSAL_WAIT_FOREVER);
        if (msg_ret != OSAL_SUCCESS) {
            osal_printk("msg queue read copy fail.");
            if (msg_data.value != NULL) {
                osal_vfree(msg_data.value);
            }
            continue;
        }
        if (msg_data.value != NULL) {
            uint16_t write_handle = ble_uart_get_write_vlaue_handle();
            ble_uart_client_write_cmd(msg_data.value, msg_data.value_len, write_handle);
            osal_vfree(msg_data.value);
        }
    }
    return NULL;
}
#endif  /* CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT */

对于Client初始化,需要完成GATT注册和GAP回调函数定义,具体代码如下

errcode_t ble_uart_client_callback_register(void)
{
    errcode_t ret = 0;
    bts_dev_manager_callbacks_t dev_cb = { 0 };
    gap_ble_callbacks_t gap_cb = { 0 };
    gattc_callbacks_t cb = { 0 };

    gap_cb.set_scan_param_cb = ble_uart_client_set_scan_param_cbk;
    gap_cb.scan_result_cb = ble_uart_client_scan_result_cbk;
    gap_cb.conn_state_change_cb = ble_uart_client_connect_change_cbk;
    gap_cb.pair_result_cb = ble_uart_client_pair_result_cb;
    dev_cb.power_on_cb = ble_uart_client_power_on_cbk;
    dev_cb.ble_enable_cb = ble_uart_client_enable_cbk;
    ret |= bts_dev_manager_register_callbacks(&dev_cb);
    ret |= gap_ble_register_callbacks(&gap_cb);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s reg gap cbk failed ret = %d\n", BLE_UART_CLIENT_ERROR, ret);
    }

    cb.discovery_svc_cb = ble_uart_client_discover_service_cbk;
    cb.discovery_svc_cmp_cb = ble_uart_client_discover_service_compl_cbk;
    cb.discovery_chara_cb = ble_uart_client_discover_character_cbk;
    cb.discovery_chara_cmp_cb = ble_uart_client_discover_character_compl_cbk;
    cb.discovery_desc_cb = ble_uart_client_discover_descriptor_cbk;
    cb.discovery_desc_cmp_cb = ble_uart_client_discover_descriptor_compl_cbk;
    cb.read_cb = ble_uart_client_read_cfm_cbk;
    cb.read_cmp_cb = ble_uart_client_read_compl_cbk;
    cb.write_cb = ble_uart_client_write_cfm_cbk;
    cb.mtu_changed_cb = ble_uart_client_mtu_changed_cbk;
    cb.notification_cb = ble_uart_client_notification_cbk;
    cb.indication_cb = ble_uart_client_indication_cbk;
    ret = gattc_register_callbacks(&cb);
    if (ret != ERRCODE_BT_SUCCESS) {
        osal_printk("%s reg gatt cbk failed ret = %d\n", BLE_UART_CLIENT_ERROR, ret);
    }
#if (CORE_NUMS < 2)
    enable_ble();
#endif
    return ret;
}

定义GAP相关的回调函数

1. 使用ble_uart_client_set_scan_param_cbk设置扫描参数回调,在这一步中,需要Client首先删除所有BLE配对设备,然后开始扫描

void ble_uart_client_set_scan_param_cbk(errcode_t status)
{
    osal_printk("%s set scan param status: %d\n", BLE_UART_CLIENT_LOG, status);
    gap_ble_remove_all_pairs();
    ble_uart_start_scan();
}

2. 使用ble_uart_client_scan_result_cbk设置扫描结果回调,在这一步中,Client与Server的连接地址匹配,则停止扫描,转而与设备建立连接

void ble_uart_client_scan_result_cbk(gap_scan_result_data_t *scan_result_data)
{
    if (memcmp(g_ble_server_addr_connect, scan_result_data->addr.addr, sizeof(g_ble_server_addr_connect)) == 0) {
        gap_ble_stop_scan();
        osal_printk("\naddr:");
        for (uint8_t i = 0; i < BD_ADDR_LEN; i++) {
            osal_printk(" %02x: ", scan_result_data->addr.addr[i]);
        }
        bd_addr_t bt_uart_client_addr = { 0 };
        bt_uart_client_addr.type = scan_result_data->addr.type;
        if (memcpy_s(bt_uart_client_addr.addr, BD_ADDR_LEN, scan_result_data->addr.addr, BD_ADDR_LEN) != EOK) {
            osal_printk("%s add server app addr memcpy failed\r\n", BLE_UART_CLIENT_ERROR);
            return;
        }
        gap_ble_connect_remote_device(&bt_uart_client_addr);
    }
}

3. 使用ble_uart_client_connect_change_cbk实现连接状态回调,这一步用于展示连接设备的相关参数,包括conn_id,status,pair_status

void ble_uart_client_connect_change_cbk(uint16_t conn_id, bd_addr_t *addr, gap_ble_conn_state_t conn_state,
                                        gap_ble_pair_state_t pair_state, gap_ble_disc_reason_t disc_reason)
{
    bd_addr_t bt_uart_client_addr = { 0 };
    bt_uart_client_addr.type = addr->type;
    g_uart_conn_id = conn_id;
    if (memcpy_s(bt_uart_client_addr.addr, BD_ADDR_LEN, addr->addr, BD_ADDR_LEN) != EOK) {
        osal_printk("%s add server app addr memcpy failed\r\n", BLE_UART_CLIENT_ERROR);
        return;
    }
    osal_printk("%s connect state change conn_id: %d, status: %d, pair_status:%d, disc_reason %x\n",
                BLE_UART_CLIENT_LOG, conn_id, conn_state, pair_state, disc_reason);

    if (conn_state == GAP_BLE_STATE_CONNECTED  &&  pair_state == GAP_BLE_PAIR_NONE) {
        osal_printk("%s connect change cbk conn_id =%d \n", BLE_UART_CLIENT_LOG, conn_id);
        gattc_exchange_mtu_req(g_uart_client_id, g_uart_conn_id, g_uart_mtu);
    } else if (conn_state == GAP_BLE_STATE_DISCONNECTED) {
        osal_printk("%s connect change cbk conn disconnected \n", BLE_UART_CLIENT_LOG);
        ble_uart_start_scan();
        return;
    }
}

4. 使用ble_uart_client_pair_result_cb实现匹配结果回调,在这一步中,Client需要向Server发送交换mtu请求

void ble_uart_client_pair_result_cb(uint16_t conn_id, const bd_addr_t *addr, errcode_t status)
{
    osal_printk("%s pair result conn_id: %d,status: %d \n", BLE_UART_CLIENT_LOG, conn_id, status);
    osal_printk("addr:\n");
    for (uint8_t i = 0; i < BD_ADDR_LEN; i++) {
        osal_printk("%2x", addr->addr[i]);
    }
    osal_printk("\n");
    gattc_exchange_mtu_req(g_uart_client_id, g_uart_conn_id, g_uart_mtu);
}

5. 使用gap_ble_register_callback注册BLE GAP回调函数

定义设备相关的回调函数

1. 使用ble_uart_client_power_on_cbk使能BLE协议栈

void ble_uart_client_power_on_cbk(uint8_t status)
{
    osal_printk("ble power on: %d\n", status);
    enable_ble();
}

2. 使用ble_uart_client_enable_cbk启动Client的bt堆栈,在这一步中需要完成GATT客户端注册和设置扫描参数

void ble_uart_client_enable_cbk(uint8_t status)
{
    osal_printk("ble enable: %d\n", status);
    gattc_register_client(&g_client_app_uuid, &g_uart_client_id);
    ble_uart_set_scan_parameters();
}

3. 使用bts_dev_manager_register_callbacks注册BT device manager回调函数

注册GATT回调函数

1. 使用ble_uart_client_discover_service_cbk发现特征

static void ble_uart_client_discover_service_cbk(uint8_t client_id, uint16_t conn_id,
                                                 gattc_discovery_service_result_t *service, errcode_t status)
{
    gattc_discovery_character_param_t param = { 0 };
    osal_printk("%s Discovery service callback client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s start handle:%d end handle:%d uuid_len:%d uuid:\n",
                BLE_UART_CLIENT_LOG, service->start_hdl, service->end_hdl, service->uuid.uuid_len);
    for (uint8_t i = 0; i < service->uuid.uuid_len; i++) {
        osal_printk("%02x", service->uuid.uuid[i]);
    }
    osal_printk("\n %s status:%d\n", BLE_UART_CLIENT_LOG, status);
    param.service_handle = service->start_hdl;
    param.uuid.uuid_len = service->uuid.uuid_len; /* uuid length is zero, discover all character */
    if (memcpy_s(param.uuid.uuid, param.uuid.uuid_len, service->uuid.uuid, service->uuid.uuid_len) != 0) {
        osal_printk("%s memcpy error\n", BLE_UART_CLIENT_ERROR);
    }
    gattc_discovery_character(g_uart_client_id, conn_id, ¶m);
}

2. 使用ble_uart_client_discover_service_compl_cbk发现特征描述符

static void ble_uart_client_discover_character_cbk(uint8_t client_id, uint16_t conn_id,
                                                   gattc_discovery_character_result_t *character, errcode_t status)
{
    for (uint8_t i = 0; i < character->uuid.uuid_len; i++) {
        osal_printk("%02x", character->uuid.uuid[i]);
    }
    osal_printk("\n%s discover character declare_handle:%d, value_handle:%d, properties:%2x\n",
                BLE_UART_CLIENT_LOG, character->declare_handle, character->value_handle, character->properties);
    osal_printk("%s client_id:%d, conn_id = %d, status:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id, status);
    bt_uuid_t write_uuid = { 0 };
    bts_data_to_uuid_len2(BLE_UART_CHARACTER_CLIENT_UUID_TX, &write_uuid);
    write_uuid.uuid_len = BT_UUID_MAX_LEN;
    if (memcmp(character->uuid.uuid, write_uuid.uuid, character->uuid.uuid_len) == 0) {
        g_ble_uart_chara_hanle_write_value = character->value_handle;
        osal_printk("%s write declare_handle:%d, value_handle:%d, properties:%2x\n",
                    BLE_UART_CLIENT_LOG, character->declare_handle, character->value_handle, character->properties);
    }
    gattc_discovery_descriptor(g_uart_client_id, conn_id, character->declare_handle);
}

3. 使用ble_uart_client_discover_descriptor_cbk发起按照uuid读取请求

static void ble_uart_client_discover_descriptor_cbk(uint8_t client_id, uint16_t conn_id,
    gattc_discovery_descriptor_result_t *descriptor, errcode_t status)
{
    osal_printk("%s Discovery descriptor----client:%d conn_id:%d uuid len:%d, uuid:\n",
                BLE_UART_CLIENT_LOG, client_id, conn_id, descriptor->uuid.uuid_len);
    for (uint8_t i = 0; i < descriptor->uuid.uuid_len; i++) {
        osal_printk("%02x", descriptor->uuid.uuid[i]);
    }
    osal_printk("\n%s descriptor handle:%d, status:%d\n", BLE_UART_CLIENT_LOG, descriptor->descriptor_hdl, status);

    gattc_read_req_by_uuid_param_t paramsss = { 0 };
    paramsss.uuid = descriptor->uuid;
    paramsss.start_hdl = descriptor->descriptor_hdl;
    paramsss.end_hdl = descriptor->descriptor_hdl;
    gattc_read_req_by_uuid(client_id, conn_id, ¶msss);
}

4. 使用ble_uart_client_discover_service_compl_cbk用于对比Client和Service的uuid

static void ble_uart_client_discover_service_compl_cbk(uint8_t client_id, uint16_t conn_id, bt_uuid_t *uuid,
                                                       errcode_t status)
{
    osal_printk("%s Discovery service complete----client:%d conn_id:%d uuid len:%d uuid:\n",
                BLE_UART_CLIENT_LOG, client_id, conn_id, uuid->uuid_len);
    for (uint8_t i = 0; i < uuid->uuid_len; i++) {
        osal_printk("%02x", uuid->uuid[i]);
    }
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

5. 使用ble_uart_client_discover_character_compl_cbk作为Client完成发现特征的回调函数

static void ble_uart_client_discover_character_compl_cbk(uint8_t client_id, uint16_t conn_id,
                                                         gattc_discovery_character_param_t *param, errcode_t status)
{
    osal_printk("%s Discovery character complete----client:%d conn_id:%d uuid len:%d uuid: \n",
                BLE_UART_CLIENT_LOG, client_id, conn_id, param->uuid.uuid_len);
    for (uint8_t i = 0; i < param->uuid.uuid_len; i++) {
        osal_printk("%02x", param->uuid.uuid[i]);
    }
    osal_printk("\n%s service handle:%d status:%d\n", BLE_UART_CLIENT_LOG, param->service_handle, status);
}

6. 使用ble_uart_client_discover_descriptor_compl_cbk作为Client完成发现特征描述符的回调函数

static void ble_uart_client_discover_descriptor_compl_cbk(uint8_t client_id, uint16_t conn_id,
                                                          uint16_t character_handle, errcode_t status)
{
    osal_printk("%s Discovery descriptor complete----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s charatcer handle:%d, status:%d\n", BLE_UART_CLIENT_LOG, character_handle, status);
}

7. 使用ble_uart_client_read_cfm_cbk作为接收到读请求触发的回调函数

static void ble_uart_client_read_cfm_cbk(uint8_t client_id, uint16_t conn_id, gattc_handle_value_t *read_result,
                                         gatt_status_t status)
{
    osal_printk("%s Read result client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, read_result->handle, read_result->data_len);
    for (uint8_t i = 0; i < read_result->data_len; i++) {
        osal_printk("%02x", read_result->data[i]);
    }
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

8. 使用ble_uart_client_read_compl_cbk作为完成读触发的回调函数

static void ble_uart_client_read_compl_cbk(uint8_t client_id, uint16_t conn_id, gattc_read_req_by_uuid_param_t *param,
                                           errcode_t status)
{
    osal_printk("%s Read by uuid complete----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s start handle:%d end handle:%d uuid len:%d uuid:\n",
                BLE_UART_CLIENT_LOG, param->start_hdl, param->end_hdl, param->uuid.uuid_len);
    for (uint8_t i = 0; i < param->uuid.uuid_len; i++) {
        osal_printk("%02x", param->uuid.uuid[i]);
    }
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

9. 使用ble_uart_client_write_cfm_cbk作为接收到写请求触发的回调函数

static void ble_uart_client_write_cfm_cbk(uint8_t client_id, uint16_t conn_id, uint16_t handle, gatt_status_t status)
{
    osal_printk("%s Write result----client:%d conn_id:%d handle:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id, handle);
    osal_printk("%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

10. 使用ble_uart_client_mtu_change_cbk作为完成mtu交换触发的回调函数,同时Client发现conn_id下的服务

static void ble_uart_client_mtu_changed_cbk(uint8_t client_id, uint16_t conn_id, uint16_t mtu_size, errcode_t status)
{
    osal_printk("%s Mtu changed----client:%d conn_id:%d, mtu size:%d, status:%d\n",
                BLE_UART_CLIENT_LOG, client_id, conn_id, mtu_size, status);
    ble_uart_client_discover_all_service(conn_id);
}

11. 使用ble_uart_client_notification_cbk作为接收到Server的notification触发的回调函数

static void ble_uart_client_notification_cbk(uint8_t client_id, uint16_t conn_id, gattc_handle_value_t *data,
                                             errcode_t status)
{
    osal_printk("%s Receive notification----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, data->handle, data->data_len);
    osal_printk("%s ble_uart_client_notification_cbk %s", BLE_UART_CLIENT_LOG, data->data);
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
    uapi_uart_write(CONFIG_BLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0);
}

12. 使用ble_uart_client_indication_cbk作为接收到Server的indication触发的回调函数

static void ble_uart_client_indication_cbk(uint8_t client_id, uint16_t conn_id, gattc_handle_value_t *data,
                                           errcode_t status)
{
    osal_printk("%s Receive indication----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id);
    osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, data->handle, data->data_len);
    for (uint8_t i = 0; i < data->data_len; i++) {
        osal_printk("%02x", data->data[i]);
    }
    osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status);
}

13. 使用gattc_register_callbacks注册GATT客户端回调函数

完成以上Client初始化步骤后,使用uapi_uart_register_rx_callback注册接收回调函数,就完成了Client的任务创建。

总结

以上就是在小熊派上完成蓝牙BLE的数据传输,这个过程和一般的BLE传输逻辑基本是一致的。本文的内容是我根据目前的经验和对代码的理解翻译而来的,有些理解不到位的或者翻译有误的,希望大家能批评指正。

此帖出自RF/无线论坛

最新回复

我觉得可以测试一下传输速率。   详情 回复 发表于 2024-8-27 14:17
点赞 关注
 

回复
举报

6773

帖子

2

TA的资源

版主

沙发
 

我觉得可以测试一下传输速率。

此帖出自RF/无线论坛

点评

下一篇测评帖子就是测试了,打算测一下功耗和传输速率(距离和丢包都测一下)  详情 回复 发表于 2024-8-27 14:30
 
 

回复

26

帖子

2

TA的资源

一粒金砂(中级)

板凳
 
wangerxian 发表于 2024-8-27 14:17 我觉得可以测试一下传输速率。

下一篇测评帖子就是测试了,打算测一下功耗和传输速率(距离和丢包都测一下)

此帖出自RF/无线论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
快速回复 返回顶部 返回列表