900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > nrf52840蓝牙协议栈主机BLE串口

nrf52840蓝牙协议栈主机BLE串口

时间:2023-12-23 18:28:15

相关推荐

nrf52840蓝牙协议栈主机BLE串口

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有变化。

二、主机连接从机过程分析

2.1、主机开始扫描广播

首先在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_REPORTcase 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 resulterr_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 supportederr_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;}}

2.2、主机分析广播数据并连接

当产生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 connecterr_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函数进行连接,否则就继续扫描。

2.3、连接成功并寻找服务

如果连接成功,则协议栈会产生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_terr_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;}

2.4、发现主服务

一旦启动寻找主服务,则剩余的动作过程就进入了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;}}

2.4.1、查找从机主服务的UUID

程序流程进入到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))函数寻找主服务的信息参数。

/**@briefFunction 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,在这个事件下 ,发现从机设备的特征值参数。

2.4.2、查找从机主服务的特征值

在GATT层触发BLE_GATTC_EVT_CHAR_DISC_RSP事件下 ,程序流程通过on_characteristic_discovery_rsp函数发现从机设备的特征值。

从机设备的主服务会定义多个特征值,因此在代码里面设置BLE_GATT_DB_MAX_CHARS宏定义来规定特征值的最大数量。在找到全部的特征值后,会启动查找描述符的工作。

/**@briefFunction 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;boolperform_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事件。

2.4.3、查找从机主服务的描述符

如果触发BLE_GATTC_EVT_DESC_DISC_RSP事件,则会调用on_descriptor_discovery_rsp函数:

/**@briefFunction 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事件。

2.5、发现中断函数

在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事件,至此完成了主机和从机的蓝牙连接过程。

三、从机到主机的蓝牙数据流分析

3.1、函数嵌套分析

从机到主机的蓝牙数据处理是靠协议栈回调函数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函数

/**@briefFunction 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;

3.2、数据处理分析

数据处理分析函数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章的串口转蓝牙基本相同。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。