-
工作在主模式蓝牙初时化
log_init();
timers_init();
uart_init();
scan_init();
db_discovery_init();
power_management_init();
ble_stack_init();
gatt_init();
nus_c_init();
// Start execution.
printf("BLE UART central example started.\r\n");
NRF_LOG_INFO("BLE UART central example started.");
scan_start();
application_timers_start();
-
先看下scan_init函数里的实现
/**@brief Function for initializing the scanning and setting the filters.
*/
static void scan_init(void)
{
ret_code_t err_code;
nrf_ble_scan_init_t init_scan;
memset(&init_scan, 0, sizeof(init_scan));
init_scan.connect_if_match = true;
init_scan.conn_cfg_tag = APP_BLE_CONN_CFG_TAG;
err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &m_nus_uuid);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_UUID_FILTER, false);
APP_ERROR_CHECK(err_code);
}
1). scan_evt_handler作为函数指针的参数传入,扫描最终结果通过蓝牙协议栈回调到此函数
2).nrf_ble_scan_filter_set函数设置扫描过滤方式
3).nrf_ble_scan_filters_enable使能扫描过滤方式
使用uuid过滤方式
/**@brief NUS UUID. */
static ble_uuid_t const m_nus_uuid =
{
.uuid = BLE_UUID_NUS_SERVICE, //由ble_nus_c.c和ble_nus_c.h中定义
.type = NUS_SERVICE_UUID_TYPE
};
err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &m_nus_uuid);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_UUID_FILTER, false);
APP_ERROR_CHECK(err_code);
另外还要在sdk_config.h中定义
#ifndef NRF_BLE_SCAN_FILTER_ENABLE
#define NRF_BLE_SCAN_FILTER_ENABLE 1
#endif
// <o> NRF_BLE_SCAN_UUID_CNT - Number of filters for UUIDs.
#ifndef NRF_BLE_SCAN_UUID_CNT
#define NRF_BLE_SCAN_UUID_CNT 1
#endif
使用蓝牙名称过滤方式
static char const m_target_periph_name[] = "Nordic_UART";
err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_target_periph_name);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false);
APP_ERROR_CHECK(err_code);
另外还要在sdk_config.h中定义
// <e> NRF_BLE_SCAN_FILTER_ENABLE - Enabling filters for the Scanning Module.
//==========================================================
#ifndef NRF_BLE_SCAN_FILTER_ENABLE
#define NRF_BLE_SCAN_FILTER_ENABLE 1
#endif
// <o> NRF_BLE_SCAN_UUID_CNT - Number of filters for UUIDs.
#ifndef NRF_BLE_SCAN_UUID_CNT
#define NRF_BLE_SCAN_UUID_CNT 0
#endif
// <o> NRF_BLE_SCAN_NAME_CNT - Number of name filters.
#ifndef NRF_BLE_SCAN_NAME_CNT
#define NRF_BLE_SCAN_NAME_CNT 1
#endif
nrf_ble_scan_init函数内的实现
ret_code_t nrf_ble_scan_init(nrf_ble_scan_t * const p_scan_ctx,
nrf_ble_scan_init_t const * const p_init,
nrf_ble_scan_evt_handler_t evt_handler)
{
VERIFY_PARAM_NOT_NULL(p_scan_ctx);
p_scan_ctx->evt_handler = evt_handler;
#if (NRF_BLE_SCAN_FILTER_ENABLE == 1) //过滤使能宏,在sdk_config.h中定义
// Disable all scanning filters.
memset(&p_scan_ctx->scan_filters, 0, sizeof(p_scan_ctx->scan_filters));
#endif
// If the pointer to the initialization structure exist, use it to scan the configuration.
if (p_init != NULL)
{
p_scan_ctx->connect_if_match = p_init->connect_if_match;
p_scan_ctx->conn_cfg_tag = p_init->conn_cfg_tag;
if (p_init->p_scan_param != NULL)
{
p_scan_ctx->scan_params = *p_init->p_scan_param;
}
else
{
// Use the default static configuration.
nrf_ble_scan_default_param_set(p_scan_ctx);
}
if (p_init->p_conn_param != NULL)
{
p_scan_ctx->conn_params = *p_init->p_conn_param;
}
else
{
// Use the default static configuration.
nrf_ble_scan_default_conn_param_set(p_scan_ctx);
}
}
// If pointer is NULL, use the static default configuration.
else
{
nrf_ble_scan_default_param_set(p_scan_ctx);
nrf_ble_scan_default_conn_param_set(p_scan_ctx);
p_scan_ctx->connect_if_match = false;
}
// Assign a buffer where the advertising reports are to be stored by the SoftDevice.
p_scan_ctx->scan_buffer.p_data = p_scan_ctx->scan_buffer_data;
p_scan_ctx->scan_buffer.len = NRF_BLE_SCAN_BUFFER;
return NRF_SUCCESS;
}
1). p_scan_ctx->evt_handler = evt_handler; 函数指针指向用户定的函数,由形参evt_handler传入m_scan定义的变量
2).m_scan由NRF_BLE_SCAN_DEF(m_scan);宏定义实现一个变量定义及初时化,宏NRF_BLE_SCAN_DEF原形如下:
#define NRF_BLE_SCAN_DEF(_name) \
static nrf_ble_scan_t _name; \
NRF_SDH_BLE_OBSERVER(_name ## _ble_obs, \
NRF_BLE_SCAN_OBSERVER_PRIO, \
nrf_ble_scan_on_ble_evt, &_name); \
3). 宏体内static nrf_ble_scan_t _name; 定义了nrf_ble_scan_t变量m_scan,nrf_ble_scan_t定义体如下:
typedef struct
{
#if (NRF_BLE_SCAN_FILTER_ENABLE == 1)
nrf_ble_scan_filters_t scan_filters; /**< Filter data. */
#endif
bool connect_if_match; /**< If set to true, the module automatically connects after a filter match or successful identification of a device from the whitelist. */
ble_gap_conn_params_t conn_params; /**< Connection parameters. */
uint8_t conn_cfg_tag; /**< Variable to keep track of what connection settings will be used if a filer match or a whitelist match results in a connection. */
ble_gap_scan_params_t scan_params; /**< GAP scanning parameters. */
nrf_ble_scan_evt_handler_t evt_handler; /**< Handler for the scanning events. Can be initialized as NULL if no handling is implemented in the main application. */
uint8_t scan_buffer_data[NRF_BLE_SCAN_BUFFER]; /**< Buffer where advertising reports will be stored by the SoftDevice. */
ble_data_t scan_buffer; /**< Structure-stored pointer to the buffer where advertising reports will be stored by the SoftDevice. */
} nrf_ble_scan_t;
4).上述p_scan_ctx->evt_handler = evt_handler的最终结果是m_scan.evt_handler指向由函数形参evt_handler传入的
函数,即用户程序自定义的函数scan_evt_handler
5).NRF_SDH_BLE_OBSERVER宏体如下
#define NRF_SDH_BLE_OBSERVER(_name, _prio, _handler, _context) \
STATIC_ASSERT(NRF_SDH_BLE_ENABLED, "NRF_SDH_BLE_ENABLED not set!"); \
STATIC_ASSERT(_prio < NRF_SDH_BLE_OBSERVER_PRIO_LEVELS, "Priority level unavailable."); \
NRF_SECTION_SET_ITEM_REGISTER(sdh_ble_observers, _prio, static nrf_sdh_ble_evt_observer_t _name) = \
{ \
.handler = _handler, \
.p_context = _context \
}
6).由NRF_SDH_BLE_OBSERVER宏定义的宏参数 nrf_ble_scan_on_ble_evt, &_name分别赋给了协议栈中要使用的
变量static nrf_sdh_ble_evt_observer_t m_scan_ble_obs(由_name ## _ble_obs宏参引入),
nrf_sdh_ble_evt_observer_t变量定义体如下:
/**@brief BLE event observer. */
typedef struct
{
nrf_sdh_ble_evt_handler_t handler; //!< BLE event handler.
void * p_context; //!< A parameter to the event handler.
} const nrf_sdh_ble_evt_observer_t;
7).最终变量m_scan_ble_obs中的函数指针handler的值指向nrf_ble_scan_on_ble_evt,p_context的值指
向m_scan变量
8).nrf_ble_scan_on_ble_evt的实现如下,此函数由协议栈调用
void nrf_ble_scan_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_contex)
{
nrf_ble_scan_t * p_scan_data = (nrf_ble_scan_t *)p_contex;
ble_gap_evt_adv_report_t const * p_adv_report = &p_ble_evt->evt.gap_evt.params.adv_report;
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_ADV_REPORT: //扫描广播触发的事件
nrf_ble_scan_on_adv_report(p_scan_data, p_adv_report);
break;
case BLE_GAP_EVT_TIMEOUT: //扫描超时触发的事件
nrf_ble_scan_on_timeout(p_scan_data, p_gap_evt);
break;
case BLE_GAP_EVT_SCAN_REQ_REPORT: //扫描请求触发的事件
nrf_ble_scan_on_req_report(p_scan_data, p_gap_evt);
break;
case BLE_GAP_EVT_CONNECTED: //连接上触发的事件
nrf_ble_scan_on_connected_evt(p_scan_data, p_gap_evt);
break;
default:
break;
}
}
9).扫描广播会调用 nrf_ble_scan_on_adv_report(p_scan_data, p_adv_report);此函数的实现体如下:
/**@brief Function for calling the BLE_GAP_EVT_ADV_REPORT event to check whether the received
* scanning data matches the scan configuration.
*
* @param[in] p_scan_ctx Pointer to the Scanning Module instance.
* @param[in] p_adv_report Advertising report.
*/
static void nrf_ble_scan_on_adv_report(nrf_ble_scan_t const * const p_scan_ctx,
ble_gap_evt_adv_report_t const * const p_adv_report)
{
scan_evt_t scan_evt;
#if (NRF_BLE_SCAN_FILTER_ENABLE == 1) //如果此宏定义1,则会启用过滤匹配
uint8_t filter_cnt = 0;
uint8_t filter_match_cnt = 0;
#endif
memset(&scan_evt, 0, sizeof(scan_evt));
scan_evt.p_scan_params = &p_scan_ctx->scan_params;
// If the whitelist is used, do not check the filters and return.
if (is_whitelist_used(p_scan_ctx)) //如果使用的白名单
{
scan_evt.scan_evt_id = NRF_BLE_SCAN_EVT_WHITELIST_ADV_REPORT;
scan_evt.params.p_not_found = p_adv_report;
p_scan_ctx->evt_handler(&scan_evt);
UNUSED_RETURN_VALUE(sd_ble_gap_scan_start(NULL, &p_scan_ctx->scan_buffer));
nrf_ble_scan_connect_with_target(p_scan_ctx, p_adv_report);
return; //跳过后面的部分
}
#if (NRF_BLE_SCAN_FILTER_ENABLE == 1) //扫描过滤部分
bool const all_filter_mode = p_scan_ctx->scan_filters.all_filters_mode;
bool is_filter_matched = false;
#if (NRF_BLE_SCAN_ADDRESS_CNT > 0) //按地址匹配
bool const addr_filter_enabled = p_scan_ctx->scan_filters.addr_filter.addr_filter_enabled;
#endif
#if (NRF_BLE_SCAN_NAME_CNT > 0) //按蓝牙名称匹配
bool const name_filter_enabled = p_scan_ctx->scan_filters.name_filter.name_filter_enabled;
#endif
#if (NRF_BLE_SCAN_SHORT_NAME_CNT > 0) //按short name匹配
bool const short_name_filter_enabled =
p_scan_ctx->scan_filters.short_name_filter.short_name_filter_enabled;
#endif
#if (NRF_BLE_SCAN_UUID_CNT > 0) //按uuid匹配
bool const uuid_filter_enabled = p_scan_ctx->scan_filters.uuid_filter.uuid_filter_enabled;
#endif
#if (NRF_BLE_SCAN_APPEARANCE_CNT > 0) //按APPEARANCE匹配
bool const appearance_filter_enabled =
p_scan_ctx->scan_filters.appearance_filter.appearance_filter_enabled;
#endif
#if (NRF_BLE_SCAN_ADDRESS_CNT > 0) //蓝牙地址匹配业务逻辑
// Check the address filter.
if (addr_filter_enabled)
{
// Number of active filters.
filter_cnt++;
if (adv_addr_compare(p_adv_report, p_scan_ctx))
{
// Number of filters matched.
filter_match_cnt++;
// Information about the filters matched.
scan_evt.params.filter_match.filter_match.address_filter_match = true;
is_filter_matched = true;
}
}
#endif
#if (NRF_BLE_SCAN_NAME_CNT > 0) //蓝牙名称匹配业务逻辑
// Check the name filter.
if (name_filter_enabled)
{
filter_cnt++;
if (adv_name_compare(p_adv_report, p_scan_ctx))
{
filter_match_cnt++;
// Information about the filters matched.
scan_evt.params.filter_match.filter_match.name_filter_match = true;
is_filter_matched = true;
}
}
#endif
#if (NRF_BLE_SCAN_SHORT_NAME_CNT > 0) //SHORT NAME匹配业务逻辑
if (short_name_filter_enabled)
{
filter_cnt++;
if (adv_short_name_compare(p_adv_report, p_scan_ctx))
{
filter_match_cnt++;
// Information about the filters matched.
scan_evt.params.filter_match.filter_match.short_name_filter_match = true;
is_filter_matched = true;
}
}
#endif
#if (NRF_BLE_SCAN_UUID_CNT > 0) //UUID匹配业务逻辑
// Check the UUID filter.
if (uuid_filter_enabled)
{
filter_cnt++;
if (adv_uuid_compare(p_adv_report, p_scan_ctx))
{
filter_match_cnt++;
// Information about the filters matched.
scan_evt.params.filter_match.filter_match.uuid_filter_match = true;
is_filter_matched = true;
}
}
#endif
#if (NRF_BLE_SCAN_APPEARANCE_CNT > 0) //APPEARANCE匹配业务逻辑
// Check the appearance filter.
if (appearance_filter_enabled)
{
filter_cnt++;
if (adv_appearance_compare(p_adv_report, p_scan_ctx))
{
filter_match_cnt++;
// Information about the filters matched.
scan_evt.params.filter_match.filter_match.appearance_filter_match = true;
is_filter_matched = true;
}
}
scan_evt.scan_evt_id = NRF_BLE_SCAN_EVT_NOT_FOUND;
#endif
scan_evt.params.filter_match.p_adv_report = p_adv_report;
// In the multifilter mode, the number of the active filters must equal the number of the filters matched to generate the notification.
if (all_filter_mode && (filter_match_cnt == filter_cnt))
{
scan_evt.scan_evt_id = NRF_BLE_SCAN_EVT_FILTER_MATCH;
nrf_ble_scan_connect_with_target(p_scan_ctx, p_adv_report); //连接匹配的设备
}
// In the normal filter mode, only one filter match is needed to generate the notification to the main application.
else if ((!all_filter_mode) && is_filter_matched)
{
scan_evt.scan_evt_id = NRF_BLE_SCAN_EVT_FILTER_MATCH;
nrf_ble_scan_connect_with_target(p_scan_ctx, p_adv_report);
}
else
{
scan_evt.scan_evt_id = NRF_BLE_SCAN_EVT_NOT_FOUND;
scan_evt.params.p_not_found = p_adv_report; //未匹配到的设备数据报告
}
// If the event handler is not NULL, notify the main application.
if (p_scan_ctx->evt_handler != NULL)
{
p_scan_ctx->evt_handler(&scan_evt); //函数回调
}
#endif // NRF_BLE_SCAN_FILTER_ENABLE
// Resume the scanning.
UNUSED_RETURN_VALUE(sd_ble_gap_scan_start(NULL, &p_scan_ctx->scan_buffer));
}
10).先看下uuid匹配段,如下代码adv_uuid_compare函数将扫描到的uuid和过滤用的uuid进行匹配,匹配到会将
匹配标记设为true,匹配计数自增1
#if (NRF_BLE_SCAN_UUID_CNT > 0) //UUID匹配业务逻辑
// Check the UUID filter.
if (uuid_filter_enabled)
{
filter_cnt++;
if (adv_uuid_compare(p_adv_report, p_scan_ctx))
{
filter_match_cnt++;
// Information about the filters matched.
scan_evt.params.filter_match.filter_match.uuid_filter_match = true;
is_filter_matched = true;
}
}
#endif
11).匹配上指定的uuid,会发起连接
if (all_filter_mode && (filter_match_cnt == filter_cnt))
{
scan_evt.scan_evt_id = NRF_BLE_SCAN_EVT_FILTER_MATCH;
nrf_ble_scan_connect_with_target(p_scan_ctx, p_adv_report);
}
// In the normal filter mode, only one filter match is needed to generate the notification to the main application.
else if ((!all_filter_mode) && is_filter_matched)
{
scan_evt.scan_evt_id = NRF_BLE_SCAN_EVT_FILTER_MATCH;
nrf_ble_scan_connect_with_target(p_scan_ctx, p_adv_report);
}
else
{
scan_evt.scan_evt_id = NRF_BLE_SCAN_EVT_NOT_FOUND;
scan_evt.params.p_not_found = p_adv_report;
}
12).扫描数据报告通过以下回调实现,这个p_scan_ctx指向的是变量m_scan,p_scan_ctx->evt_handler这个
函数指针指向的是用户程序定义的函数scan_evt_handler
// If the event handler is not NULL, notify the main application.
if (p_scan_ctx->evt_handler != NULL)
{
p_scan_ctx->evt_handler(&scan_evt);
}
13).最终扫描结果还是交由用户程序定义的函数scan_evt_handler来处理,scan_evt_handler函数的实现如下:
/**@brief Function for handling Scanning Module events.
*/
static void scan_evt_handler(scan_evt_t const * p_scan_evt)
{
ret_code_t err_code;
uint16_t data_offset = 0;
uint8_t i;
switch(p_scan_evt->scan_evt_id)
{
case NRF_BLE_SCAN_EVT_CONNECTING_ERROR: //连接出错事件
{
err_code = p_scan_evt->params.connecting_err.err_code;
APP_ERROR_CHECK(err_code);
} break;
case NRF_BLE_SCAN_EVT_NOT_FOUND: //未匹配到事件
if(scanTotal < 16)
{
if(searchMac(p_scan_evt))
{
scanInfo[scanTotal].len = ble_advdata_search(p_scan_evt->params.p_not_found->data.p_data,
p_scan_evt->params.p_not_found->data.len,
&data_offset,
BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
if(scanInfo[scanTotal].len == 0)
break;
strncpy((char*)scanInfo[scanTotal].data,(const char*)&p_scan_evt->params.p_not_found->data.p_data[data_offset],scanInfo[scanTotal].len);
scanInfo[scanTotal].rssi = p_scan_evt->params.p_not_found->rssi;
for(i=0;i<6;i++)
{
scanInfo[scanTotal].addr[i] = p_scan_evt->params.p_not_found->peer_addr.addr[i];
}
for(uint8_t j=0;j<scanInfo[scanTotal].len;j++)
printf("%c", scanInfo[scanTotal].data[j]);
printf("\n");
scanTotal++;
}
}
break;
case NRF_BLE_SCAN_EVT_CONNECTED: //连接上事件
{
ble_gap_evt_connected_t const * p_connected =
p_scan_evt->params.connected.p_connected;
// Scan is automatically stopped by the connection.
NRF_LOG_INFO("Connecting to target %02x%02x%02x%02x%02x%02x",
p_connected->peer_addr.addr[0],
p_connected->peer_addr.addr[1],
p_connected->peer_addr.addr[2],
p_connected->peer_addr.addr[3],
p_connected->peer_addr.addr[4],
p_connected->peer_addr.addr[5]
);
} break;
case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT: //扫描超时事件
{
NRF_LOG_INFO("Scan timed out.");
scan_start();
} break;
default:
break;
}
}
14).p_scan_evt指针可以得到需要的扫描到的设备相关信息,结构体定义体如下:
/**@brief Structure for Scanning Module event data.
*
* @details This structure is used to send module event data to the main application when an event occurs.
*/
typedef struct
{
nrf_ble_scan_evt_t scan_evt_id; /**< Type of event propagated to the main application. */
union
{
nrf_ble_scan_evt_filter_match_t filter_match; /**< Scan filter match. */
ble_gap_evt_scan_req_report_t req_report; /**< Scan request report parameters. */
ble_gap_evt_timeout_t timeout; /**< Timeout event parameters. */
ble_gap_evt_adv_report_t const * p_whitelist_adv_report; /**< Advertising report event parameters for whitelist. */
ble_gap_evt_adv_report_t const * p_not_found; /**< Advertising report event parameters when filter is not found. */
nrf_ble_scan_evt_connected_t connected; /**< Connected event parameters. */
nrf_ble_scan_evt_connecting_err_t connecting_err; /**< Error event when connecting. Propagates the error code returned by the SoftDevice API @ref sd_ble_gap_scan_start. */
} params;
ble_gap_scan_params_t const * p_scan_params; /**< GAP scanning parameters. These parameters are needed to establish connection. */
} scan_evt_t;
-
再来看db_discovery_init函数
/** @brief Function for initializing the database discovery module. */
static void db_discovery_init(void)
{
ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
APP_ERROR_CHECK(err_code);
}
1). db_discovery_init函数调用了ble_db_discovery_init函数,函数db_disc_handler作为参数传入函数指针,
最终会回调到用户程序定义的函数,ble_db_discovery_init函数实现体
uint32_t ble_db_discovery_init(const ble_db_discovery_evt_handler_t evt_handler)
{
uint32_t err_code = NRF_SUCCESS;
VERIFY_PARAM_NOT_NULL(evt_handler);
m_num_of_handlers_reg = 0;
m_initialized = true;
m_pending_usr_evt_index = 0;
m_evt_handler = evt_handler;
return err_code;
}
2). 由形参evt_handler将用户程序定义的函数db_disc_handler传递给函数指针m_evt_handler保存,这个函数指针
由函数registered_handler_get返回,registered_handler_get的实现体如下:
/**@brief Function for fetching the event handler provided by a registered application module.
*
* @param[in] srv_uuid UUID of the service.
*
* @retval evt_handler Event handler of the module, registered for the given service UUID.
* @retval NULL If no event handler is found.
*/
static ble_db_discovery_evt_handler_t registered_handler_get(ble_uuid_t const * p_srv_uuid)
{
for (uint32_t i = 0; i < m_num_of_handlers_reg; i++)
{
if (BLE_UUID_EQ(&(m_registered_handlers[i]), p_srv_uuid))
{
return (m_evt_handler);
}
}
return NULL;
}
3).discovery_complete_evt_trigger函数调用了
p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));得到函数指针对象赋给p_evt_handler,
p_evt_handler指针又传递给一个事件数组m_pending_user_evts中保存,然后事件计数器加1
m_pending_user_evts[m_pending_usr_evt_index].evt_handler = p_evt_handler;
m_pending_usr_evt_index++;
discovery_complete_evt_trigger的实现体如下
/**@brief Function for triggering a Discovery Complete or Service Not Found event to the
* application.
*
* @details This function will fetch the event handler based on the UUID of the service being
* discovered. (The event handler is registered by the application beforehand).
* It then triggers an event indicating the completion of the service discovery.
* If no event handler was found, then this function will do nothing.
*
* @param[in] p_db_discovery Pointer to the DB discovery structure.
* @param[in] is_srv_found Variable to indicate if the service was found at the peer.
* @param[in] conn_handle Connection Handle.
*/
static void discovery_complete_evt_trigger(ble_db_discovery_t * p_db_discovery,
bool is_srv_found,
uint16_t conn_handle)
{
ble_db_discovery_evt_handler_t p_evt_handler;
ble_gatt_db_srv_t * p_srv_being_discovered;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));
if (p_evt_handler != NULL)
{
if (m_pending_usr_evt_index < DB_DISCOVERY_MAX_USERS)
{
// Insert an event into the pending event list.
m_pending_user_evts[m_pending_usr_evt_index].evt.conn_handle = conn_handle;
m_pending_user_evts[m_pending_usr_evt_index].evt.params.discovered_db =
*p_srv_being_discovered;
if (is_srv_found)
{
m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
BLE_DB_DISCOVERY_COMPLETE;
}
else
{
m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
BLE_DB_DISCOVERY_SRV_NOT_FOUND;
}
m_pending_user_evts[m_pending_usr_evt_index].evt_handler = p_evt_handler;
m_pending_usr_evt_index++;
if (m_pending_usr_evt_index == m_num_of_handlers_reg)
{
// All registered modules have pending events. Send all pending events to the user
// modules.
pending_user_evts_send(); //由此函数实现函数回调
}
else
{
// Too many events pending. Do nothing. (Ideally this should not happen.)
}
}
}
}
4).pending_user_evts_send函数中调用m_pending_user_evts[i].evt_handler(&(m_pending_user_evts[i].evt));
实现用户程序回调
pending_user_evts_send的实现体如下:
/**@brief Function for sending all pending discovery events to the corresponding user modules.
*/
static void pending_user_evts_send(void)
{
for (uint32_t i = 0; i < m_num_of_handlers_reg; i++)
{
// Pass the event to the corresponding event handler.
m_pending_user_evts[i].evt_handler(&(m_pending_user_evts[i].evt));
}
m_pending_usr_evt_index = 0;
}
5). m_pending_user_evts[0].evt_handler函数指针指向的对象是用户程序定义的函数db_disc_handler,所以最终调用
的函数是db_disc_handler
db_disc_handler函数实现体如下:
/**@brief Function for handling database discovery events.
*
* @details This function is a callback function to handle events from the database discovery module.
* Depending on the UUIDs that are discovered, this function forwards the events
* to their respective services.
*
* @param[in] p_event Pointer to the database discovery event.
*/
static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
{
ble_nus_c_on_db_disc_evt(&m_ble_nus_c, p_evt);
}
6).db_disc_handler函数调用了ble_nus_c_on_db_disc_evt函数
ble_nus_c_on_db_disc_evt实现体如下:
void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
{
ble_nus_c_evt_t nus_c_evt;
memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));
ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
// Check if the NUS was discovered.
if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
&& (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE)
&& (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type))
{
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
switch (p_chars[i].characteristic.uuid.uuid)
{
case BLE_UUID_NUS_RX_CHARACTERISTIC: //RX uuid特征匹配
nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value;
break;
case BLE_UUID_NUS_TX_CHARACTERISTIC: //TX uuid特征匹配
nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value;
nus_c_evt.handles.nus_tx_cccd_handle = p_chars[i].cccd_handle;
break;
default:
break;
}
}
if (p_ble_nus_c->evt_handler != NULL)
{
nus_c_evt.conn_handle = p_evt->conn_handle;
nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt); //实现函数回调
}
}
}
7).BLE_UUID_NUS_RX_CHARACTERISTIC和BLE_UUID_NUS_TX_CHARACTERISTIC实现了两个特征字事件处理
分支,由 p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);回调到用户程序定义ble_nus_c_evt_handler函数
ble_nus_c_evt_handler函数实现体如下:
/**@brief Callback handling Nordic UART Service (NUS) client events.
*
* @details This function is called to notify the application of NUS client events.
*
* @param[in] p_ble_nus_c NUS client handle. This identifies the NUS client.
* @param[in] p_ble_nus_evt Pointer to the NUS client event.
*/
/**@snippet [Handling events from the ble_nus_c module] */
static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
{
ret_code_t err_code;
switch (p_ble_nus_evt->evt_type)
{
case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
NRF_LOG_INFO("Discovery complete.");
err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
APP_ERROR_CHECK(err_code);
err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
APP_ERROR_CHECK(err_code);
NRF_LOG_INFO("Connected to device with Nordic UART Service.");
break;
case BLE_NUS_C_EVT_NUS_TX_EVT:
ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
break;
case BLE_NUS_C_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected.");
scan_start();
break;
}
}
8).在BLE_NUS_C_EVT_DISCOVERY_COMPLETE事件中使能notify特征字
err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
APP_ERROR_CHECK(err_code);
err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
APP_ERROR_CHECK(err_code);
9).上述第3条discovery_complete_evt_trigger函数分别由以下4个函数中调用
on_primary_srv_discovery_rsp
on_characteristic_discovery_rsp
on_descriptor_discovery_rsp
on_disconnected
10).ble_db_discovery_on_ble_evt函数调用了上述4个函数,但这个函数ble_db_discovery_on_ble_evt由协议栈调用
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_PRIM_SRVC_DISC_RSP: //主服务事件
on_primary_srv_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
case BLE_GATTC_EVT_CHAR_DISC_RSP: //特征字事件
on_characteristic_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
case BLE_GATTC_EVT_DESC_DISC_RSP: //描述符事件
on_descriptor_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
case BLE_GAP_EVT_DISCONNECTED: //GAP断开连接事件
on_disconnected(p_db_discovery, &(p_ble_evt->evt.gap_evt));
break;
default:
break;
}
if ( (p_db_discovery->discovery_pending)
&& (p_ble_evt->header.evt_id >= BLE_GATTC_EVT_BASE)
&& (p_ble_evt->header.evt_id <= BLE_GATTC_EVT_LAST)
&& (p_ble_evt->evt.gattc_evt.conn_handle == p_db_discovery->conn_handle))
{
(void)discovery_start(p_db_discovery, p_db_discovery->conn_handle);
}
}
11).使用BLE_DB_DISCOVERY_DEF(m_db_disc)定义变量 m_db_disc并与ble_db_discovery_on_ble_evt关联起来
BLE_DB_DISCOVERY_DEF宏实现体如下:
#define BLE_DB_DISCOVERY_DEF(_name) \
static ble_db_discovery_t _name = {.discovery_in_progress = 0, \
.discovery_pending = 0, \
.conn_handle = BLE_CONN_HANDLE_INVALID}; \
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
BLE_DB_DISC_BLE_OBSERVER_PRIO, \
ble_db_discovery_on_ble_evt, &_name)
NRF_SDH_BLE_OBSERVER宏实现体如下:
#define NRF_SDH_BLE_OBSERVER(_name, _prio, _handler, _context) \
STATIC_ASSERT(NRF_SDH_BLE_ENABLED, "NRF_SDH_BLE_ENABLED not set!"); \
STATIC_ASSERT(_prio < NRF_SDH_BLE_OBSERVER_PRIO_LEVELS, "Priority level unavailable."); \
NRF_SECTION_SET_ITEM_REGISTER(sdh_ble_observers, _prio, static nrf_sdh_ble_evt_observer_t _name) = \
{ \
.handler = _handler, \
.p_context = _context \
}
nrf_sdh_ble_evt_observer_t 会定义一个变量m_db_disc_obs(由_name ## _obs合成),这个变量中的handler 成员
保存着ble_db_discovery_on_ble_evt,p_context成员保存着变量m_db_disc
nrf_sdh_ble_evt_observer_t 定义体如下:
/**@brief BLE event observer. */
typedef struct
{
nrf_sdh_ble_evt_handler_t handler; //!< BLE event handler.
void * p_context; //!< A parameter to the event handler.
} const nrf_sdh_ble_evt_observer_t;
-
最后看nus_c_init函数
/**@brief Function for initializing the Nordic UART Service (NUS) client. */
static void nus_c_init(void)
{
ret_code_t err_code;
ble_nus_c_init_t init;
init.evt_handler = ble_nus_c_evt_handler;
err_code = ble_nus_c_init(&m_ble_nus_c, &init);
APP_ERROR_CHECK(err_code);
}
1).ble_nus_c_evt_handler赋给init结构体成员evt_handler ,然后将结构体地址传递给ble_nus_c_init函数进行
初时化
ble_nus_c_init函数实现体如下:
uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init)
{
uint32_t err_code;
ble_uuid_t uart_uuid;
ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init);
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);
VERIFY_SUCCESS(err_code);
uart_uuid.type = p_ble_nus_c->uuid_type;
uart_uuid.uuid = BLE_UUID_NUS_SERVICE;
p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_nus_c->evt_handler = p_ble_nus_c_init->evt_handler;
p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID;
p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID;
return ble_db_discovery_evt_register(&uart_uuid);
}
2). 上述函数中p_ble_nus_c->evt_handler = p_ble_nus_c_init->evt_handler;
p_ble_nus_c指向变量m_ble_nus_c,p_ble_nus_c_init->evt_handler指向用户定义的程序ble_nus_c_evt_handler,
最终m_ble_nus_c.evt_handler 函数指针保存的是用户初时化时传递自定义的函数ble_nus_c_evt_handler,所以
ble_nus_c_on_db_disc_evt函数中 p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt); 实现函数回调到用户程
序自定义的函数
3).使用BLE_NUS_C_DEF(m_ble_nus_c)宏 定义变量m_ble_nus_c
BLE_NUS_C_DEF定义体如下:
#define BLE_NUS_C_DEF(_name) \
static ble_nus_c_t _name; \
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
BLE_NUS_C_BLE_OBSERVER_PRIO, \
ble_nus_c_on_ble_evt, &_name)
NRF_SDH_BLE_OBSERVER定义体如下:
#define NRF_SDH_BLE_OBSERVER(_name, _prio, _handler, _context) \
STATIC_ASSERT(NRF_SDH_BLE_ENABLED, "NRF_SDH_BLE_ENABLED not set!"); \
STATIC_ASSERT(_prio < NRF_SDH_BLE_OBSERVER_PRIO_LEVELS, "Priority level unavailable."); \
NRF_SECTION_SET_ITEM_REGISTER(sdh_ble_observers, _prio, static nrf_sdh_ble_evt_observer_t _name) = \
{ \
.handler = _handler, \
.p_context = _context \
}
4).定义了一个静态变量m_ble_nus_c_obs(由_name ## _obs宏参引入)
nrf_sdh_ble_evt_observer_t 定义体如下:
/**@brief BLE event observer. */
typedef struct
{
nrf_sdh_ble_evt_handler_t handler; //!< BLE event handler.
void * p_context; //!< A parameter to the event handler.
} const nrf_sdh_ble_evt_observer_t;
5).最终m_ble_nus_c_obs.handler函数指针保存的函数是ble_nus_c_on_ble_evt,m_ble_nus_c_obs.p_context指针
保存的是变量m_ble_nus_c
6).ble_nus_c_on_ble_evt函数将由协议栈调用
ble_nus_c_on_ble_evt定义实现体如下:
void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_context;
if ((p_ble_nus_c == NULL) || (p_ble_evt == NULL))
{
return;
}
if ( (p_ble_nus_c->conn_handle != BLE_CONN_HANDLE_INVALID)
&&(p_ble_nus_c->conn_handle != p_ble_evt->evt.gap_evt.conn_handle)
)
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
on_hvx(p_ble_nus_c, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
if (p_ble_evt->evt.gap_evt.conn_handle == p_ble_nus_c->conn_handle
&& p_ble_nus_c->evt_handler != NULL)
{
ble_nus_c_evt_t nus_c_evt;
nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCONNECTED;
p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
}
break;
default:
// No implementation needed.
break;
}
}
7).当BLE_GATTC_EVT_HVX事件发生(接收到数据从机的TX uuid事件),调用on_hvx(p_ble_nus_c, p_ble_evt);
on_hvx函数定义实现本如下
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
*
* @details This function will uses the Handle Value Notification received from the SoftDevice
* and checks if it is a notification of the NUS TX characteristic from the peer. If
* it is, this function will decode the data and send it to the
* application.
*
* @param[in] p_ble_nus_c Pointer to the NUS Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_hvx(ble_nus_c_t * p_ble_nus_c, ble_evt_t const * p_ble_evt)
{
// HVX can only occur from client sending.
if ( (p_ble_nus_c->handles.nus_tx_handle != BLE_GATT_HANDLE_INVALID)
&& (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_tx_handle)
&& (p_ble_nus_c->evt_handler != NULL))
{
ble_nus_c_evt_t ble_nus_c_evt;
ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TX_EVT;
ble_nus_c_evt.p_data = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data;
ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len;
p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
NRF_LOG_DEBUG("Client sending data.");
}
}
8).on_hvx函数最终将接收到的数据通过p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt)回调到用户程序
定义的函数ble_nus_c_evt_handler。
ble_nus_c_evt_handler函数定义体如下:
/**@brief Callback handling Nordic UART Service (NUS) client events.
*
* @details This function is called to notify the application of NUS client events.
*
* @param[in] p_ble_nus_c NUS client handle. This identifies the NUS client.
* @param[in] p_ble_nus_evt Pointer to the NUS client event.
*/
/**@snippet [Handling events from the ble_nus_c module] */
static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
{
ret_code_t err_code;
switch (p_ble_nus_evt->evt_type)
{
case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
NRF_LOG_INFO("Discovery complete.");
err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
APP_ERROR_CHECK(err_code);
err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
APP_ERROR_CHECK(err_code);
NRF_LOG_INFO("Connected to device with Nordic UART Service.");
break;
case BLE_NUS_C_EVT_NUS_TX_EVT:
ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
break;
case BLE_NUS_C_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected.");
scan_start();
break;
}
}
9).ble_nus_c_evt_handler函数中BLE_NUS_C_EVT_NUS_TX_EVT事件调用函数ble_nus_chars_received_uart_print
ble_nus_chars_received_uart_print函数的定义实现体
/**@brief Function for handling characters received by the Nordic UART Service (NUS).
*
* @details This function takes a list of characters of length data_len and prints the characters out on UART.
* If @ref ECHOBACK_BLE_UART_DATA is set, the data is sent back to sender.
*/
static void ble_nus_chars_received_uart_print(uint8_t * p_data, uint16_t data_len)
{
for (uint32_t i = 0; i < data_len; i++)
{
printf("%02x ",p_data[i]);
}
printf("\n");
}
10).ble_nus_chars_received_uart_print函数将接收到的数据按十六进制格式打印输出,在这可以根据程序的需要
可以将数据进行转存及其它处理
-
ble_nus_c_string_send函数进行数据的发送
uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
{
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
if (length > BLE_NUS_MAX_DATA_LEN)
{
NRF_LOG_WARNING("Content too long.");
return NRF_ERROR_INVALID_PARAM;
}
if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
NRF_LOG_WARNING("Connection handle invalid.");
return NRF_ERROR_INVALID_STATE;
}
ble_gattc_write_params_t const write_params =
{
.write_op = BLE_GATT_OP_WRITE_CMD,
.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
.handle = p_ble_nus_c->handles.nus_rx_handle,
.offset = 0,
.len = length,
.p_value = p_string
};
return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
}
1).ble_nus_c_string_send函数将数据封装好调用协议栈函数sd_ble_gattc_write将数据发送出去
-
发现蓝牙uuid服务
1). 在ble_evt_handler函数中的BLE_GAP_EVT_CONNECTED事件中开启蓝牙服务发现,以下是ble_evt_handler函数中
的部分代码片段
m_center_handle = p_ble_evt->evt.gap_evt.conn_handle;
err_code = ble_nus_c_handles_assign(&m_ble_nus_c, m_center_handle, NULL); //指定关联m_ble_nus_c变最
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, m_center_handle); //开始蓝牙uuid服务发现
APP_ERROR_CHECK(err_code);
2).蓝牙服务发现完成后会派发BLE_NUS_C_EVT_DISCOVERY_COMPLETE事件到ble_nus_c_evt_handler函数中,
在此事件中使能uuid的notify特征字
err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
APP_ERROR_CHECK(err_code);
err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
APP_ERROR_CHECK(err_code);
-
总结
扫描流程:
NRF_BLE_SCAN_DEF定义变量m_scan -> scan_init初时化 -> 初时化事件函数scan_evt_handler,关联变量m_scan ,
设置扫描过滤 -> 开启扫描scan_start ->由协议栈调用nrf_ble_scan_on_ble_evt函数 -> 调用nrf_ble_scan_on_adv_report
函数进行扫描过
滤匹配并连接 -> 最后报告结果到scan_evt_handler用户程序定义的函数
发现服务流程
BLE_DB_DISCOVERY_DEF定义变量m_db_disc -> db_discovery_init初时化服务发现 -> 初时化事件函数db_disc_handler
-> 由扫描过滤匹配连接触发BLE_GAP_EVT_CONNECTED事件,在此事件中开始蓝牙服务发现ble_db_discovery_start
-> 服务发现完成事触发BLE_NUS_C_EVT_DISCOVERY_COMPLETE事件,在此事件中打开notify特征字
ble_nus_c_tx_notif_enable
数据接收流程
蓝牙协议栈调用ble_nus_c_on_ble_evt派发BLE_GATTC_EVT_HVX事件 -> 调用on_hvx函数 -> 回调ble_nus_c_evt_handler
函数 -> 调用ble_nus_chars_received_uart_print函数
数据发送
直接调用ble_nus_c_string_send函数即可发送