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.
|