- 工作在主模式蓝牙初时化
    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
//  NRF_BLE_SCAN_UUID_CNT - Number of filters for UUIDs. 
#ifndef NRF_BLE_SCAN_UUID_CNT
#define NRF_BLE_SCAN_UUID_CNT 1
#endifstatic 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中定义
//  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
//  NRF_BLE_SCAN_UUID_CNT - Number of filters for UUIDs. 
#ifndef NRF_BLE_SCAN_UUID_CNT
#define NRF_BLE_SCAN_UUID_CNT 0
#endif
//  NRF_BLE_SCAN_NAME_CNT - Number of name filters. 
#ifndef NRF_BLE_SCAN_NAME_CNT
#define NRF_BLE_SCAN_NAME_CNT 1
#endifret_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;iparams.p_not_found->peer_addr.addr[i];
                        
                     }
                     
                  
                     
             
                         for(uint8_t j=0;jparams.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 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)
#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
 
                 
    