赞
踩
nrf52840蓝牙协议栈主BLE串口,参考蓝牙SDK的example中ble_central里面的ble_app_uart样例。本文主要是参考ble_app_uart样例,但是nordic的SDK的example中ble_central里面的ble_app_uart样例有严重问题,所以进行了修改,从而实现蓝牙主机串口的功能。
蓝牙主机机串口的数据传递模式是:从机通过蓝牙发送数据到主机,主机接收到蓝牙数据后通过串口转发出去;主机从串口接收数据,将数据通过蓝牙发送给从机。
蓝牙串口主要有三部分的工作,第一部分是建立串口,第二部分是建立BLE,第三部分是搭建蓝牙和串口的双向数据通道。本文只重点分析主机端蓝牙的建立及处理,蓝牙通用的配置分析参见文章nrf52840蓝牙协议栈样例分析,建立串口参见文章nrf52840蓝牙协议栈从机BLE串口。
主函数内容如下
int main(void) { // Initialize. log_init();//打印初始化 timer_init();//软件定时器初始化 uart_init();//串口初始化 buttons_leds_init();//按键和LED初始化 db_discovery_init();//蓝牙数据发现初始化 power_management_init();//能量管理初始化 ble_stack_init();//协议栈初始化 gatt_init();//GATT初始化 nus_c_init();//蓝牙主机功能初始化 // Start execution. printf("BLE UART central example started.\r\n"); NRF_LOG_INFO("BLE UART central example started."); scan_start();//开始扫描 // Enter main loop. for (;;) { idle_state_handle();//待机状态 } }
首先是定时器、按键和LED初始化,和串口初始化,他们和从机串口基本没有变化。
其次,是协议栈初始化,里面有部分变化,第一在ble_stack_init函数内设置的主机和从机角色变化,第二注册的回调函数ble_evt_handler有变化。
首先在main函数内调用scan_start函数进行扫描
/**@brief Function to start scanning. */
static void scan_start(void)
{
ret_code_t ret;
ret = sd_ble_gap_scan_start(&m_scan_params, &m_scan_buffer);
APP_ERROR_CHECK(ret);
ret = bsp_indication_set(BSP_INDICATE_SCANNING);
APP_ERROR_CHECK(ret);
}
在scan_start函数内调用sd_ble_gap_scan_start函数进行扫描。如果发现了从机广播,则协议栈的GAP层会抛出BLE_GAP_EVT_ADV_REPORT事件,就是广播报告。那么在协议栈初始化函数ble_stack_init内注册的派发函数ble_evt_handler就会被调用。
ble_evt_handler函数内容如下:
/**@brief Function for handling BLE events. * * @param[in] p_ble_evt Bluetooth stack event. * @param[in] p_context Unused. */ 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_ADV_REPORT: on_adv_report(&p_gap_evt->params.adv_report); break; // BLE_GAP_EVT_ADV_REPORT 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; case BLE_GAP_EVT_TIMEOUT: if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) { NRF_LOG_INFO("Scan timed out."); scan_start(); } else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { NRF_LOG_INFO("Connection Request timed out."); } break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: // Pairing not supported err_code = sd_ble_gap_sec_params_reply(p_ble_evt->evt.gap_evt.conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: // Accepting parameters requested by peer. err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { NRF_LOG_DEBUG("PHY update request."); ble_gap_phys_t const phys = { .rx_phys = BLE_GAP_PHY_AUTO, .tx_phys = BLE_GAP_PHY_AUTO, }; err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys); APP_ERROR_CHECK(err_code); } break; case BLE_GATTC_EVT_TIMEOUT: // Disconnect on GATT Client timeout event. NRF_LOG_DEBUG("GATT Client Timeout."); err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); break; case BLE_GATTS_EVT_TIMEOUT: // Disconnect on GATT Server timeout event. NRF_LOG_DEBUG("GATT Server Timeout."); err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); break; default: break; } }
当产生BLE_GAP_EVT_ADV_REPORT事件后调用的on_adv_report函数如下
/**@brief Function for handling the advertising report BLE event. * * @param[in] p_adv_report Advertising report from the SoftDevice. */ 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); if (err_code == NRF_SUCCESS) { // scan is automatically stopped by the connect err_code = bsp_indication_set(BSP_INDICATE_IDLE); APP_ERROR_CHECK(err_code); NRF_LOG_INFO("Connecting to target %02x%02x%02x%02x%02x%02x", p_adv_report->peer_addr.addr[0], p_adv_report->peer_addr.addr[1], p_adv_report->peer_addr.addr[2], p_adv_report->peer_addr.addr[3], p_adv_report->peer_addr.addr[4], p_adv_report->peer_addr.addr[5] ); } } else { err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer); APP_ERROR_CHECK(err_code); } }
该函数首先通过ble_advdata_uuid_find函数判断广播数据是否是自己需要的UUID,如果是就调用sd_ble_gap_connect函数进行连接,否则就继续扫描。
如果连接成功,则协议栈会产生BLE_GAP_EVT_CONNECTED事件,在BLE_GAP_EVT_CONNECTED事件里面,主机要调用ble_db_discovery_start函数寻找GATT层的服务。ble_db_discovery_start会调用discovery_start进行具体的操作。
static uint32_t discovery_start(ble_db_discovery_t * const p_db_discovery, uint16_t conn_handle) { ret_code_t err_code; ble_gatt_db_srv_t * p_srv_being_discovered; nrf_ble_gq_req_t db_srv_disc_req; memset(p_db_discovery, 0x00, sizeof(ble_db_discovery_t)); memset(&db_srv_disc_req, 0x00, sizeof(nrf_ble_gq_req_t)); err_code = nrf_ble_gq_conn_handle_register(mp_gatt_queue, conn_handle); VERIFY_SUCCESS(err_code); p_db_discovery->conn_handle = conn_handle; p_db_discovery->pending_usr_evt_index = 0; p_db_discovery->discoveries_count = 0; p_db_discovery->curr_srv_ind = 0; p_db_discovery->curr_char_ind = 0; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind]; NRF_LOG_DEBUG("Starting discovery of service with UUID 0x%x on connection handle 0x%x.", p_srv_being_discovered->srv_uuid.uuid, conn_handle); db_srv_disc_req.type = NRF_BLE_GQ_REQ_SRV_DISCOVERY; db_srv_disc_req.params.gattc_srv_disc.start_handle = SRV_DISC_START_HANDLE; db_srv_disc_req.params.gattc_srv_disc.srvc_uuid = p_srv_being_discovered->srv_uuid; db_srv_disc_req.error_handler.p_ctx = p_db_discovery; db_srv_disc_req.error_handler.cb = discovery_error_handler; err_code = nrf_ble_gq_item_add(mp_gatt_queue, &db_srv_disc_req, conn_handle); if (err_code == NRF_SUCCESS) { p_db_discovery->discovery_in_progress = true; } return err_code; }
一旦启动寻找主服务,则剩余的动作过程就进入了GATT协议层,此时就需要进入GATT层处理函数ble_db_discovery_on_ble_evt里面了。 ble_db_discovery_on_ble_evt的声明如下:
/**@brief Macro for defining a ble_db_discovery instance.
*
* @param _name Name of the instance.
* @hideinitializer
*/
#define BLE_DB_DISCOVERY_DEF(_name) \
static ble_db_discovery_t _name = {.discovery_in_progress = 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)
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: on_disconnected(p_db_discovery, &(p_ble_evt->evt.gap_evt)); break; default: break; } }
程序流程进入到GATT层协议后首先要做的是寻找主服务,也就是在GAP层协议触发的BLE_GAP_EVT_CONNECTED事件后启动的ble_db_discovery_start,会在GATT层产生一个BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP事件,也就是主服务发现事件。在这个事件下通过on_primary_srv_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt))函数寻找主服务的信息参数。
/**@brief Function for handling primary service discovery response. * * @details This function will handle the primary service discovery response and start the * discovery of characteristics within that service. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. */ static void on_primary_srv_discovery_rsp(ble_db_discovery_t * p_db_discovery, ble_gattc_evt_t const * p_ble_gattc_evt) { ble_gatt_db_srv_t * p_srv_being_discovered; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle) { return; } if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS) { uint32_t err_code; ble_gattc_evt_prim_srvc_disc_rsp_t const * p_prim_srvc_disc_rsp_evt; NRF_LOG_DEBUG("Found service UUID 0x%x.", p_srv_being_discovered->srv_uuid.uuid); p_prim_srvc_disc_rsp_evt = &(p_ble_gattc_evt->params.prim_srvc_disc_rsp); p_srv_being_discovered->srv_uuid = p_prim_srvc_disc_rsp_evt->services[0].uuid; p_srv_being_discovered->handle_range = p_prim_srvc_disc_rsp_evt->services[0].handle_range; err_code = characteristics_discover(p_db_discovery, p_ble_gattc_evt->conn_handle); if (err_code != NRF_SUCCESS) { p_db_discovery->discovery_in_progress = false; // Error with discovering the service. // Indicate the error to the registered user application. discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle); m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE; m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle; } } else { NRF_LOG_DEBUG("Service UUID 0x%x not found.", p_srv_being_discovered->srv_uuid.uuid); // Trigger Service Not Found event to the application. discovery_complete_evt_trigger(p_db_discovery, false, p_ble_gattc_evt->conn_handle); on_srv_disc_completion(p_db_discovery, p_ble_gattc_evt->conn_handle); } }
如果发现主服务的信息(UUID),则会在GATT层触发BLE_GATTC_EVT_CHAR_DISC_RSP,在这个事件下 ,发现从机设备的特征值参数。
在GATT层触发BLE_GATTC_EVT_CHAR_DISC_RSP事件下 ,程序流程通过on_characteristic_discovery_rsp函数发现从机设备的特征值。
从机设备的主服务会定义多个特征值,因此在代码里面设置BLE_GATT_DB_MAX_CHARS宏定义来规定特征值的最大数量。在找到全部的特征值后,会启动查找描述符的工作。
/**@brief Function for handling characteristic discovery response. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. */ static void on_characteristic_discovery_rsp(ble_db_discovery_t * p_db_discovery, ble_gattc_evt_t const * p_ble_gattc_evt) { uint32_t err_code; ble_gatt_db_srv_t * p_srv_being_discovered; bool perform_desc_discov = false; if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle) { return; } p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS) { ble_gattc_evt_char_disc_rsp_t const * p_char_disc_rsp_evt; p_char_disc_rsp_evt = &(p_ble_gattc_evt->params.char_disc_rsp); // Find out the number of characteristics that were previously discovered (in earlier // characteristic discovery responses, if any). uint8_t num_chars_prev_disc = p_srv_being_discovered->char_count; // Find out the number of characteristics that are currently discovered (in the // characteristic discovery response being handled). uint8_t num_chars_curr_disc = p_char_disc_rsp_evt->count; // Check if the total number of discovered characteristics are supported by this module. if ((num_chars_prev_disc + num_chars_curr_disc) <= BLE_GATT_DB_MAX_CHARS) { // Update the characteristics count. p_srv_being_discovered->char_count += num_chars_curr_disc; } else { // The number of characteristics discovered at the peer is more than the supported // maximum. This module will store only the characteristics found up to this point. p_srv_being_discovered->char_count = BLE_GATT_DB_MAX_CHARS; } uint32_t i; uint32_t j; for (i = num_chars_prev_disc, j = 0; i < p_srv_being_discovered->char_count; i++, j++) { p_srv_being_discovered->charateristics[i].characteristic = p_char_disc_rsp_evt->chars[j]; p_srv_being_discovered->charateristics[i].cccd_handle = BLE_GATT_HANDLE_INVALID; p_srv_being_discovered->charateristics[i].ext_prop_handle = BLE_GATT_HANDLE_INVALID; p_srv_being_discovered->charateristics[i].user_desc_handle = BLE_GATT_HANDLE_INVALID; p_srv_being_discovered->charateristics[i].report_ref_handle = BLE_GATT_HANDLE_INVALID; } ble_gattc_char_t * p_last_known_char; p_last_known_char = &(p_srv_being_discovered->charateristics[i - 1].characteristic); // If no more characteristic discovery is required, or if the maximum number of supported // characteristic per service has been reached, descriptor discovery will be performed. if ( !is_char_discovery_reqd(p_db_discovery, p_last_known_char) || (p_srv_being_discovered->char_count == BLE_GATT_DB_MAX_CHARS)) { perform_desc_discov = true; } else { // Update the current characteristic index. p_db_discovery->curr_char_ind = p_srv_being_discovered->char_count; // Perform another round of characteristic discovery. err_code = characteristics_discover(p_db_discovery, p_ble_gattc_evt->conn_handle); if (err_code != NRF_SUCCESS) { p_db_discovery->discovery_in_progress = false; discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle); m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE; m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle; return; } } } else { // The previous characteristic discovery resulted in no characteristics. // descriptor discovery should be performed. perform_desc_discov = true; } if (perform_desc_discov) { bool raise_discov_complete; p_db_discovery->curr_char_ind = 0; err_code = descriptors_discover(p_db_discovery, &raise_discov_complete, p_ble_gattc_evt->conn_handle); if (err_code != NRF_SUCCESS) { p_db_discovery->discovery_in_progress = false; discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle); m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE; m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle; return; } if (raise_discov_complete) { // No more characteristics and descriptors need to be discovered. Discovery is complete. // Send a discovery complete event to the user application. NRF_LOG_DEBUG("Discovery of service with UUID 0x%x completed with success" " on connection handle 0x%x.", p_srv_being_discovered->srv_uuid.uuid, p_ble_gattc_evt->conn_handle); discovery_complete_evt_trigger(p_db_discovery, true, p_ble_gattc_evt->conn_handle); on_srv_disc_completion(p_db_discovery, p_ble_gattc_evt->conn_handle); } } }
如果找到了从机主服务的全部特征值,就会开始描述符的查找。即触发BLE_GATTC_EVT_DESC_DISC_RSP事件。
如果触发BLE_GATTC_EVT_DESC_DISC_RSP事件,则会调用on_descriptor_discovery_rsp函数:
/**@brief Function for handling descriptor discovery response. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. */ static void on_descriptor_discovery_rsp(ble_db_discovery_t * const p_db_discovery, const ble_gattc_evt_t * const p_ble_gattc_evt) { const ble_gattc_evt_desc_disc_rsp_t * p_desc_disc_rsp_evt; ble_gatt_db_srv_t * p_srv_being_discovered; if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle) { return; } p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_desc_disc_rsp_evt = &(p_ble_gattc_evt->params.desc_disc_rsp); ble_gatt_db_char_t * p_char_being_discovered = &(p_srv_being_discovered->charateristics[p_db_discovery->curr_char_ind]); if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS) { // The descriptor was found at the peer. // Iterate through and collect CCCD, Extended Properties, // User Description & Report Reference descriptor handles. for (uint32_t i = 0; i < p_desc_disc_rsp_evt->count; i++) { switch (p_desc_disc_rsp_evt->descs[i].uuid.uuid) { case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: p_char_being_discovered->cccd_handle = p_desc_disc_rsp_evt->descs[i].handle; break; case BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP: p_char_being_discovered->ext_prop_handle = p_desc_disc_rsp_evt->descs[i].handle; break; case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: p_char_being_discovered->user_desc_handle = p_desc_disc_rsp_evt->descs[i].handle; break; case BLE_UUID_REPORT_REF_DESCR: p_char_being_discovered->report_ref_handle = p_desc_disc_rsp_evt->descs[i].handle; break; } /* Break if we've found all the descriptors we are looking for. */ if (p_char_being_discovered->cccd_handle != BLE_GATT_HANDLE_INVALID && p_char_being_discovered->ext_prop_handle != BLE_GATT_HANDLE_INVALID && p_char_being_discovered->user_desc_handle != BLE_GATT_HANDLE_INVALID && p_char_being_discovered->report_ref_handle != BLE_GATT_HANDLE_INVALID) { break; } } } bool raise_discov_complete = false; if ((p_db_discovery->curr_char_ind + 1) == p_srv_being_discovered->char_count) { // No more characteristics and descriptors need to be discovered. Discovery is complete. // Send a discovery complete event to the user application. raise_discov_complete = true; } else { // Begin discovery of descriptors for the next characteristic. uint32_t err_code; p_db_discovery->curr_char_ind++; err_code = descriptors_discover(p_db_discovery, &raise_discov_complete, p_ble_gattc_evt->conn_handle); if (err_code != NRF_SUCCESS) { p_db_discovery->discovery_in_progress = false; // Error with discovering the service. // Indicate the error to the registered user application. discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle); m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE; m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle; return; } } if (raise_discov_complete) { NRF_LOG_DEBUG("Discovery of service with UUID 0x%x completed with success" " on connection handle 0x%x.", p_srv_being_discovered->srv_uuid.uuid, p_ble_gattc_evt->conn_handle); discovery_complete_evt_trigger(p_db_discovery, true, p_ble_gattc_evt->conn_handle); on_srv_disc_completion(p_db_discovery, p_ble_gattc_evt->conn_handle); } }
如果查找完描述符,则raise_discov_complete会被置位,进而会调用discovery_complete_evt_trigger函数。discovery_complete_evt_trigger函数里面会触发协议栈的BLE_DB_DISCOVERY_COMPLETE事件。
在main函数的db_discovery_init()中定义了一个发现服务的中断函数db_disc_handler
/** @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);
}
db_disc_handler中断函数定义如下;
/**@brief Function for handling database discovery events.
*
* @details This function is callback function to handle events from the database discovery module.
* Depending on the UUIDs that are discovered, this function should forward 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);
}
ble_nus_c_on_db_disc_evt最终会触发BLE_NUS_C_EVT_DISCOVERY_COMPLETE事件,至此完成了主机和从机的蓝牙连接过程。
从机到主机的蓝牙数据处理是靠协议栈回调函数ble_nus_c_on_ble_evt来处理的。ble_nus_c_on_ble_evt的声明如下:
/**@brief Macro for defining a ble_nus_c instance.
*
* @param _name Name of the instance.
* @hideinitializer
*/
#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)
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; } }
在此函数内调用了on_hvx函数
/**@brief Function for handling Handle Value Notification received from the SoftDevice. * * @details This function handles the Handle Value Notification received from the SoftDevice * and checks whether it is a notification of the Battery Level measurement from the peer. If * it is, this function decodes the battery level measurement and sends it to the * application. * * @param[in] p_ble_bas_c Pointer to the Battery Service Client structure. * @param[in] p_ble_evt Pointer to the BLE event received. */ static void on_hvx(ble_bas_c_t * p_ble_bas_c, ble_evt_t const * p_ble_evt) { // Check if the event is on the link for this instance. if (p_ble_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle) { return; } // Check if this notification is a battery level notification. if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_bas_c->peer_bas_db.bl_handle) { if (p_ble_evt->evt.gattc_evt.params.hvx.len == 1) { ble_bas_c_evt_t ble_bas_c_evt; ble_bas_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle; ble_bas_c_evt.evt_type = BLE_BAS_C_EVT_BATT_NOTIFICATION; ble_bas_c_evt.params.battery_level = p_ble_evt->evt.gattc_evt.params.hvx.data[0]; p_ble_bas_c->evt_handler(p_ble_bas_c, &ble_bas_c_evt); } } }
在这个函数里面有一句
p_ble_bas_c->evt_handler(p_ble_bas_c, &ble_bas_c_evt);
这里的函数指向的是ble_nus_c_evt_handler函数。因为在初始化函数nus_c_init内将函数指针指向了此处。如下所示。
init.evt_handler = ble_nus_c_evt_handler;
数据处理分析函数ble_nus_c_evt_handler如下:
/**@brief Callback handling 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);//使能TX通知 APP_ERROR_CHECK(err_code); NRF_LOG_INFO("Connected to device with Nordic UART Service."); break; case BLE_NUS_C_EVT_NUS_TX_EVT://从机上传TX事件 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; } }
该函数里面的BLE_NUS_C_EVT_DISCOVERY_COMPLETE事件类型,正是第2.5章节里面的上抛事件。
ble_nus_chars_received_uart_print函数内部实际就是调用了app_uart_put函数将数据通过串口发送出去。
主机串口接收数据通过蓝牙发送数据流分析和nrf52840蓝牙协议栈从机BLE串口里面的第3.1章的串口转蓝牙基本相同。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。