美文网首页物联网相关技术研究物联网loT从业者
NRF52832学习笔记(16)——GAP主机端扫描

NRF52832学习笔记(16)——GAP主机端扫描

作者: Leung_ManWah | 来源:发表于2020-03-14 16:53 被阅读0次

    一、背景

    1.1 蓝牙协议栈

    链路层(LL)控制设备的射频状态,有五个设备状态:待机、广播、扫描、初始化和连接。

    广播 为广播数据包,而 扫描 则是监听广播。

    GAP通信中角色,中心设备(Central - 主机) 用来扫描和连接 外围设备(Peripheral - 从机)

    大部分情况下外围设备通过广播自己来让中心设备发现自己,并建立 GATT 连接,从而进行更多的数据交换。

    也有些情况是不需要连接的,只要外设广播自己的数据即可,用这种方式主要目的是让外围设备,把自己的信息发送给多个中心设备。

    1.2 扫描概念

    扫描是一个在一定范围内用来寻址其他低功耗蓝牙设备广播的过程。扫描者设备在扫描过程中会使用广播信道。与广播过程不同的是,扫描过程没有严格的时间定义和信道规则。扫描过程应该按照由 Host 层所设定扫描定时参数还运行。

    1.2.1 被动扫描

    被动扫描:在被动扫描中,扫描设备应该仅仅去监听广播包,而不向广播设备发送任何数据。


    一旦扫描参数设置完成,主机就可以在协议栈中发送命令启动扫描。扫描过程中,如果控制器接收到符合过滤策略或其他规则的广播数据包,则发送一个广播报告事件给主机。报告事件除了有广播者的设备地址外,还包括广播数据包中的数据,以及接收广播数据包时的信号接收强度。我们可以利用该信号强度以及位于广播包中的发射功率,共同确定信号的路径损失,从而给出大致的范围,这个应用就是防丢器和蓝牙定位。

    1.2.2 主动扫描

    主动扫描:不仅可以捕获到从端设备的广播数据包,还可以捕获扫描响应包,并区分它们。


    控制器收到扫描数据后将向主机发送一个广播报告事件(adv_report),该事件包括了链路层数据包的广播类型。因此,主机能够判断从端设备是否可以连接或扫描,并且区分出广播数据包和扫描响应包。

    二、配置扫描参数

    2.1 扫描参数变量

    在 main.c 中

    static ble_gap_scan_params_t m_scan_param =                                         /**< Scan parameters requested for scanning and connection. */
    {
        .active        = 0x01,                                                          // 主动扫描
        .interval      = NRF_BLE_SCAN_SCAN_INTERVAL,                                    // 扫描间隔
        .window        = NRF_BLE_SCAN_SCAN_WINDOW,                                      // 扫描窗口
        .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL,
        .timeout       = NRF_BLE_SCAN_SCAN_DURATION,                                    // 扫描超时
        .scan_phys     = BLE_GAP_PHY_1MBPS,
        .extended      = true,
    };
    
    • active:是否主动扫描,配置为1则是主动扫描,0则是被动扫描
    • interval:扫描间隔,控制器间隔多长时间扫描一次,也就是两个连续的扫描窗口开始时间的时间间隔。在 NRF 上设置为 0x0004 and 0x4000 in 0.625ms units(2.5ms 到 10.24s)
    • window:扫描窗口,每次扫描所持续的时间,在持续时间内,扫描设备一直在广播信道上运行。在 NRF 上设置为 0x0004 and 0x4000 in 0.625ms units(2.5ms 到 10.24s)
    • filter_policy:扫描筛选策略,也就死说接受任何广播数据或者仅仅接受白名单设备的广播数据包。实际上就死决定是否使用白名单过滤广播数据包。这里注意一点,如果定向广播数据包中的目的地址并非是自己的,那么该数据必须抛弃,即使广播数据包的发送者在自己的白名单中。
    • timeout:扫描超时,超过指定的时间后,没有扫描到设备将停止扫描。在 NRF 上设置为 0x0001 and 0xFFFF in seconds,设置为 0 则认为没有 timeout
    • scan_phys:扫描的物理层速度

    注意:扫描窗口和扫描间隔两个参数非常重要。扫描窗口的设置要小于或等于扫描间隔,并且都要是 0.625ms 的整倍数。这两个参数决定了主机控制器的扫描占空比。比如,如果设置扫描间隔为 100 ms,扫描窗口为 10ms ,那么主机控制器的扫描占空比就死 10%。特别注意可以捕获的定向数据包的最低占空比为 0.4%,即每一秒中扫描时间为 3.75ms,这些时间设置在任何蓝牙 4.x 处理器中都是一致的,不仅仅限于 NRF 处理器。

    如果把时间间隔设置为相同的大小,那么控制器会进行连续扫描,每个间隔会改变扫描频率,也就死切换扫描信道。

    2.2 扫描过滤相关宏

    /**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies
     * @{ */
    #define BLE_GAP_SCAN_FP_ACCEPT_ALL                      0x00  /**< Accept all advertising packets except directed advertising packets
                                                                       not addressed to this device. */
    #define BLE_GAP_SCAN_FP_WHITELIST                       0x01  /**< Accept advertising packets from devices in the whitelist except directed
                                                                       packets not addressed to this device. */
    #define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED       0x02  /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL.
                                                                       In addition, accept directed advertising packets, where the advertiser's
                                                                       address is a resolvable private address that cannot be resolved. */
    #define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED 0x03  /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST.
                                                                       In addition, accept directed advertising packets, where the advertiser's
                                                                       address is a resolvable private address that cannot be resolved. */
    /**@} */
    
    • BLE_GAP_SCAN_FP_ACCEPT_ALL:接收所有的广播包,除去广播地址不是指向该设备的定向广播。
    • BLE_GAP_SCAN_FP_WHITELIST:接收在白名单里所有的广播,除去广播地址不是指向该设备的定向广播。
    • BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED:接收所有的广播包,包含定向广播包。这里如果广播MAC地址是私密地址,这里是无法被解析的。
    • BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED:接收白名单里所有的广播包,包含定向广播包。这里如果广播MAC地址是私密地址,这里是无法被解析的。

    2.3 定义扫描模块

    NRF_BLE_SCAN_DEF(m_scan);                                                           /**< Scanning module instance. */
    

    2.4 初始化扫描参数

    /**@brief Function for initialization 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.p_scan_param = &m_scan_param;
    
        err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        if(strlen(m_target_periph_name) != 0)
        {
            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_filter_set(&m_scan, 
                                           SCAN_UUID_FILTER, 
                                           &m_adv_uuids[HART_RATE_SERVICE_UUID_IDX]);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filter_set(&m_scan, 
                                           SCAN_UUID_FILTER, 
                                           &m_adv_uuids[RSCS_SERVICE_UUID_IDX]);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filters_enable(&m_scan, 
                                               NRF_BLE_SCAN_ALL_FILTER, 
                                               false);
        APP_ERROR_CHECK(err_code);
    }
    

    在 main 函数中,执行 scan_init() 进行初始化扫描参数

    /**@brief Function for initializing the application main entry.
     */
    int main(void)
    {
        bool erase_bonds;
    
        /*-------------------------- 外设驱初始化 ---------------------------*/
        // Initialize.
        log_init();                                 // 日志驱动初始化
    
        /*-------------------------- 蓝牙协议栈初始化 ---------------------------*/
        power_management_init();                    // 能量初始化
        ble_stack_init();                           // 协议栈初始化
        scan_init();                                // 扫描初始化
        gap_params_init();
        gatt_init();
        conn_params_init();                         // 连接参数初始化
        db_discovery_init();
        peer_manager_init();
        services_init();                            // 服务初始化
        advertising_init();                         // 广播初始化
        
        /*-------------------------- 开启应用 ---------------------------*/
        // Start execution.
        NRF_LOG_INFO("Relay example started.");
    
        if(erase_bonds == true)
        {
            NRF_LOG_INFO("delete_bonds");
            // Scanning and advertising is done upon PM_EVT_PEERS_DELETE_SUCCEEDED event.
            delete_bonds();
        }
        else
        {
            NRF_LOG_INFO("adv_scan_start"); 
            adv_scan_start();
        }
    
        // Enter main loop.
        for(;;)
        {
            idle_state_handle();
        }
    }
    

    三、开启扫描

    包含头文件

    #include "nrf_ble_scan.h"
    

    开启扫描函数

    /**@brief Function for initializing the scanning.
     */
    void scan_start(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_ble_scan_start(&m_scan);
        APP_ERROR_CHECK(err_code);
    }
    

    四、关闭扫描

    包含头文件

    #include "nrf_ble_scan.h"
    

    关闭扫描函数

    nrf_ble_scan_stop();
    

    五、广播报告

    控制器收到广播数据包后向主机发送一个广播报告事件。

    5.1 扫描事件处理

    在 main.c 中

    /**@brief   Function for handling BLE events from the central application.
     *
     * @details This function parses scanning reports and initiates a connection to peripherals when a
     *          target UUID is found. It updates the status of LEDs used to report the central application
     *          activity.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     */
    static void on_ble_central_evt(ble_evt_t const *p_ble_evt)
    {
        ret_code_t           err_code;
        ble_gap_evt_t const *p_gap_evt = &p_ble_evt->evt.gap_evt;
    
        switch(p_ble_evt->header.evt_id)
        {
            ···
            case BLE_GAP_EVT_ADV_REPORT:
                GetAdvReport(p_gap_evt->params.adv_report);
                break;
            ···
    

    5.2 获取广播报告

    /**
     @brief 获取广播数据
     @param advReport - 广播报告结构体
     @return 无
    */
    void GetAdvReport(ble_gap_evt_adv_report_t advReport)
    {
        // 在这里加入对广播报告的处理    
    }
    

    5.2.1 ble_gap_evt_adv_report_t

    /**@brief Event structure for @ref BLE_GAP_EVT_ADV_REPORT.
     *
     * @note If @ref ble_gap_adv_report_type_t::status is set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA,
     *       not all fields in the advertising report may be available.
     *
     * @note When ble_gap_adv_report_type_t::status is not set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA,
     *       scanning will be paused. To continue scanning, call @ref sd_ble_gap_scan_start.
     */
    typedef struct
    {
      ble_gap_adv_report_type_t type;                  /**< Advertising report type. See @ref ble_gap_adv_report_type_t. */
      ble_gap_addr_t            peer_addr;             /**< Bluetooth address of the peer device. If the peer_addr is resolved:
                                                            @ref ble_gap_addr_t::addr_id_peer is set to 1 and the address is the
                                                            peer's identity address. */
      ble_gap_addr_t            direct_addr;           /**< Contains the target address of the advertising event if
                                                            @ref ble_gap_adv_report_type_t::directed is set to 1. If the
                                                            SoftDevice was able to resolve the address,
                                                            @ref ble_gap_addr_t::addr_id_peer is set to 1 and the direct_addr
                                                            contains the local identity address. If the target address of the
                                                            advertising event is @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE,
                                                            and the SoftDevice was unable to resolve it, the application may try
                                                            to resolve this address to find out if the advertising event was
                                                            directed to us. */
      uint8_t                   primary_phy;           /**< Indicates the PHY on which the primary advertising packet was received.
                                                            See @ref BLE_GAP_PHYS. */
      uint8_t                   secondary_phy;         /**< Indicates the PHY on which the secondary advertising packet was received.
                                                            See @ref BLE_GAP_PHYS. This field is set to @ref BLE_GAP_PHY_NOT_SET if no packets
                                                            were received on a secondary advertising channel. */
      int8_t                    tx_power;              /**< TX Power reported by the advertiser in the last packet header received.
                                                            This field is set to @ref BLE_GAP_POWER_LEVEL_INVALID if the
                                                            last received packet did not contain the Tx Power field.
                                                            @note TX Power is only included in extended advertising packets. */
      int8_t                    rssi;                  /**< Received Signal Strength Indication in dBm of the last packet received. */
      uint8_t                   ch_index;              /**< Channel Index on which the last advertising packet is received (0-39). */
      uint8_t                   set_id;                /**< Set ID of the received advertising data. Set ID is not present
                                                            if set to @ref BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE. */
      uint16_t                  data_id:12;            /**< The advertising data ID of the received advertising data. Data ID
                                                            is not present if @ref ble_gap_evt_adv_report_t::set_id is set to
                                                            @ref BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE. */
      ble_data_t                data;                  /**< Received advertising or scan response data. If
                                                            @ref ble_gap_adv_report_type_t::status is not set to
                                                            @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the data buffer provided
                                                            in @ref sd_ble_gap_scan_start is now released. */
      ble_gap_aux_pointer_t     aux_pointer;           /**< The offset and PHY of the next advertising packet in this extended advertising
                                                            event. @note This field is only set if @ref ble_gap_adv_report_type_t::status
                                                            is set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. */
    } ble_gap_evt_adv_report_t;
    
    • type:广播报告类型
    • peer_addr:扫描设备的MAC地址。如果peer_addr被解析,那么参数ble_gap_addr_t::addr_id_peer被设置为1,同时该地址是对等方的身份地址
    • direct_addr:扫描定向广播的MAC地址。当参数ble_gap_adv_report_type_t::directed被设置为1,包含目的地址的广播事件。如果协议栈能够解析地址,参数ble_gap_addr_t::addr_id_peer被设置为1,direct_addr包含本地的认证地址。如果广播事件的目的地址是BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE类型,协议栈是服务解析的,应用程序可以尝试解析这个地址,以查明广播是否指向我们
    • primary_phy:主广播包的物理层速度
    • secondry_phy:第二扩展广播包的物理层速度。看参数BLE_GAP_PHYS。如果在二级广播频道上没有收到信息包,则此字段为0
    • tx_power:TX功率报告由广播客户端在最后收到的包头。如果最后收到的数据包不包含TX字段,则这个字段被设置为BLE_GAP_POWER_LEVEL_INVALID
    • rssi:接收的信号强度
    • ch_index:接收到最后一个广播包的频道(0-39)
    • set_id:设置接收广播数据的ID
    • data_id:接收的广播数据的广播数据ID
    • data:接收的广播数据包或者扫描响应包。如果参数ble_gap_adv_report_type_t::status没有被设置为参数BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA,参数sd_ble_gap_scan_start中提供的数据缓存立即释放
    • aux_pointer:在此扩展广播事件中,下一个广播包的偏移量。注意:只有当ble_gap_adv_report_type_t::status被设置为BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA时,该字段才会被设置

    5.2.2 ble_gap_adv_report_type_t

    /**@brief Advertising report type. */
    typedef struct
    {
      uint16_t connectable   : 1; /**< Connectable advertising event type. */
      uint16_t scannable     : 1; /**< Scannable advertising event type. */
      uint16_t directed      : 1; /**< Directed advertising event type. */
      uint16_t scan_response : 1; /**< Received a scan response. */
      uint16_t extended_pdu  : 1; /**< Received an extended advertising set. */
      uint16_t status        : 2; /**< Data status. See @ref BLE_GAP_ADV_DATA_STATUS. */
      uint16_t reserved      : 9; /**< Reserved for future use. */
    } ble_gap_adv_report_type_t;
    
    • connectable:可连接广播事件类型
    • scannable:可扫描广播事件类型
    • directed:定向广播事件类型
    • scan_response:收到扫描响应
    • extended_pdu:收到加长广播
    • status:数据状态,参考参数BLE_GAP_ADV_DATA_STATUS
    /**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status
     * @{ */
    // 广播包的所有数据已收到
    #define BLE_GAP_ADV_DATA_STATUS_COMPLETE             0x00 /**< All data in the advertising event have been received. */
    // 需要接收更多的数据
    #define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA 0x01 /**< More data to be received.
                                                                   @note This value will only be used if
                                                                   @ref ble_gap_scan_params_t::report_incomplete_evts and
                                                                   @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */
    // 不完整的数据,缓冲区大小不足以接收更多
    #define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED 0x02 /**< Incomplete data. Buffer size insufficient to receive more.
                                                                   @note This value will only be used if
                                                                   @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */
    // 未能接收剩余的数据
    #define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED    0x03 /**< Failed to receive the remaining data.
                                                                   @note This value will only be used if
                                                                   @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */
    /**@} */
    
    • reserved:保留部分

    5.2.3 ble_data_t

    /**@brief Data structure. */
    typedef struct
    {
      uint8_t     *p_data;  /**< Pointer to the data buffer provided to/from the application. */
      uint16_t     len;     /**< Length of the data buffer, in bytes. */
    } ble_data_t;
    
    • p_data:广播或扫描响应的数据
    • len:广播或扫描响应的数据长度

    • 由 Leung 写于 2020 年 3 月 14 日

    • 参考:青风电子社区

    相关文章

      网友评论

        本文标题:NRF52832学习笔记(16)——GAP主机端扫描

        本文链接:https://www.haomeiwen.com/subject/oqofshtx.html