NRF52832學習筆記(16)——GAP主機端掃描

一、背景

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 日

• 參考:青風電子社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章