nrf51822---主从通信(1)

来源:互联网 发布:郭天祥单片机教材下载 编辑:程序博客网 时间:2024/05/17 09:35

1.目的

   学习nrf51822主机和从机通信

2.分析

    2个设备,一个做主机一个做从机,相互通信   

3.平台:

协议栈版本:SDK10.0.0

编译软件:keil 5.12

硬件平台:nrf51822最小系统

例子:SDK 10.0.0\examples\ble_peripheral\ble_app_uart\pca10028\s110\arm4 从机例子

          SDK10.0\examples\ble_central_and_peripheral\experimental\ble_app_hrs_rscs_relay\pca10028\s130\arm4 做主机

      

4.步骤

   1.先把从机的程序下载到一个板子里面

   注意:a.32.769khz晶体的选型。b.SDK 以及softwaredevice的版本号

    2.来分析下主机的程序

   协议栈初始化,串口服务初始化,开始扫描参数初始化以及开始扫描

int main(void){    uint32_t err_code;        APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, NULL);        uart_init();    buttons_leds_init();        ble_stack_init();        err_code = ble_db_discovery_init();    APP_ERROR_CHECK(err_code);        nus_c_init();    // Start scanning for peripherals and initiate connection    // with devices that advertise NUS UUID.    scan_start();    APPL_LOG("Scan started\r\n");    for (;;)    {        power_manage();    }}


这里初始化回调函数,一个串口服务初始化

/**@brief Function for initializing the NUS Client. */static void nus_c_init(void){    uint32_t         err_code;    ble_nus_c_init_t nus_c_init_t;        nus_c_init_t.evt_handler = ble_nus_c_evt_handler;        err_code = ble_nus_c_init(&m_ble_nus_c, &nus_c_init_t);    APP_ERROR_CHECK(err_code);}

这里是最终注册函数,看如下函数

sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type); 获得uuid的类型

 uuid的类型有 

/** @defgroup BLE_UUID_TYPES Types of UUID * @{ */#define BLE_UUID_TYPE_UNKNOWN       0x00 /**< Invalid UUID type. */#define BLE_UUID_TYPE_BLE           0x01 /**< Bluetooth SIG UUID (16-bit). */#define BLE_UUID_TYPE_VENDOR_BEGIN  0x02 /**< Vendor UUID types start at this index (128-bit). *//** @} */

  uart_uuid.type = p_ble_nus_c->uuid_type;  //串口服务的类型
  uart_uuid.uuid = BLE_UUID_NUS_SERVICE; //串口主服务的UUID


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;            if ((p_ble_nus_c == NULL) || (p_ble_nus_c_init == NULL))    {        return NRF_ERROR_NULL;    }        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);    if (err_code != NRF_SUCCESS)    {        return err_code;    }        uart_uuid.type = p_ble_nus_c->uuid_type;    uart_uuid.uuid = BLE_UUID_NUS_SERVICE;        // save the pointer to the ble_uart_c_t struct locally    mp_ble_nus_c = p_ble_nus_c;        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->nus_rx_handle = BLE_GATT_HANDLE_INVALID;    p_ble_nus_c->nus_tx_handle = BLE_GATT_HANDLE_INVALID;        return ble_db_discovery_evt_register(&uart_uuid, db_discover_evt_handler);}

串口服务回调函数可以看到对应的事件类型的处理,因为串口服务只有2个特征值,一个notify(通知) 和一个write and write no response(写并无返回)的属性

 这里在描述对应事件的时候就会产生对应的事件,比如扫描的时候发现了write and write no response(BLE_NUS_C_EVT_FOUND_NUS_TX_CHARACTERISTIC)的特征值就是跳到BLE_NUS_C_EVT_FOUND_NUS_TX_CHARACTERISTIC事件,

 扫描到notify(BLE_NUS_C_EVT_FOUND_NUS_RX_CHARACTERISTIC)的事件,主机要使能从机,这样才能接到从机主动发来的信息,

BLE_NUS_C_EVT_NUS_RX_EVT 事件是,当使能了从机,从机发送过来信息的时候产生的事件,

BLE_NUS_C_EVT_DISCONNECTED ,蓝牙断开事件,断开从新开始扫描

<pre name="code" class="cpp">/**@snippet [Handling events from the ble_nus_c module] */ static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, const ble_nus_c_evt_t * p_ble_nus_evt){    uint32_t err_code;    switch (p_ble_nus_evt->evt_type)    {        case BLE_NUS_C_EVT_FOUND_NUS_TX_CHARACTERISTIC:            APPL_LOG("The device has the device TX characteristic\r\n");            break;                case BLE_NUS_C_EVT_FOUND_NUS_RX_CHARACTERISTIC:            err_code = ble_nus_c_rx_notif_enable(p_ble_nus_c);            APP_ERROR_CHECK(err_code);            APPL_LOG("The device has the device RX characteristic\r\n");            break;                case BLE_NUS_C_EVT_NUS_RX_EVT:            for (uint32_t i = 0; i < p_ble_nus_evt->data_len; i++)            {                while(app_uart_put( p_ble_nus_evt->p_data[i]) != NRF_SUCCESS);            }            break;                case BLE_NUS_C_EVT_DISCONNECTED:            APPL_LOG("NUS device disconnected\r\n");            scan_start();            break;    }}

开始扫描主要是扫描参数的设置。
<pre name="code" class="cpp">#define SCAN_INTERVAL           0x00A0                          /**< Determines scan interval in units of 0.625 millisecond. */#define SCAN_WINDOW             0x0050                          /**< Determines scan window in units of 0.625 millisecond. */#define SCAN_ACTIVE             1                               /**< If 1, performe active scanning (scan requests). */#define SCAN_SELECTIVE          0                               /**< If 1, ignore unknown devices (non whitelisted). */#define SCAN_TIMEOUT            0x0000    

/** * @brief Parameters used when scanning. */static const ble_gap_scan_params_t m_scan_params =   {    .active      = SCAN_ACTIVE,    .selective   = SCAN_SELECTIVE,    .p_whitelist = NULL,    .interval    = SCAN_INTERVAL,    .window      = SCAN_WINDOW,    .timeout     = SCAN_TIMEOUT  };

/**@brief Function to start scanning. */static void scan_start(void){    uint32_t err_code;        err_code = sd_ble_gap_scan_start(&m_scan_params);    APP_ERROR_CHECK(err_code);        err_code = bsp_indication_set(BSP_INDICATE_SCANNING);    APP_ERROR_CHECK(err_code);}


开始扫描后如果发现了广播数据,就会产生广播报告事件。即BLE_GAP_EVT_ADV_REPORT事件,然后在通过is_uuid_present() 函数来找对应的是UUID以及类型,通过这2个特征来识别是不是要连接的从机,然后通过sd_ble_gap_connect来连接从机,连接是通过mac地址来连接的如下

err_code = sd_ble_gap_connect(&p_adv_report->peer_addr,
                                              &m_scan_params,
                                              &m_connection_param);

 当连接上了蓝牙产生,BLE_GAP_EVT_CONNECTED事件,在这里,

    开始发现服务和特征值:ble_db_discovery_start(&m_ble_db_discovery, p_ble_evt->evt.gap_evt.conn_handle);具体代码如下:

/**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler. * * @details This function is called from the scheduler in the main loop after a BLE stack event has *  been received. * * @param[in]   p_ble_evt   Bluetooth stack event. */static void ble_evt_dispatch(ble_evt_t * p_ble_evt){    on_ble_evt(p_ble_evt);      bsp_btn_ble_on_ble_evt(p_ble_evt);    ble_db_discovery_on_ble_evt(&m_ble_db_discovery, p_ble_evt);    ble_nus_c_on_ble_evt(&m_ble_nus_c,p_ble_evt);}


/**@brief Function for handling the Application's BLE Stack events. * * @param[in]   p_ble_evt   Bluetooth stack event. */static void on_ble_evt(ble_evt_t * p_ble_evt){    uint32_t              err_code;    const ble_gap_evt_t * p_gap_evt = &p_ble_evt->evt.gap_evt;        switch (p_ble_evt->header.evt_id)    {        case BLE_GAP_EVT_ADV_REPORT:        {            const ble_gap_evt_adv_report_t *p_adv_report = &p_gap_evt->params.adv_report;                                    if (is_uuid_present(&m_nus_uuid, p_adv_report))            {                err_code = sd_ble_gap_connect(&p_adv_report->peer_addr,                                              &m_scan_params,                                              &m_connection_param);                                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);                    APPL_LOG("Connecting to target %02x%02x%02x%02x%02x%02x\r\n",                             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]                             );                }            }            break;        }               case BLE_GAP_EVT_CONNECTED:            APPL_LOG("Connected to target\r\n");            err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);            APP_ERROR_CHECK(err_code);                        m_ble_nus_c.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;            // start discovery of services. The NUS Client waits for a discovery result            err_code = ble_db_discovery_start(&m_ble_db_discovery, 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)            {                APPL_LOG("[APPL]: Scan timed out.\r\n");                scan_start();            }            else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)            {                APPL_LOG("[APPL]: Connection Request timed out.\r\n");            }            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;           default:            break;    }}

开始发现服务,也会产生对应的事件,代码如下:第一次扫描发现的是主服务:产生的是BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP事件。表示找到了主服务

 

void ble_db_discovery_on_ble_evt(ble_db_discovery_t * const p_db_discovery,                                 const ble_evt_t * const    p_ble_evt){    if ((p_db_discovery == NULL) || (p_ble_evt == NULL))    {        // Null pointer provided. Return.        return;    }    if (!m_initialized)    {        return;    }      switch (p_ble_evt->header.evt_id)    {        case BLE_GAP_EVT_CONNECTED:SEGGER_RTT_printf(0,"BLE_GAP_EVT_CONNECTED\r\n");            p_db_discovery->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;            break;                case BLE_GAP_EVT_DISCONNECTED:            memset(p_db_discovery, 0, sizeof(ble_db_discovery_t));            p_db_discovery->conn_handle = BLE_CONN_HANDLE_INVALID;            break;        case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:  <strong>//找到了主服务</strong>SEGGER_RTT_printf(0,"BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP\r\n");            on_primary_srv_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));            break;        case BLE_GATTC_EVT_CHAR_DISC_RSP: SEGGER_RTT_printf(0,"BLE_GATTC_EVT_CHAR_DISC_RSP\r\n");            on_characteristic_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));            break;        case BLE_GATTC_EVT_DESC_DISC_RSP:SEGGER_RTT_printf(0,"BLE_GATTC_EVT_DESC_DISC_RSP\r\n");  //SEGGER_RTT_printf(0,"\r\np_ble_evt->header.evt_id=%d\r\n,p_ble_evt->header.evt_id");            on_descriptor_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));            break;        default:            break;    }}

这里是发现主服务之后的处理,找特征值:characteristics_discover(p_db_discovery);

static void on_primary_srv_discovery_rsp(ble_db_discovery_t * const    p_db_discovery,                                         const ble_gattc_evt_t * const p_ble_gattc_evt){    if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)    {        uint32_t err_code;        const ble_gattc_evt_prim_srvc_disc_rsp_t * p_prim_srvc_disc_rsp_evt;        ble_gatt_db_srv_t                        * p_srv_being_discovered;        p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);        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);               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);        }    }    else    {        // Trigger Service Not Found event to the application.        discovery_complete_evt_trigger(p_db_discovery, false);           on_srv_disc_completion(p_db_discovery);    }}



找到特征值后会产生BLE_GATTC_EVT_CHAR_DISC_RSP事件,然后会处理,on_characteristic_discovery_rsp()函数,该函数注意2点,是否全部找到了特征值,如果没有找到继续找,如果找到了,这找描述符。

  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;
        }

   判断是否找全了特征值,或者是否超出了设置的特征值的数量,BLE_GATT_DB_MAX_CHARS是预定义的一个特征值的个数,意思就是,假如一个服务里面有超过BLE_GATT_DB_MAX_CHARS特征值,则认为是全部找到了。可以在项目中适当的改变这个值的大小。

  当全部找到了特征值,则descriptors_discover(p_db_discovery, &raise_discov_complete); 找描述符

static void on_characteristic_discovery_rsp(ble_db_discovery_t * const    p_db_discovery,                             const 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;        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)    {        const ble_gattc_evt_char_disc_rsp_t * 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;        }              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); <strong> //找特征值</strong>            if (err_code != NRF_SUCCESS)            {                p_db_discovery->discovery_in_progress = false;                discovery_error_evt_trigger(p_db_discovery, err_code);                                 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); <strong>//找描述符</strong>        if (err_code != NRF_SUCCESS)        {            p_db_discovery->discovery_in_progress = false;            discovery_error_evt_trigger(p_db_discovery, err_code);                      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.            DB_LOG("[DB]: Discovery of service with UUID 0x%x completed with success for Connection"                   " handle %d\r\n", p_srv_being_discovered->srv_uuid.uuid,                   p_db_discovery->conn_handle);            discovery_complete_evt_trigger(p_db_discovery, true);                         on_srv_disc_completion(p_db_discovery);        }    }}

找到了描述符则会产生BLE_GATTC_EVT_DESC_DISC_RSP事件,如果没有找全 则descriptors_discover(p_db_discovery, &raise_discov_complete);,再次发现描述符,并再次产生BLE_GATTC_EVT_DESC_DISC_RSP事件,如果全部找到了则 discovery_complete_evt_trigger(p_db_discovery, true);


/**@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;    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.        // If the descriptor was a CCCD, then the cccd_handle needs to be populated.        uint32_t i;        // Loop through all the descriptors to find the CCCD.        for (i = 0; i < p_desc_disc_rsp_evt->count; i++)        {            if (                p_desc_disc_rsp_evt->descs[i].uuid.uuid ==                BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG               )            {                p_char_being_discovered->cccd_handle = p_desc_disc_rsp_evt->descs[i].handle;                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);        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);                return;        }    }    if (raise_discov_complete)    {        DB_LOG("[DB]: Discovery of service with UUID 0x%x completed with success for Connection"               "handle %d\r\n", p_srv_being_discovered->srv_uuid.uuid,               p_db_discovery->conn_handle);        SEGGER_RTT_printf(0,"Discovery\r\n");        discovery_complete_evt_trigger(p_db_discovery, true);        on_srv_disc_completion(p_db_discovery);    }}



现在来具体分析下这个函数:

首先找到对应的回调函数p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));

 nus_c_init(); --->  ble_nus_c_init(&m_ble_nus_c, &nus_c_init_t);-->ble_db_discovery_evt_register(&uart_uuid, db_discover_evt_handler);--->registered_handler_set(p_uuid, evt_handler);

static uint32_t registered_handler_set(const ble_uuid_t * const       p_srv_uuid,
                                       ble_db_discovery_evt_handler_t p_evt_handler)
{
    if (m_num_of_handlers_reg < DB_DISCOVERY_MAX_USERS)
    {
        m_registered_handlers[m_num_of_handlers_reg].srv_uuid    = *p_srv_uuid;
        m_registered_handlers[m_num_of_handlers_reg].evt_handler = p_evt_handler;


        m_num_of_handlers_reg++;


        return NRF_SUCCESS;
    }
    else
    {
        return NRF_ERROR_NO_MEM;
    }
}

通过一层一层,把串口的服务的类型 和回调函数复制给了m_registered_handlers结构体保存期来了,如果还有其他的服务也可以按照同样步骤添加。

最后把static void db_discover_evt_handler(ble_db_discovery_evt_t * p_evt)函数地址保存在m_registered_handlers里面了

再看

static ble_db_discovery_evt_handler_t registered_handler_get(ble_uuid_t * p_srv_uuid)
{
    uint32_t i;


    for (i = 0; i < m_num_of_handlers_reg; i++)
    {
        if (BLE_UUID_EQ(&(m_registered_handlers[i].srv_uuid), p_srv_uuid))
        {
            return (m_registered_handlers[i].evt_handler);
        }
    }


    return NULL;
}

这里就是把输入的UUID的类型和m_registered_handlers保存的UUID的类型对比,如果一样则返回它对应的回调函数。

然后在m_pending_user_evts结构体赋值。因为is_srv_found == true

     if (is_srv_found)
            {
                m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
                    BLE_DB_DISCOVERY_COMPLETE;


                m_pending_user_evts[m_pending_usr_evt_index].evt.params.discovered_db =
                    *p_srv_being_discovered;
            }

最后执行, pending_user_evts_send();

/**@brief Function for sending all pending discovery events to the corresponding user modules.
 */
static void pending_user_evts_send(void)
{
    uint32_t i;


    for (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;
}

在discovery_complete_evt_trigger里面

    p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));   ------>  m_pending_user_evts[m_pending_usr_evt_index].evt_handler         = p_evt_handler; // 把回调函数赋值给m_pending_user_evts对应的地址。

   m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =   BLE_DB_DISCOVERY_COMPLETE;

这样就执行了db_discover_evt_handler(ble_db_discovery_evt_t * p_evt)函数


static void discovery_complete_evt_trigger(ble_db_discovery_t * const p_db_discovery,                                           bool                       is_srv_found){    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 =                p_db_discovery->conn_handle;            if (is_srv_found)            {                m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =                    BLE_DB_DISCOVERY_COMPLETE;                m_pending_user_evts[m_pending_usr_evt_index].evt.params.discovered_db =                    *p_srv_being_discovered;            }            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.)            }        }    }}

这里会把发现的特征值全部过一遍,然后执行对应的处理。执行对应的回调

经过 nus_c_init()---> ble_nus_c_init(); 执行 ,把 ble_nus_c_evt_handler函数地址赋值给了mp_ble_nus_c.evt_handler

所以mp_ble_nus_c->evt_handler 就是 ble_nus_c_evt_handler。

p_evt就发现一个服务的全部信息的结构体,比如主服务的UUID,特征值的UUID一个权限,handle,发现特征值的个数(p_evt->params.discovered_db.char_count)等等,因为串口有2个特征值,write和notify 对应BLE_UUID_NUS_TX_CHARACTERISTIC和BLE_UUID_NUS_RX_CHARACTERISTIC 2个UUID,所以只要在找到对应的uuid,并保存下handle就好了。(假如提前并不知道对方的属性呢?)

 注意:为什么这里要保存handle,因为当主机发送要发数据给从机的时候,比如有好几个特征值,要往某个特定的UUID发送数据,就必须知道地址,而handle就是类是地址,每个特征值对应的地址,当主机连上从机后,知道了handle就可以往特定的权限的UUID通信了。

static void db_discover_evt_handler(ble_db_discovery_evt_t * p_evt){    // 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 == mp_ble_nus_c->uuid_type)    {        uint32_t i;               for (i = 0; i < p_evt->params.discovered_db.char_count; i++)        {            if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid                 == BLE_UUID_NUS_TX_CHARACTERISTIC)            {                mp_ble_nus_c->nus_tx_handle =                    p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;                                if (mp_ble_nus_c->evt_handler != NULL)                {                    ble_nus_c_evt_t nus_c_evt;                                        nus_c_evt.evt_type = BLE_NUS_C_EVT_FOUND_NUS_TX_CHARACTERISTIC;                    mp_ble_nus_c->evt_handler(mp_ble_nus_c, &nus_c_evt);                }            }            else if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid                         == BLE_UUID_NUS_RX_CHARACTERISTIC)            {                mp_ble_nus_c->nus_rx_handle =                    p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;                mp_ble_nus_c->nus_rx_cccd_handle =                    p_evt->params.discovered_db.charateristics[i].cccd_handle;                  if (mp_ble_nus_c->evt_handler != NULL)                {                    ble_nus_c_evt_t nus_c_evt;                                    nus_c_evt.evt_type = BLE_NUS_C_EVT_FOUND_NUS_RX_CHARACTERISTIC;                    mp_ble_nus_c->evt_handler(mp_ble_nus_c, &nus_c_evt);                }            }        }    }}


接下看对应的事件会对应对的case 事件。这里看 BLE_NUS_C_EVT_FOUND_NUS_RX_CHARACTERISTIC 事件。这事件表示特征值的属性为notify 所以要使能监听才能收到数据,使能操作ble_nus_c_rx_notif_enable(p_ble_nus_c);

BLE_NUS_C_EVT_NUS_RX_EVT为接收从机发送数据事件。

/**@snippet [Handling events from the ble_nus_c module] */ static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, const ble_nus_c_evt_t * p_ble_nus_evt){    uint32_t err_code;    switch (p_ble_nus_evt->evt_type)    {        case BLE_NUS_C_EVT_FOUND_NUS_TX_CHARACTERISTIC:            APPL_LOG("The device has the device TX characteristic\r\n");            break;                case BLE_NUS_C_EVT_FOUND_NUS_RX_CHARACTERISTIC:            err_code = ble_nus_c_rx_notif_enable(p_ble_nus_c);            APP_ERROR_CHECK(err_code);            APPL_LOG("The device has the device RX characteristic\r\n");            break;               case BLE_NUS_C_EVT_NUS_RX_EVT:            for (uint32_t i = 0; i < p_ble_nus_evt->data_len; i++)            {                while(app_uart_put( p_ble_nus_evt->p_data[i]) != NRF_SUCCESS);            }            break;                case BLE_NUS_C_EVT_DISCONNECTED:            APPL_LOG("NUS device disconnected\r\n");            scan_start();            break;    }}


好了 到现在大概分析完了程序执行的流程。。。。。。上一张图对应ble_db_discovery_on_ble_evt()函数,执行流程


0 0
原创粉丝点击