1017 views|2 replies

26

Posts

2

Resources
The OP
 

BearPi-Pico H2821 Star Flash Development Board Review (V) - BLE Serial Port Transparent Transmission Test [Copy link]

This post was last edited by FuShenxiao on 2024-8-27 09:14

Official case implementation

The official case uses two development boards to implement BLE data transmission test. Development board A receives data through the serial port, and then transmits it to development board B through BLE. Development board B prints out the received data through the serial port. Similarly, development board B receives data through the serial port, and then transmits it to development board A through BLE. Development board A prints out the received data through the serial port. In the test, one development board is required as the server and the other development board is required as the client. After the two development boards are paired, they can send messages to each other. The connection method is as follows

Configuring the BLE UART Server

Select BLE UART Server Sample

Select protocol

Complete the configuration and exit the configuration environment to compile

Configuring the BLE UART Client

Select BLE UART Client Sample

Select protocol

Complete the configuration and exit the configuration environment to compile

Server Initialization

First, initialize the SDK

Initialize and start the BLE task

Configure and start ADV, and finally enable BLE service

Client Initialization

First, initialize the SDK

Exchange mtu information and establish contact with the Server

Client Discovery Features

Client discovers feature descriptors

Client receives read response

After the client is initialized, the server log shows

You can see the mtu exchange

Send Test

Server sends, Client receives

Client sends Server receives

Code Implementation

ble_uart_server code

#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 code

#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 code

#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 code

#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 code

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

Code Interpretation

The code first enters the ble_uart_entry task entry of ble_uart.c. The code is as follows

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

Create Server tasks and Client tasks separately

Server Tasks

For the Server task, you need to complete the initialization and define the interrupt callback function when receiving information. The specific code is as follows

#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)

For Server initialization, the specific code is as follows:

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;
}

Device initialization

1. Use ble_uart_server_power_on_cbk to enable the BLE protocol stack

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

2. Use ble_uart_server_enable_cbk to enable the 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();
}

In this step, you need to complete the following:

  • Use gap_ble_set_local_name to set the local device name
  • Use gap_ble_set_local_addr to set the local device address
  • Register the GATT server using gatts_register_server
  • Creating a uart service using GATT
  • Initialize the bth ota channel using bth_ota_init

3. Use bts_dev_manager_register_callbacks to register the BT device manager callback function

GAP parameter initialization

1. Use ble_uart_server_adv_enable_cbk to enable the ADV of the Server

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. Initialize ADV using ble_uart_server_connect_change_cbk

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

Among them, you need to complete setting ADV information -> setting scan feedback information -> starting 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. Use ble_uart_server_pair_result_cb to initialize the output information after successful pairing

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. Use gap_ble_register_callbacks to register the BLE GAP callback function

Create task callback function initialization

1. Use ble_uart_server_service_add_cbk to create a service add callback function, use ble_uart_server_characteristics_add_cbk to create a characteristic add callback function, use ble_uart_server_descriptor_add_cbk to create a descriptor add callback function, and use ble_uart_service_start_cbk to create a start service callback function

/* 服务添加回调 */
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. Create log information when receiving read information/receiving write information

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. Create mtu exchange log information

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. Register the callback function using gatts_register_callbacks

After completing the above Server initialization steps, use uapi_uart_register_rx_callback to register the receive callback function to complete the Server task creation.

Client Tasks

For the Client task, it is also necessary to complete the initialization and define the interrupt callback function when receiving information. The specific code implementation is as follows

#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 */

For Client initialization, GATT registration and GAP callback function definition need to be completed. The specific code is as follows

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;
}

Define GAP related callback functions

1. Use ble_uart_client_set_scan_param_cbk to set the scan parameter callback. In this step, the Client needs to delete all BLE paired devices first and then start scanning.

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. Use ble_uart_client_scan_result_cbk to set the scan result callback. In this step, if the connection address of the Client matches that of the Server, the scan stops and a connection is established with the device instead.

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. Use ble_uart_client_connect_change_cbk to implement the connection status callback. This step is used to display the relevant parameters of the connected device, including 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. Use ble_uart_client_pair_result_cb to implement the matching result callback. In this step, the Client needs to send an exchange MTU request to the Server.

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. Use gap_ble_register_callback to register the BLE GAP callback function

Define device-related callback functions

1. Use ble_uart_client_power_on_cbk to enable the BLE protocol stack

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

2. Use ble_uart_client_enable_cbk to start the Client's BT stack. In this step, you need to complete the GATT client registration and set the scanning parameters.

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. Use bts_dev_manager_register_callbacks to register the BT device manager callback function

Register GATT callback function

1. Use ble_uart_client_discover_service_cbk to discover characteristics

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. Use ble_uart_client_discover_service_compl_cbk to discover characteristic descriptors

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. Use ble_uart_client_discover_descriptor_cbk to initiate a read request based on the 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. Use ble_uart_client_discover_service_compl_cbk to compare the uuids of Client and Service.

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. Use ble_uart_client_discover_character_compl_cbk as the callback function for the Client to complete the discovery of features

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. Use ble_uart_client_discover_descriptor_compl_cbk as the callback function for the Client to complete the discovery of characteristic descriptors

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. Use ble_uart_client_read_cfm_cbk as the callback function triggered by receiving a read request

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. Use ble_uart_client_read_compl_cbk as the callback function for completing the read trigger

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. Use ble_uart_client_write_cfm_cbk as the callback function triggered by receiving a write request

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. Use ble_uart_client_mtu_change_cbk as the callback function to complete the mtu exchange trigger, and the Client discovers the service under 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. Use ble_uart_client_notification_cbk as the callback function triggered by receiving the notification from the Server

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. Use ble_uart_client_indication_cbk as the callback function triggered by receiving the indication from the Server

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. Register the GATT client callback function using gattc_register_callbacks

After completing the above Client initialization steps, use uapi_uart_register_rx_callback to register the receive callback function to complete the Client task creation.

Summarize

The above is how to complete the Bluetooth BLE data transmission on the Bear Pi. This process is basically the same as the general BLE transmission logic. The content of this article is translated based on my current experience and understanding of the code. If there are some incomplete understandings or errors in the translation, I hope you can criticize and correct them.

This post is from RF/Wirelessly

Latest reply

I think I can test the transmission rate.   Details Published on 2024-8-27 14:17
 

6788

Posts

2

Resources
2
 

I think I can test the transmission rate.

This post is from RF/Wirelessly

Comments

The next review post will be about testing. I plan to test the power consumption and transmission rate (both distance and packet loss).  Details Published on 2024-8-27 14:30
 
 

26

Posts

2

Resources
3
 
wangerxian posted on 2024-8-27 14:17 I think we can test the transmission rate.

The next review post will be about testing. I plan to test the power consumption and transmission rate (both distance and packet loss).

This post is from RF/Wirelessly
 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

快速回复 返回顶部 Return list