Nordic nRF5 SDK 学习笔记之二, 蓝牙主机与从机建立联结及服务发现过程
基于 NORDIC softDevice 蓝牙协议栈 S132, nRF5 SDK Ver 15.0.0
蓝牙角色: 主机,ble_central
文章内容: 蓝牙主机与从机建立联结及服务发现过程
程序样例: nRF5_SDK_15.0.0\examples\ble_central\ble_app_uart_c
关于NORDIC softDevice 蓝牙协议栈主机的蓝牙初始化,请参见博客文章: NORDIC softDevice 蓝牙协议栈初始化程序分析(蓝牙主机,ble_central)
蓝牙主机与从机的联结及服务发现过程图
程序调用流程
蓝牙主机扫描启动, scan_start()
1. 发现广播从机,并触发广播报告事件;
回调函数 ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) 处理 BLE_GAP_EVT_ADV_REPORT 事件;
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
...
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_ADV_REPORT:
on_adv_report(&p_gap_evt->params.adv_report);
break; // BLE_GAP_EVT_ADV_REPORT
...
}
2. 判断广播报告中 UUID 是否为需要的 UUID ?
处理函数 on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report);
判断函数 ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &m_nus_uuid);
static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
{
ret_code_t err_code;
if (ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &m_nus_uuid))
{
...
}
}
3. 联结蓝牙从机,并触发联结事件 (注: 蓝牙实际是通过 MAC 地址进行联结的)
BLE 联结函数 sd_ble_gap_connect(&p_adv_report->peer_addr,
&m_scan_params,&m_connection_param,APP_BLE_CONN_CFG_TAG);
static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
{
ret_code_t err_code;
if (ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &m_nus_uuid))
{
err_code = sd_ble_gap_connect(&p_adv_report->peer_addr,
&m_scan_params,
&m_connection_param,
APP_BLE_CONN_CFG_TAG);
...
}
}
4. 蓝牙联结成功后,启动蓝牙服务数据发现 ble_db_discovery_start(),
并**服务发现回调函数 ble_db_discovery_on_ble_evt(ble_evt_t const * p_ble_evt,void * p_context);
蓝牙联结事件处理函数 ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context);
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
ret_code_t err_code;
ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
switch (p_ble_evt->header.evt_id)
{
...
case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("Connected to target");
err_code = ble_nus_c_handles_assign(&m_ble_nus_c, p_ble_evt->evt.gap_evt.conn_handle, NULL);
APP_ERROR_CHECK(err_code);
err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
APP_ERROR_CHECK(err_code);
// start discovery of services. The NUS Client waits for a discovery result
err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
APP_ERROR_CHECK(err_code);
break;
...
}
}
5. 蓝牙发现主服务事件处理, 处理函数: ble_db_discovery_on_ble_evt();
处理事件 BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP;
void ble_db_discovery_on_ble_evt(ble_evt_t const * p_ble_evt,
void * p_context)
{
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
VERIFY_PARAM_NOT_NULL_VOID(p_context);
VERIFY_MODULE_INITIALIZED_VOID();
ble_db_discovery_t * p_db_discovery = (ble_db_discovery_t *)p_context;
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
on_primary_srv_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
...
}
}
6. 蓝牙发现服务特征值事件处理, 处理函数: ble_db_discovery_on_ble_evt();
void ble_db_discovery_on_ble_evt(ble_evt_t const * p_ble_evt,
void * p_context)
{
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
VERIFY_PARAM_NOT_NULL_VOID(p_context);
VERIFY_MODULE_INITIALIZED_VOID();
ble_db_discovery_t * p_db_discovery = (ble_db_discovery_t *)p_context;
switch (p_ble_evt->header.evt_id)
{
...
case BLE_GATTC_EVT_CHAR_DISC_RSP:
on_characteristic_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
...
}
}
7. 蓝牙发现描述符事件处理, 处理函数: ble_db_discovery_on_ble_evt();
void ble_db_discovery_on_ble_evt(ble_evt_t const * p_ble_evt,
void * p_context)
{
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
VERIFY_PARAM_NOT_NULL_VOID(p_context);
VERIFY_MODULE_INITIALIZED_VOID();
ble_db_discovery_t * p_db_discovery = (ble_db_discovery_t *)p_context;
switch (p_ble_evt->header.evt_id)
{
...
case BLE_GATTC_EVT_DESC_DISC_RSP:
on_descriptor_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
...
}
}
上一篇: MySQL多表查询和事务安全
下一篇: 6.使用zuul实现网关