nrf52832 sdk15.2.0蓝牙主模式工作过程分析(uart官网实例)

  • 工作在主模式蓝牙初时化

    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函数即可发送

   Demo下载地址:https://download.csdn.net/download/mygod2008ok/11162759

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 要下载青风nRF52832 SDK,首先需要访问青风官方网站。在该网站上,您可以找到一个专门的SDK下载页面。在该页面上,您会看到一些相关的信息,例如nRF52832芯片的版本号,SDK的最新版本号以及其他支持的硬件和软件要求。 在页面上,您可以找到一个下载按钮,点击该按钮将开始SDK的下载过程。下载过程可能需要一些时间,具体取决于您的网络连接速度。 下载完成后,您将获得一个压缩文件,其中包含青风nRF52832 SDK的所有文件和文件夹。您可以将该文件解压缩到您选择的目标文件夹中。 解压缩后,您将可以看到一些重要的文件和文件夹,如示例代码、文档、库文件和支持工具等。在这些文件和文件夹中,您可以找到有关SDK的详细信息和使用指南。 如果您打算在开发项目中使用这个SDK,您可以根据需要选择和使用适当的示例代码和库文件。此外,您还可以参考SDK的文档和指南,以获得更多有关SDK的信息和帮助。 总之,要下载青风nRF52832 SDK,您需要访问青风官网SDK下载页面,并按照提示完成下载和解压缩过程。下载后,您可以开始使用SDK的示例代码和其他支持工具来进行开发。 ### 回答2: 青风nrf52832是一款基于Nordic Semiconductor的nRF52832芯片的开发板,可以进行蓝牙低功耗设备的开发和应用。nRF52832 SDK是青风nrf52832开发板所需要的软件开发工具包。以下是青风nrf52832 SDK下载的步骤: 1. 首先,打开浏览器,进入青风官方网站的下载页面。 2. 在下载页面中找到nRF52832 SDK软件包,它通常以压缩文件的形式提供。 3. 点击下载链接,开始下载nRF52832 SDK软件包。下载过程可能需要一些时间,取决于您的网络连接速度。 4. 下载完成后,使用解压软件将软件包解压到您希望保存的位置。解压后,您将得到一个包含SDK的文件夹。 5. 进入解压后的文件夹,可以看到SDK的各种软件工具和示例代码。 6. 根据自己的需求,可以使用SDK提供的示例代码进行开发,或者查看SDK文档进行更详细的学习和使用。 请注意,下载过程中需要确保网络连接正常,同时确保您的设备符合软件包的系统要求,以确保成功下载和使用青风nrf52832 SDK

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风雨依依

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值