LE Manager
This document aims to guide developers on how to use the Bluetooth LE manager.
The chapter LE Manager Introduction gives an overview of the LE manager.
The chapter LE Extended Advertising describes the LE extended advertising manager and LE extended advertising data manager.
The chapter GATT Service Manager describes the manager for the ATT server role.
The chapter GATT Client Manager describes the manager for the ATT client role.

LE Manager Architecture
The LE manager is developed based on the interfaces provided by the LE Host. The purpose of developing this manager is to facilitate users in developing complex LE applications.
LE Manager Introduction
This chapter gives an overview of the LE manager, including:
LE Manager Sub-module Introduction
LE manager includes several sub-modules shown in the Sub-module Name column. The header file corresponding to the sub-module is displayed in the Header Files column.
Sub-module Name |
Header Files |
GAP Interface Usage Restrictions |
---|---|---|
LE Extended Advertising Manager |
|
Cannot use |
LE Extended Advertising Data Manager |
|
Cannot use |
LE Scan Manager |
|
Cannot use |
GATT Service Manager |
|
Cannot use |
GATT Client Manager |
|
Cannot use |
Bond Manager |
|
Cannot use |
LE Connection Parameters Update |
|
Cannot use |
LE Extended Advertising Manager and LE Extended Advertising Data Manager
The LE extended advertising manager is introduced in the chapter LE Extended Advertising Manager.
The LE extended advertising data manager is introduced in the chapter LE Extended Advertising Data Manager.
The LE extended advertising data manager is implemented based on the interface provided by the LE extended advertising manager. The interfaces exported by the LE extended advertising manager and the LE extended advertising data manager can be used simultaneously.
LE Scan Manager
When an application has multiple modules that need to use scan, it can use this module to independently manage scan. Each application module can independently manage scan policies and actions by scan handle, and has an independent callback to receive and filter reported advertising packets.
GATT Service Manager
The GATT service manager is a management module encapsulated by
ble_mgr.lib
based onprofile_server_ext.h
.The purpose of this module is to facilitate service development, it has the following advantages:
The GATT service manager will temporarily hold notifications that can’t be sent yet.
The GATT service manager internally implements the ATT sequential protocol and caches indications. The APP does not need to adhere to this protocol when handling indications.
The GATT service manager is introduced in the chapter GATT Service Manager.
GATT Client Manager
The GATT client manager is a management module encapsulated by
ble_mgr.lib
based onprofile_client_ext.h
.The purpose of this module is to facilitate client development, it has the following advantages:
The GATT client manager implements the discovery service process internally, so the APP only needs to register the service UUID.
The service table storage found is organized with a unified management structure within the GATT client manager, and also provides unified sample code for the APP to store the service table.
The GATT client manager implements the ATT sequential protocol internally and caches requests, so the APP implementing the client is not restricted by the protocol.
The GATT client manager is introduced in the chapter GATT Client Manager.
Bond Manager
This module is used to manage bond information, serving as a replacement for the bond module in the GAP layer.
LE Connection Parameters Update
This module is used to update ble connection parameters, serving as a replacement for the bond module in the GAP layer.
LE Manager Library Introduction
The functions of LE manager are provided by the ble_mgr.lib
.
The library directory and header files directory are shown as follows.
IC Type |
Library Directory |
Header Files Directory |
---|---|---|
|
|
|
|
||
|
If APP wants to use the LE manager, the ble_mgr.lib
shall be included in the project as shown in the following figure.

LE Manager Sample Project
LE Manager Initialization
The initialization sample code is shown below:
void app_ble_mgr_lib_init(void)
{
BLE_MGR_PARAMS param = {0};
param.ble_ext_adv.enable = true;
param.ble_ext_adv.adv_num = 1;
#if (BAP_BROADCAST_SINK | BAP_SCAN_DELEGATOR)
param.ble_scan.enable = true;
#endif
param.ble_conn.enable = true;
param.ble_conn.link_num = APP_MAX_BLE_LINK_NUM;
ble_mgr_init(¶m);
}
ble_mgr_init()
is used to initialize the ble_mgr.lib
.
GAP message and callback handling functions are shown below:
void app_handle_gap_msg(T_IO_MSG *p_gap_msg)
{
T_LE_GAP_MSG gap_msg;
uint8_t conn_id;
memcpy(&gap_msg, &p_gap_msg->u.param, sizeof(p_gap_msg->u.param));
ble_mgr_handle_gap_msg(p_gap_msg->subtype, &gap_msg);
......
}
T_APP_RESULT app_gap_callback(uint8_t cb_type, void *p_cb_data)
{
T_APP_RESULT result = APP_RESULT_SUCCESS;
T_LE_CB_DATA *p_data = (T_LE_CB_DATA *)p_cb_data;
ble_mgr_handle_gap_cb(cb_type, p_cb_data);
......
}
ble_mgr_handle_gap_msg()
is used to handle GAP messages.
ble_mgr_handle_gap_cb()
is used to handle GAP callback messages.
LE Extended Advertising
This chapter describes the LE extended advertising manager which is a new feature introduced in Bluetooth core spec 5.0.
The constants and function prototypes are defined in inc\ble_mgr\ble_ext_adv.h
.
This module is designed to make it easy for applications to manage the operation of multiple advertisements.
This module is encapsulated on the basis of gap_adv.h
and gap_ext_adv.h
.
When using this module, in order to prevent some unnecessary conflicts, it is recommended that applications shall not directly call the interface in
gap_ext_adv.h
and gap_adv.h
.
LE Extended Advertising Manager
This chapter will be introduced according to the following several parts:
Advertising manager initialization will be introduced in chapter Advertising Manager Initialization.
Advertising parameter initialization will be introduced in chapter Advertising Parameter Initialization.
Enable or disable advertising will be introduced in chapter Enable or Disable Advertising.
Handle callbacks of advertising will be introduced in chapter Handle Callbacks of Advertising.
Advertising parameter update after Bluetooth Host ready will be introduced in chapter Advertising Parameter Update.

LE Advertising Module Framework
The dotted box in the figure above is implemented by the Bluetooth LE manager library, and the APP may not care about it.
Each advertisement has its own advertising handle and is assigned a separate advertising set to manage its own broadcast-related parameters:
First call
ble_mgr_init()
to allocate storage for different broadcasts.Then create an advertising handle and set advertising parameters and advertising data for the broadcast.
Then the APP can enable or disable the broadcast.
Advertising Manager Initialization
This module shall be initialized before it can be used. The initialization steps are as follows:
Please call ble_mgr_init()
to initialize the LE advertising manager.
void app_ble_gap_ble_mgr_init(void)
{
BLE_MGR_PARAMS param = {0};
param.ble_ext_adv.enable = true;
param.ble_ext_adv.adv_num = app_ble_gap_get_ext_adv_num();
param.ble_conn.enable = true;
uint8_t supported_max_le_link_num = le_get_max_link_num();
param.ble_conn.link_num = ((MAX_BLE_LINK_NUM <= supported_max_le_link_num) ? MAX_BLE_LINK_NUM :
supported_max_le_link_num);
if (extend_app_cfg_const.ama_support || extend_app_cfg_const.xiaowei_support ||
extend_app_cfg_const.bisto_support || extend_app_cfg_const.xiaoai_support)
{
param.ble_adv_data.enable = true;
param.ble_adv_data.update_scan_data = true;
param.ble_adv_data.adv_interval = (extend_app_cfg_const.multi_adv_interval * 8) / 5;
app_ble_gap_gen_scan_rsp_data(&scan_rsp_data_len, scan_rsp_data);
param.ble_adv_data.scan_rsp_len = scan_rsp_data_len;
param.ble_adv_data.scan_rsp_data = scan_rsp_data;
}
param.ble_scan.enable = true;
ble_mgr_init(¶m);
}
void app_ble_gap_init(void)
{
......
app_ble_gap_ble_mgr_init();
}
int main(void)
{
......
app_ble_gap_init();
......
}
param.ble_ext_adv.enable = true;
means enabling LE extended advertising.param.ble_ext_adv.adv_num = app_ble_gap_get_ext_adv_num();
means the advertising handle number.If the APP wants to add a new advertising, the parameter
param.ble_ext_adv.adv_num
shall be increased by 1. The maximum advertising set number is 10.
Advertising Parameter Initialization
APP can use ble_ext_adv_mgr_init_adv_params()
to initialize advertising parameters.
This API is used to create advertising handle and initialize advertising parameters, advertising data, scan response data and random address.
void app_ble_common_adv_init(void)
{
T_LE_EXT_ADV_LEGACY_ADV_PROPERTY adv_event_prop = LE_EXT_ADV_LEGACY_ADV_CONN_SCAN_UNDIRECTED;
uint16_t adv_interval_min = 0xA0;
uint16_t adv_interval_max = 0xB0;
T_GAP_LOCAL_ADDR_TYPE own_address_type = GAP_LOCAL_ADDR_LE_RANDOM;
if (le_common_adv.use_static_addr_type)
{
own_address_type = GAP_LOCAL_ADDR_LE_RANDOM;
}
else
{
own_address_type = GAP_LOCAL_ADDR_LE_PUBLIC;
}
T_GAP_REMOTE_ADDR_TYPE peer_address_type = GAP_REMOTE_ADDR_LE_PUBLIC;
uint8_t peer_address[6] = {0, 0, 0, 0, 0, 0};
T_GAP_ADV_FILTER_POLICY filter_policy = GAP_ADV_FILTER_ANY;
uint8_t data_len = sizeof(app_cfg_nv.bud_local_addr) + sizeof(app_cfg_const.company_id);
app_ble_gap_gen_scan_rsp_data(&scan_rsp_data_len, scan_rsp_data);
uint8_t le_random_addr[6] = {0};
app_ble_rand_addr_get(le_random_addr);
ble_ext_adv_mgr_init_adv_params(&le_common_adv.adv_handle, adv_event_prop, adv_interval_min,
adv_interval_max, own_address_type, peer_address_type, peer_address,
filter_policy, 23 + data_len, app_ble_common_adv_data,
scan_rsp_data_len, scan_rsp_data, le_random_addr);
ble_ext_adv_mgr_register_callback(app_ble_common_adv_callback, le_common_adv.adv_handle);
}
static void app_ble_gap_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
T_BT_EVENT_PARAM *param = event_buf;
switch (event_type)
{
case BT_EVENT_READY:
{
if (app_cfg_const.rtk_app_adv_support || app_cfg_const.tts_support)
{
/* init here to avoid app_cfg_nv.bud_local_addr no mac info (due to factory reset) */
app_ble_common_adv_init();
}
}
break;
default:
break;
}
}
T_LE_EXT_ADV_LEGACY_ADV_PROPERTY adv_event_prop = LE_EXT_ADV_LEGACY_ADV_CONN_SCAN_UNDIRECTED;
Set
adv_event_prop
, the value please refer toT_LE_EXT_ADV_LEGACY_ADV_PROPERTY
.uint16_t adv_interval_min = 0xA0; uint16_t adv_interval_max = 0xB0;
Set advertising interval:
adv_interval_min
: Minimum advertising interval for undirected and low duty directed advertising. In units of 0.625 ms, range: 0x000020 to 0xFFFFFF.adv_interval_max
: Maximum advertising interval for undirected and low duty directed advertising. In units of 0.625 ms, range: 0x000020 to 0xFFFFFF.
T_GAP_LOCAL_ADDR_TYPE own_address_type = GAP_LOCAL_ADDR_LE_RANDOM;
Set
own_address_type
, the value please refer toT_GAP_LOCAL_ADDR_TYPE
.T_GAP_REMOTE_ADDR_TYPE peer_address_type = GAP_REMOTE_ADDR_LE_PUBLIC;
Set
peer_address_type
(only used for directed advertising).T_GAP_ADV_FILTER_POLICY filter_policy = GAP_ADV_FILTER_ANY;
Set
filter_policy
, the value please refer toT_GAP_ADV_FILTER_POLICY
.ble_ext_adv_mgr_init_adv_params()
Set advertising parameters into Bluetooth Host and create advertising handle.
ble_ext_adv_mgr_register_callback()
Register advertising callback, each advertisement has its own advertising callback. Advertising state and connection state will be reported by this callback.
Enable or Disable Advertising
ble_ext_adv_mgr_enable()
is used to enable advertising.If
ble_ext_adv_mgr_enable()
returnsGAP_CAUSE_SUCCESS
, it means the Bluetooth Host has already received this command and is ready to execute it, and when this command execution is complete, the Bluetooth Host will sendBLE_EXT_ADV_MGR_ADV_ENABLED
to the callback functions registered for advertising.bool app_ble_common_adv_start(uint16_t duration_10ms) { if (le_common_adv.state == BLE_EXT_ADV_MGR_ADV_DISABLED) { if (ble_ext_adv_mgr_enable(le_common_adv.adv_handle, duration_10ms) == GAP_CAUSE_SUCCESS) { return true; } else { return false; } } else { APP_PRINT_TRACE0("app_ble_common_adv_start: Already started"); return true; } }
ble_ext_adv_mgr_disable()
is used to disable advertising.If
ble_ext_adv_mgr_disable()
returnsGAP_CAUSE_SUCCESS
, it means the Bluetooth Host has already received this command and is ready to execute. When this command execution is complete, the Bluetooth Host will sendBLE_EXT_ADV_MGR_ADV_DISABLED
to the callback functions registered for advertising.bool app_ble_common_adv_stop(int8_t app_cause) { APP_PRINT_INFO0("app_ble_common_adv_stop"); if (ble_ext_adv_mgr_disable(le_common_adv.adv_handle, app_cause) == GAP_CAUSE_SUCCESS) { return true; } else { return false; } }
Handle Callbacks of Advertising
Two events will be notified: BLE_EXT_ADV_STATE_CHANGE
and BLE_EXT_ADV_SET_CONN_INFO
.
-
This message is used to notify the application of the final desired advertising state of the registered advertising set. There are two advertising state events that may be sent to the advertising set callback function:
BLE_EXT_ADV_MGR_ADV_ENABLED
andBLE_EXT_ADV_MGR_ADV_DISABLED
. -
This message is used to notify the application of the connection information for the LE link that was established with the advertising set.
static void app_ble_common_adv_callback(uint8_t cb_type, void *p_cb_data)
{
T_BLE_EXT_ADV_CB_DATA cb_data;
memcpy(&cb_data, p_cb_data, sizeof(T_BLE_EXT_ADV_CB_DATA));
switch (cb_type)
{
case BLE_EXT_ADV_STATE_CHANGE:
{
le_common_adv.state = cb_data.p_ble_state_change->state;
if (le_common_adv.state == BLE_EXT_ADV_MGR_ADV_ENABLED)
{
}
else if (le_common_adv.state == BLE_EXT_ADV_MGR_ADV_DISABLED)
{
switch (cb_data.p_ble_state_change->stop_cause)
{
case BLE_EXT_ADV_STOP_CAUSE_APP:
break;
case BLE_EXT_ADV_STOP_CAUSE_CONN:
break;
case BLE_EXT_ADV_STOP_CAUSE_TIMEOUT:
if ((app_cfg_const.bud_role == REMOTE_SESSION_ROLE_SECONDARY) && le_common_adv.use_static_addr_type)
{
/*secondary ear ota need modify the random address and start advertising,
when advertising timeout, the random address shall be set back to le_rws_random_addr*/
uint8_t rand_addr[6] = {0};
app_ble_rand_addr_get(rand_addr);
app_ble_common_adv_set_random(rand_addr);
}
break;
default:
break;
}
}
}
break;
case BLE_EXT_ADV_SET_CONN_INFO:
APP_PRINT_TRACE4("app_ble_common_adv_callback: BLE_EXT_ADV_SET_CONN_INFO conn_id 0x%x, adv_handle %d, local_addr_type %d, local_bd %b",
cb_data.p_ble_conn_info->conn_id,
cb_data.p_ble_conn_info->adv_handle,
cb_data.p_ble_conn_info->local_addr_type,
TRACE_BDADDR(cb_data.p_ble_conn_info->local_addr));
break;
default:
break;
}
return;
}
Advertising Parameter Update
ble_ext_adv_mgr_set_adv_data()
is used to update advertising data.void app_ble_common_adv_bud_role_update(T_REMOTE_SESSION_ROLE role) { /*app_ble_common_adv_data update bud role*/ if (app_ble_common_adv_data[20] != role) { app_ble_common_adv_data[20] = role; ble_ext_adv_mgr_set_adv_data(le_common_adv.adv_handle, sizeof(app_ble_common_adv_data), app_ble_common_adv_data); } else { //bud role not change } }
ble_ext_adv_mgr_set_random()
is used to update random addr.T_GAP_CAUSE app_adv_update_randomaddr(uint8_t *random_address) { return ble_ext_adv_mgr_set_random(adv_handle, random_address); }
ble_ext_adv_mgr_set_scan_response_data()
is used to update scan response data.T_GAP_CAUSE app_adv_update_scanrspdata(uint8_t *p_scan_data, uint16_t scan_data_len) { return ble_ext_adv_mgr_set_scan_response_data(adv_handle, scan_data_len, p_scan_data); }
Update advertising parameters:
LE Extended Advertising Data Manager
If APP expects to use the public address to advertise multiple connectable advertisings. It is recommended to use the LE extended advertising data manager.
This manager only starts advertising with one advertising handle, and this manager will add new advertising data to the queue and regularly update advertising data to achieve different advertisements.

LE Advertising Data Module
The dotted box in the figure above is implemented by the LE manager library, APP may not care about it.
Limitations:
Only one advertising interval can be set, shared by multiple advertising data.
For example, if the advertising interval is 50ms, only one kind of advertising data needs to be sent, the interval is 50ms. If two kinds of advertising data need to be sent, the interval is 100ms, and so on.
adv_event_prop
cannot be specified, the default value isLE_EXT_ADV_LEGACY_ADV_CONN_SCAN_UNDIRECTED
.Advertising address can only set public address, other address type is invalid.
Advertising Data Initialization
Call ble_mgr_init()
to initialize the LE advertising data manager.
void app_ble_gap_ble_mgr_init(void)
{
BLE_MGR_PARAMS param = {0};
param.ble_ext_adv.enable = true;
param.ble_ext_adv.adv_num = app_ble_gap_get_ext_adv_num();
......
if (extend_app_cfg_const.ama_support || extend_app_cfg_const.xiaowei_support ||
extend_app_cfg_const.bisto_support || extend_app_cfg_const.xiaoai_support)
{
param.ble_adv_data.enable = true;
param.ble_adv_data.update_scan_data = true;
param.ble_adv_data.adv_interval = (extend_app_cfg_const.multi_adv_interval * 8) / 5;
app_ble_gap_gen_scan_rsp_data(&scan_rsp_data_len, scan_rsp_data);
param.ble_adv_data.scan_rsp_len = scan_rsp_data_len;
param.ble_adv_data.scan_rsp_data = scan_rsp_data;
}
......
ble_mgr_init(¶m);
}
void app_ble_gap_init(void)
{
......
app_ble_gap_ble_mgr_init();
}
int main(void)
{
......
app_ble_gap_init();
......
}
param.ble_adv_data.enable = true;
It means enabling the LE advertising data manager.
param.ble_adv_data.update_scan_data = true;
It means the LE advertising data manager updates scan response data.
param.ble_adv_data.adv_interval = (extend_app_cfg_const.multi_adv_interval * 8) / 5;
It means the LE advertising data manager sets the advertising interval.
Enable or Disable Advertising Data
The function ble_adv_data_enable()
is used to enable the advertising data manager,
and the function ble_adv_data_disable()
is used to disable the advertising data manager.
The function ble_adv_data_add()
is used to add the advertising data and scan response
data into the data queue. Then, the corresponding advertising packet will be transmitted over the air.
bool le_xm_xiaoai_adv_start(uint16_t timeout_sec)
{
......
if (ble_adv_data_add(&p_le_xm_xiaoai_adv_handle, sizeof(xm_xiaoai_adv_data),
(uint8_t *)&xm_xiaoai_adv_data,
sizeof(xm_xiaoai_scan_rsp_data), (uint8_t *)&xm_xiaoai_scan_rsp_data))
{
app_xiaoai_device_start_adv_timer(timeout_sec);
return true;
}
......
}
The function ble_adv_data_del()
is used to delete the advertising data and scan response
data from the data queue. Then, the corresponding advertising packet will not be transmitted over the air.
bool le_xm_xiaoai_adv_stop(void)
{
......
if (ble_adv_data_del(p_le_xm_xiaoai_adv_handle))
{
p_le_xm_xiaoai_adv_handle = NULL;
return true;
}
......
}
GATT Service Manager
This chapter describes the GATT service module which is used to implement the services.
The constants and function prototypes are defined in inc\ble_mgr\bt_gatt_svc.h
.
This module is encapsulated on the basis of profile_server.h
and profile_server_ext.h
.
When using this module, in order to prevent some unnecessary conflicts, APP shall not directly call the interface in
profile_server.h
and profile_server_ext.h
.
This chapter will be introduced according to the following several parts:
GATT service manager initialization will be introduced in chapter GATT Service Manager Initialization.
GATT service related APIs will be introduced in chapter GATT Service APIs.
GATT service implementation will be introduced in chapter GATT Service Implementation.
Handle callbacks of GATT service will be introduced in chapter Handle Callback of GATT Service.
GATT Service Manager Initialization
This module shall be initialized before it can be used.
Please call gatt_svc_init()
to initialize the GATT service manager.
bool gatt_svc_init(uint16_t mode, uint8_t svc_num);
mode
: GATT service mode.GATT_SVC_DISABLE
: Not use GATT service manager.GATT_SVC_USE_NORMAL_SERVER
: GATT service manager APIs based onprofile_service.h
.GATT_SVC_USE_EXT_SERVER
: GATT service manager APIs based onprofile_service_ext.h
.
If APP wants to use the GATT service manager, the parameter
mode
shall be set toGATT_SVC_USE_NORMAL_SERVER
orGATT_SVC_USE_EXT_SERVER
. If APP wants to use ATT over BREDR or EATT over BREDR, the parametermode
shall be set toGATT_SVC_USE_EXT_SERVER
.number
: GATT service number.0
.Before calling the initialization API, it is necessary to call several APIs to set the service number and register the callback function.
-
If the GATT service mode is set to
GATT_SVC_USE_EXT_SERVER
, this API shall be set totrue
before callingserver_init()
. -
This API is used to initialize the maximum GATT service number that can be registered.
server_register_app_cb()
orserver_ext_register_app_cb()
If the GATT service mode is set to
GATT_SVC_USE_NORMAL_SERVER
, the APIserver_register_app_cb()
will be used to register the general callback function. If the GATT service mode is set toGATT_SVC_USE_EXT_SERVER
, the APIserver_ext_register_app_cb()
will be used to register the general callback function. The APP shall callgatt_svc_handle_profile_data_cmpl()
when receivingPROFILE_EVT_SEND_DATA_COMPLETE
.
-
Non-zero.
If the parameter
svc_num
is non-zero, the APP does not need to call other interfaces before calling this API.
GATT Service APIs
gatt_svc_add()
: Register specific service.gatt_svc_send_data()
: Send notification or indication.gatt_svc_service_changed_indicate()
: Send service changed indication.gatt_svc_read_confirm()
: When the APP does not want to return the read result via callback, the cause inread_attr_cb
shall be set toAPP_RESULT_PENDING
. The APP shall call this API to return the read result.gatt_svc_write_confirm()
: When the APP does not want to return the write result via callback, the cause inwrite_attr_cb
shall be set toAPP_RESULT_PENDING
. The APP shall call this API to return the write result.gatt_svc_get_num()
: Get the number of registered services.APIs for querying characteristic UUID and attribute index:
gatt_svc_find_char_uuid_by_index()
: Find characteristic UUID through attribute index.gatt_svc_find_char_index_by_uuid()
: Find attribute index through characteristic UUID.gatt_svc_find_char_index_by_uuid16()
: Find the attribute index using a 16-bit characteristic UUID.
gatt_svc_handle_profile_data_cmpl()
: Used for indication and notification flow control.If the parameter
svc_num
ingatt_svc_init()
is0
during initialization, the APP needs to callgatt_svc_handle_profile_data_cmpl()
when receivingPROFILE_EVT_SEND_DATA_COMPLETE
. If the parametersvc_num
is non-zero, the APP does not need to call this function.
GATT Service Implementation
The guideline on how to develop a specific service is as follows:
Define service and profile spec.
Define service attribute table.
Define callback function between service and APP.
Define APIs for APP.
More information about step 1 and step 2, please refer to the chapter Implementation of Specific Service in the LE Host.
The sample code of some SIG standard services, please refer to the files in the directory src\ble\bt_gatt_svc
.
Define Callback Function between Service and APP
When implementing the GATT service based on the GATT service module, it is necessary to define the callback function for that service. This should be registered together when registering the service, in order to send events and data to the APP.
Taking BAS as an example, describe the specific process of defining a callback function.
Define macros for the message corresponding to each characteristic’s property.
In the BAS service, the battery level characteristic supports read and notify properties, so two message macros are defined:
A GATT message for notifying the reading of the battery level.
A GATT message for notifying CCCD value updates.
#define GATT_MSG_BAS_SERVER_READ_BATTERY_LEVEL_IND 0x00 #define GATT_MSG_BAS_SERVER_CCCD_UPDATE 0x01
Define the message data structure corresponding to different messages.
/** @brief BAS server read ind * The message data for GATT_MSG_BAS_SERVER_READ_BATTERY_LEVEL_IND. */ typedef struct { T_SERVER_ID service_id; } T_BAS_SERVER_READ_BATTERY_LEVEL_IND; /** @brief BAS server cccd data update info * The message data for GATT_MSG_BAS_SERVER_CCCD_UPDATE. */ typedef struct { T_SERVER_ID service_id; uint16_t char_uuid; uint16_t cccd_cfg; } T_BAS_SERVER_CCCD_UPDATE;
Define the callback function.
The parameter
type
is the previously defined message type, the callback function is registered together when registering the service.typedef T_APP_RESULT(*P_FUN_BAS_SERVER_APP_CB)(uint16_t conn_handle, uint16_t cid, uint8_t type, void *p_data); T_SERVER_ID bas_reg_srv(P_FUN_BAS_SERVER_APP_CB app_cb) { T_SERVER_ID service_id; if (false == gatt_svc_add(&service_id, (uint8_t *)bas_attr_tbl, bas_attr_tbl_size, &bas_cbs, NULL)) { PROFILE_PRINT_ERROR("bas_reg_srv: service_id %d", service_id); service_id = 0xff; } pfn_bas_cb = app_cb; return service_id; }
Define APIs for APP
Define APIs for APP access to services.
xxx_reg_srv
: Register the specific service and callback function.T_SERVER_ID bas_reg_srv(P_FUN_BAS_SERVER_APP_CB app_cb);
xxx_read_confirm
orxxx_write_confirm
: Confirm when receiving the corresponding read or write request.bool bas_battery_level_read_confirm(uint16_t conn_handle, uint16_t cid, uint8_t service_id, uint8_t battery_level);
xxx_send_xxx
: Send notification or indication.bool bas_send_battery_level_notify(uint16_t conn_handle, uint8_t service_id, uint8_t battery_level);
Handle Callback of GATT Service
General Callback
When the parameter svc_num of gatt_svc_init()
is not 0
, the APP can call gatt_svc_register_general_cb()
to register a general callback function,
which is used to notify the APP of the result of registering the service.
void app_ble_service_init(void)
{
gatt_svc_init(GATT_SVC_USE_NORMAL_SERVER, 1);
gatt_svc_register_general_cb(app_gatt_svc_general_cb);
}
void app_gatt_svc_general_cb(uint8_t type, void *p_data)
{
if (type == GATT_SVC_EVENT_REG_RESULT)
{
T_GATT_SVC_REG_RESULT *p_result = (T_GATT_SVC_REG_RESULT *)p_data;
APP_PRINT_INFO1("GATT_SVC_EVENT_REG_RESULT: result 0x%x", p_result->result);
}
else if (type == GATT_SVC_EVENT_REG_AFTER_INIT_RESULT)
{
T_GATT_SVC_REG_AFTER_INIT_RESULT *p_result = (T_GATT_SVC_REG_AFTER_INIT_RESULT *)p_data;
APP_PRINT_INFO2("GATT_SVC_EVENT_REG_AFTER_INIT_RESULT: service_id %d, cause 0x%x",
p_result->service_id, p_result->cause);
}
}
Specific Service Callback
When the APP receives the message sent by the callback, it forcibly converts the type of p_data
into the corresponding structure type based on the message type.
T_APP_RESULT app_bas_gatt_svc_callback(uint16_t conn_handle, uint16_t cid, uint8_t type,
void *p_data)
{
if (type == GATT_MSG_BAS_SERVER_READ_BATTERY_LEVEL_IND)
{
uint8_t battery_level = 90;
bas_battery_level_read_confirm(conn_handle, cid, bas_gatt_srv_id, battery_level);
}
else if (type == GATT_MSG_BAS_SERVER_CCCD_UPDATE)
{
T_BAS_SERVER_CCCD_UPDATE *p_update = (T_BAS_SERVER_CCCD_UPDATE *)p_data;
APP_PRINT_INFO("app_bas_gatt_svc_callback: char uuid 0x%x, cccd_cfg 0x%x",
p_update->char_uuid, p_update->cccd_cfg);
}
return APP_RESULT_SUCCESS;
}
GATT Client Manager
This chapter describes the GATT client module which is used to implement the service client role.
The constants and function prototypes are defined in inc\ble_mgr\bt_gatt_client.h
.
This module is encapsulated on the basis of profile_client.h
and profile_client_ext.h
.
When using this module, in order to prevent some unnecessary conflicts, applications shall not directly call the interface in
profile_client.h
and profile_client_ext.h
.
This chapter will be introduced according to the following several parts:
GATT client manager initialization will be introduced in chapter GATT Client Manager Initialization.
GATT client related APIs will be introduced in chapter GATT Client APIs.
GATT client implementation will be introduced in chapter GATT Client Implementation.
Handle callbacks of GATT client will be introduced in chapter Handle Callback of GATT Client.
Service table storage sample will be introduced in chapter Service Table Storage.
GATT Client Manager Initialization
This module shall be initialized before it can be used.
Please call gatt_client_init()
to initialize the GATT service manager.
bool gatt_client_init(uint16_t mode);
The bit values of the parameter mode
can refer to GATT Client Discover Mode Bit Field.
void test(void)
{
gatt_client_init(GATT_CLIENT_DISCOV_MODE_REG_SVC_BIT | GATT_CLIENT_DISCOV_MODE_CCCD_STORAGE_BIT);
}
GATT Client APIs
gatt_client_spec_register()
: Register GATT client.gatt_client_start_discovery_all()
: Send discovery all primary services request.gatt_client_read()
: Read characteristic value or characteristic descriptor via attribute handle.gatt_client_read_uuid()
: Read the characteristic value through the characteristic UUID.gatt_client_write()
: Write characteristic value or characteristic descriptor through attribute handle.gatt_client_ind_confirm()
: When receiving an indication from the server, the APP can call this API to send a confirmation itself.gatt_client_enable_srv_cccd()
: Enable all CCCDs in the service.gatt_client_enable_char_cccd()
: Enable the CCCD of a certain characteristic.gatt_client_get_char_cccd()
: Get the CCCD value of a certain characteristic.gatt_client_check_cccd_enabled()
: Check if the CCCD of the characteristic is enabled.gatt_client_find_char_descriptor_range()
: Get the range of characteristic descriptor attribute handles.gatt_client_find_char_handle()
: Get the attribute handle information of a certain characteristic.gatt_client_find_char_cccd_handle()
: Get the attribute handle of a certain characteristic’s CCCD.gatt_client_find_primary_srv_by_include()
: Find the primary service through the include service.gatt_client_find_include_srv_by_primary()
: Find the included service through the primary service.gatt_client_get_char_num()
: Get the total number of a certain characteristic.gatt_client_get_char_prop()
: Get the property of a certain characteristic.gatt_client_is_load_from_ftl()
: Determine whether the service table is loaded from FTL.gatt_client_cfg_client_supported_feature()
: Configure the features supported by the GATT client.
By default, these features are not supported. If needed, the app can be configured according to requirements.
#define GATT_SVC_CLIENT_SUPPORTED_FEATURES_DEFAULT_VALUE 0x00 /**< Server shall not use any of the features associated with that bit when communicating with this client. */ #define GATT_SVC_CLIENT_SUPPORTED_FEATURES_ROBUST_CACHING_BIT 0x01 /**< The client supports robust caching. */ #define GATT_SVC_CLIENT_SUPPORTED_FEATURES_EATT_BEARER_BIT 0x02 /**< The client supports Enhanced ATT bearer. */ #define GATT_SVC_CLIENT_SUPPORTED_FEATURES_MULTI_NOTIF_BIT 0x04 /**< The client supports receiving ATT_MULTIPLE_HANDLE_VALUE_NTF PDUs. */ #define GATT_SVC_CLIENT_SUPPORTED_FEATURES_MASK 0x07
gatt_client_storage_register()
: Register callback functions related to GATT client storage.
GATT Client Implementation
The guideline on how to develop a specific client is as follows:
Define callback function between client and APP.
Define APIs for APP.
Taking BAS client as an example, describe the specific process of defining a client callback function.
Define Callback Function between Client and APP
Define the corresponding message macros based on the behaviors and functions that the client needs to have.
For a BAS client, it needs to support these functions: service discovery, reading characteristic values, writing CCCD, and receiving notifications. So the macro definition for message is as follows:
The result of the service discovery.
The result of reading the characteristic value.
The message sent to the APP upon receiving a notification.
The result of configuring the CCCD value.
#define GATT_MSG_BAS_CLIENT_DIS_DONE 0x00 #define GATT_MSG_BAS_CLIENT_READ_BATTERY_LEVEL_RESULT 0x01 #define GATT_MSG_BAS_CLIENT_BATTERY_LEVEL_NOTIFY 0x02 #define GATT_MSG_BAS_CLIENT_CCCD_CFG_RESULT 0x03
Define the message data structure corresponding to different messages.
/** @brief BAS client discovery result * The message data for GATT_MSG_BAS_CLIENT_DIS_DONE. */ typedef struct { bool is_found; bool load_from_ftl; uint8_t srv_instance_num; } T_BAS_CLIENT_DIS_DONE; /** @brief BAS client read result * The message data for GATT_MSG_BAS_CLIENT_READ_BATTERY_LEVEL_RESULT. */ typedef struct { uint8_t srv_instance_id; uint16_t cause; uint8_t battery_level; } T_BAS_CLIENT_READ_BATTERY_LEVEL_RESULT; /** @brief BAS client notify info * The message data for GATT_MSG_BAS_CLIENT_BATTERY_LEVEL_NOTIFY. */ typedef struct { uint8_t srv_instance_id; uint8_t battery_level; } T_BAS_CLIENT_BATTERY_LEVEL_NOTIFY; /** @brief BAS client configure cccd data info * The message data for GATT_MSG_BAS_CLIENT_CCCD_CFG_RESULT. */ typedef struct { uint8_t srv_instance_id; uint16_t cause; bool enable; } T_BAS_CLIENT_CCCD_CFG_RESULT;
Define the callback function.
The parameter
type
is the previously defined message type, the callback function is registered together when registering the client.typedef T_APP_RESULT(*P_FUN_BAS_CLIENT_APP_CB)(uint16_t conn_handle, uint8_t type, void *p_data); bool bas_client_init(P_FUN_BAS_CLIENT_APP_CB app_cb) { T_ATTR_UUID srv_uuid = {0}; srv_uuid.is_uuid16 = true; srv_uuid.p.uuid16 = GATT_UUID_BATTERY; if (gatt_client_spec_register(&srv_uuid, bas_client_cbs) == GAP_CAUSE_SUCCESS) { /* register callback for profile to inform application that some events happened. */ bas_client_cb = app_cb; return true; } return false; }
Define APIs for APP
Define APIs for APP to use.
xxx_client_init
: register specific client.bool bas_client_init(P_FUN_BAS_CLIENT_APP_CB app_cb);
xxx_client_cfg_cccd
: Configure CCCD.bool bas_client_cfg_cccd(uint16_t conn_handle, uint8_t srv_instance_id, bool enable);
xxx_client_read_xxx
orxxx_client_write_xxx
: Read or write characteristic value.bool bas_client_read_battery_level(uint16_t conn_handle, uint8_t srv_instance_id);
Handle Callback of GATT Client
When the APP receives the message sent by the callback, it forcibly converts the type of p_data
into the corresponding structure type based on the message type.
T_APP_RESULT app_bas_client_callback(uint16_t conn_handle, uint8_t type, void *p_data)
{
T_APP_RESULT app_result = APP_RESULT_SUCCESS;
if (type == GATT_MSG_BAS_CLIENT_DIS_DONE)
{
T_BAS_CLIENT_DIS_DONE *p_bas_done = (T_BAS_CLIENT_DIS_DONE *)p_data;
APP_PRINT_INFO("app_bas_client_callback DIS_DONE: conn_handle 0x%x, is_found %d, load_from_ftl %d, srv_instance_num %d",
conn_handle, p_bas_done->is_found, p_bas_done->load_from_ftl, p_bas_done->srv_instance_num);
}
else if (type == GATT_MSG_BAS_CLIENT_READ_BATTERY_LEVEL_RESULT)
{
T_BAS_CLIENT_READ_BATTERY_LEVEL_RESULT *p_write_result = (T_BAS_CLIENT_READ_BATTERY_LEVEL_RESULT *)
p_data;
APP_PRINT_INFO("app_bas_client_callback READ_RESULT: conn_handle 0x%x, srv_instance_id %d, cause 0x%x, battery_level %d",
conn_handle, p_write_result->srv_instance_id, p_write_result->cause, p_write_result->battery_level);
}
else if (type == GATT_MSG_BAS_CLIENT_BATTERY_LEVEL_NOTIFY)
{
T_BAS_CLIENT_BATTERY_LEVEL_NOTIFY *p_notify_result = (T_BAS_CLIENT_BATTERY_LEVEL_NOTIFY *)
p_data;
APP_PRINT_INFO("app_bas_client_callback NOTIFY: conn_handle 0x%x, srv_instance_id %d, battery_level %d",
conn_handle, p_notify_result->srv_instance_id, p_notify_result->battery_level);
}
return app_result;
}
Service Table Storage
The service table storage found is organized with a unified management structure within the GATT client manager, and also provides unified sample code for the APP to store the service table.
The sample code is located in src\ble\gatt_client
. The application can call gattc_tbl_storage_init()
to enable service table storage.
When this feature is enabled, for bonded devices, the service information will be stored in FTL after the first services discovery is completed. When reconnecting the device, it will first read information from the FTL, allowing the services discovery process to be skipped.
void app_lea_profile_init(void)
{
#if (CCP_CALL_CONTROL_SERVER || MCP_MEDIA_CONTROL_SERVER)
gatt_svc_init(GATT_SVC_USE_EXT_SERVER, MAX_BLE_SRV_NUM);
#endif
#if GATTC_TBL_STORAGE_SUPPORT
gattc_tbl_storage_init();
#endif
}