中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

wordpress使用指南網(wǎng)站seo最新優(yōu)化方法

wordpress使用指南,網(wǎng)站seo最新優(yōu)化方法,佛山網(wǎng)站建設(shè)服務(wù),武漢教育網(wǎng)站建設(shè)公司前言 前面我們已經(jīng)了解了 ESP32 的 BLE 整體架構(gòu),現(xiàn)在我們開始實際學(xué)習(xí)一下Bluedroid 從機(jī)篇的廣播和掃描。本文將會以 ble_ibeacon demo 為例子進(jìn)行講解,需要注意的一點是。ibeacon 分為兩個部分,一個是作為廣播者,一個是作為觀…

前言

  1. 前面我們已經(jīng)了解了 ESP32 的 BLE 整體架構(gòu),現(xiàn)在我們開始實際學(xué)習(xí)一下Bluedroid 從機(jī)篇的廣播和掃描。
  2. 本文將會以 ble_ibeacon demo 為例子進(jìn)行講解,需要注意的一點是。ibeacon 分為兩個部分,一個是作為廣播者,一個是作為觀察者。IBEACON_RECEIVER 這個宏表示作為觀察者IBEACON_SENDER 這個宏被置 1 表示為廣播者。
  3. 需要注意的一點是,本文先僅介紹廣播相關(guān)內(nèi)容

ibeacon 介紹

ibeacon 是什么?

  1. 作為一名初學(xué)者,當(dāng)聽到 ibeacon 時候,大概率是一臉懵逼的。即使網(wǎng)上搜索大量資料,沒有親身體驗,也是一頭霧水。為了方便各位理解,就以我來上海實習(xí),周末逛的第一個景點 – 豫園 為例子進(jìn)行分析。
  2. 當(dāng)我們進(jìn)入景點,肯定會有一個二維碼建議我們掃描,然后之后就會有電子講解功能。例如我現(xiàn)在掃描了豫園的二維碼,打開了一個微信小程序,此時微信小程序上就能夠顯示出我的位置在哪里。

在這里插入圖片描述
3. 如果你移動到一個地方,該小程序就會進(jìn)行相關(guān)講解當(dāng)前景點的一些歷史文化信息。此時,各位有沒有想過一個問題,該小程序,是如何精確的知道我們當(dāng)前是在哪個景點呢?
4. 此時,就是利用的 ibeacon 技術(shù)進(jìn)行的。如果你有興趣的話,可以在走到某個景點,發(fā)現(xiàn)微信小程序播報講解時刻停下來,然后在這個附近十米內(nèi)的范圍轉(zhuǎn)轉(zhuǎn),會驚奇的發(fā)現(xiàn),一些地方藏有這種小方塊。

在這里插入圖片描述

在這里插入圖片描述
5. 這個小方塊,就是本文要進(jìn)行講解的,ESP32 作為廣播者的功能。而你手機(jī),就是充當(dāng)?shù)?strong>觀察者。

ibeacon 有什么用?

  1. 現(xiàn)在我們明白了 ibeacon 技術(shù)大概是什么東西了。那么這個有什么作用呢?從上面的例子我們就可以很好的知道,室內(nèi)定位廣播信息。
  2. 當(dāng)前,室內(nèi)定位技術(shù)一直是一項值得探索的技術(shù),ibeacon 可以說提供了一個不錯的選擇(不過個人感覺目前 BLE 室內(nèi)定位更多的是聚焦于 AOA)。
  3. 同樣,在商場,我們只需要打開微信小程序走到哪家店鋪,就可以直接查看那家店鋪的商品信息,這樣一定程度上可以方便用戶挑選商品。

ibeacon 工程介紹

工程源碼

  1. 我們先拷貝 ble_ibeacon demo 例程出來,打開ibeacon_demo.c 文件,將其替換為如下內(nèi)容。
/** SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD** SPDX-License-Identifier: Unlicense OR CC0-1.0*//****************************************************************************
*
* This file is for iBeacon demo. It supports both iBeacon sender and receiver
* which is distinguished by macros IBEACON_SENDER and IBEACON_RECEIVER,
*
* iBeacon is a trademark of Apple Inc. Before building devices which use iBeacon technology,
* visit https://developer.apple.com/ibeacon/ to obtain a license.
*
****************************************************************************/#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs_flash.h"#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gattc_api.h"
#include "esp_gatt_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_defs.h"
#include "esp_ibeacon_api.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"static const char* DEMO_TAG = "IBEACON_DEMO";
extern esp_ble_ibeacon_vendor_t vendor_config;#if (IBEACON_MODE == IBEACON_RECEIVER)
// 在停止掃描請求發(fā)送后,藍(lán)牙堆??赡苓€會處理一些尚未完成的掃描結(jié)果。因此需要通過這個標(biāo)志位來設(shè)置是否需要繼續(xù)處理掃描完成事件
static bool is_scanning = false;
#endif///Declare static functions
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);#if (IBEACON_MODE == IBEACON_RECEIVER)
static esp_ble_scan_params_t ble_scan_params = {.scan_type              = BLE_SCAN_TYPE_ACTIVE, // 主動掃描.own_addr_type          = BLE_ADDR_TYPE_PUBLIC, // 公共地址.scan_filter_policy     = BLE_SCAN_FILTER_ALLOW_ALL, // 允許掃描所有設(shè)備.scan_interval          = 0x50,.scan_window            = 0x30,.scan_duplicate         = BLE_SCAN_DUPLICATE_DISABLE
};#elif (IBEACON_MODE == IBEACON_SENDER)
static esp_ble_adv_params_t ble_adv_params = {.adv_int_min        = 0x20,                 // 0x20*0.625ms=20ms,Range: 0x0020 to 0x4000 (20ms to 10240ms).adv_int_max        = 0x40,                 // 0x40*0.625ms=40ms.adv_type           = ADV_TYPE_NONCONN_IND, // 不可連接廣播// .adv_type           = ADV_TYPE_DIRECT_IND_HIGH,  // 設(shè)置為高占空比定向廣播// .peer_addr          = {0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6},  // 目標(biāo)設(shè)備MAC地址// .peer_addr_type     = BLE_ADDR_TYPE_PUBLIC,      // 目標(biāo)設(shè)備的地址類型.own_addr_type      = BLE_ADDR_TYPE_PUBLIC, // 公共地址.channel_map        = ADV_CHNL_ALL,         // 在 37,38,39 頻道廣播.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, // 允許任何設(shè)備掃描和連接
};
#endifstatic void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{esp_err_t err;ESP_LOGI(DEMO_TAG, "====> ESP_GAP_BLE_EVT %d <====", event);switch (event) {
#if (IBEACON_MODE == IBEACON_SENDER)case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: { // 原始廣播數(shù)據(jù)設(shè)置完成事件if ((err = param->adv_data_raw_cmpl.status) != ESP_BT_STATUS_SUCCESS) {ESP_LOGE(DEMO_TAG, "Set raw adv data failed: %s", esp_err_to_name(err));return;}esp_ble_gap_start_advertising(&ble_adv_params);break;}case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: { // 廣播啟動完成事件//adv start complete event to indicate adv start successfully or failedif ((err = param->adv_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {ESP_LOGE(DEMO_TAG, "Adv start failed: %s", esp_err_to_name(err));}break;}case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: { // 廣播停止完成事件if ((err = param->adv_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS){ESP_LOGE(DEMO_TAG, "Adv stop failed: %s", esp_err_to_name(err));}else {ESP_LOGI(DEMO_TAG, "Stop adv successfully");}break;}
#endif
#if (IBEACON_MODE == IBEACON_RECEIVER)case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { // 掃描參數(shù)設(shè)置完成事件//the unit of the duration is second, 0 means scan permanentlyuint32_t duration = 0;esp_ble_gap_start_scanning(duration);break;}case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: // 掃描啟動完成事件//scan start complete event to indicate scan start successfully or failedif ((err = param->scan_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {ESP_LOGE(DEMO_TAG, "Scan start failed: %s", esp_err_to_name(err));} else {is_scanning = true;}break;case ESP_GAP_BLE_SCAN_RESULT_EVT: { // 掃描結(jié)果準(zhǔn)備完畢事件if (is_scanning == false) { // 如果沒有在掃描,則不處理掃描結(jié)果ESP_LOGW(DEMO_TAG, "Scan is not started yet");break;}esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;switch (scan_result->scan_rst.search_evt) {case ESP_GAP_SEARCH_INQ_RES_EVT: {/* 搜索 BLE iBeacon 數(shù)據(jù)包 */if (esp_ble_is_ibeacon_packet(scan_result->scan_rst.ble_adv, scan_result->scan_rst.adv_data_len)) {esp_ble_ibeacon_t *ibeacon_data = (esp_ble_ibeacon_t*)(scan_result->scan_rst.ble_adv);ESP_LOGI(DEMO_TAG, "----------iBeacon Found----------");esp_log_buffer_hex("IBEACON_DEMO: Device address:", scan_result->scan_rst.bda, ESP_BD_ADDR_LEN );esp_log_buffer_hex("IBEACON_DEMO: Proximity UUID:", ibeacon_data->ibeacon_vendor.proximity_uuid, ESP_UUID_LEN_128);uint16_t major = ENDIAN_CHANGE_U16(ibeacon_data->ibeacon_vendor.major);uint16_t minor = ENDIAN_CHANGE_U16(ibeacon_data->ibeacon_vendor.minor);ESP_LOGI(DEMO_TAG, "Major: 0x%04x (%d)", major, major);ESP_LOGI(DEMO_TAG, "Minor: 0x%04x (%d)", minor, minor);ESP_LOGI(DEMO_TAG, "Measured power (RSSI at a 1m distance):%d dbm", ibeacon_data->ibeacon_vendor.measured_power);ESP_LOGI(DEMO_TAG, "RSSI of packet:%d dbm", scan_result->scan_rst.rssi);esp_err_t err = esp_ble_gap_stop_scanning();if (err != ESP_OK) {ESP_LOGE(DEMO_TAG, "Stop scaning failed: %s", esp_err_to_name(err));} else {is_scanning = false;ESP_LOGI(DEMO_TAG, "Stop scaning"); }}break;}default:break;}break;}case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: { // 掃描停止完成事件if ((err = param->scan_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS){ESP_LOGE(DEMO_TAG, "Scan stop failed: %s", esp_err_to_name(err));}else {ESP_LOGI(DEMO_TAG, "Stop scan successfully");}break;}
#endifdefault:break;}
}void ble_ibeacon_appRegister(void)
{esp_err_t status;ESP_LOGI(DEMO_TAG, "register callback");/* 注冊 GAP 回調(diào)函數(shù) */if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {ESP_LOGE(DEMO_TAG, "gap register error: %s", esp_err_to_name(status));return;}}void ble_ibeacon_init(void)
{/* 初始化藍(lán)牙 HOST 層 */esp_bluedroid_init();/* 使能藍(lán)牙 HOST 層 */esp_bluedroid_enable();/* 注冊 ibeacon */ble_ibeacon_appRegister();
}void app_main(void)
{/* 初始化 NVS */ESP_ERROR_CHECK(nvs_flash_init());/* 釋放經(jīng)典藍(lán)牙 Control 層內(nèi)存 */ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));/* 初始化 BLE Control 層 */esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();esp_bt_controller_init(&bt_cfg);/* 啟動 BLE Control 層 */esp_bt_controller_enable(ESP_BT_MODE_BLE);/* BLE Ibeacon 功能初始化 */ble_ibeacon_init();#if (IBEACON_MODE == IBEACON_RECEIVER)/* 設(shè)置掃描參數(shù) */esp_ble_gap_set_scan_params(&ble_scan_params);#elif (IBEACON_MODE == IBEACON_SENDER)esp_ble_ibeacon_t ibeacon_adv_data;/* 填充 ibeacon 數(shù)據(jù) */esp_err_t status = esp_ble_config_ibeacon_data (&vendor_config, &ibeacon_adv_data);if (status == ESP_OK) {for (int i = 0; i < sizeof(ibeacon_adv_data); i++) {ESP_LOGI(DEMO_TAG, "ibeacon_adv_data[%d] = 0x%x", i, *((uint8_t*)(&ibeacon_adv_data) + i));}/* 設(shè)置廣播原始數(shù)據(jù),此函數(shù)將會觸發(fā) ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT 事件 */esp_ble_gap_config_adv_data_raw((uint8_t*)&ibeacon_adv_data, sizeof(ibeacon_adv_data));}else {ESP_LOGE(DEMO_TAG, "Config iBeacon data failed: %s", esp_err_to_name(status));}
#endif
}

解析代碼流程

  1. 現(xiàn)在,我們開始捋一遍 ibeacon 工程代碼順序以方便我們后續(xù)理解。

NVS 分區(qū)

  1. 首先是 NVS 分區(qū)的初始化,他主要用于存儲一些 RF(射頻)校準(zhǔn)數(shù)據(jù),以確保無線通信的性能和穩(wěn)定性。
  2. 當(dāng) ESP32 第一次啟動并運行無線功能(如 Wi-Fi 或藍(lán)牙)時,它會進(jìn)行 RF 校準(zhǔn),以確定在當(dāng)前硬件和環(huán)境條件下的最佳射頻參數(shù)。
  3. 校準(zhǔn)過程的結(jié)果會被存儲在 NVS 中,這樣在后續(xù)啟動時,設(shè)備可以直接使用這些校準(zhǔn)數(shù)據(jù),避免每次啟動都需要重新校準(zhǔn)。從而提高設(shè)備運行效率。
    /* 初始化 NVS */ESP_ERROR_CHECK(nvs_flash_init());
  1. 為了更為方便的理解 NVS 分區(qū)在當(dāng)前的作用,我們可以進(jìn)行如下實驗。我們會發(fā)現(xiàn),只有第一次才會產(chǎn)生 RF 校驗數(shù)據(jù)失敗,而后就將不再出現(xiàn)該信息。
  2. 這是因為,在第一次芯片啟動時,芯片會去檢測 NVS 分區(qū)是否存在 RF 校驗數(shù)據(jù)。如果有,那么就馬上利用該數(shù)據(jù)進(jìn)行啟動射頻模塊。如果沒有,那么就先進(jìn)行 RF 校準(zhǔn),然后將校準(zhǔn)數(shù)據(jù)存儲在 NVS 分區(qū),方便后續(xù)芯片快速啟動。
# 將 Flash 全部擦除,該命令必須執(zhí)行,否則現(xiàn)象可能無法出現(xiàn)
idf.py erase-flash
# 重新燒錄程序
idf.py flash monitor
# 燒錄完成后,我們將能夠看到這樣的日志打印信息
# -------------
W (602) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration
W (642) phy_init: saving new calibration data because of checksum failure, mode(2)
# -------------
# 看到這條信息后,復(fù)位芯片,我們將看不到這條信息。
idf.py monitor

bluedroid 協(xié)議棧啟動

  1. 如下為 bluedroid 協(xié)議棧啟動代碼,為什么這樣編寫,我已經(jīng)在 ESP32 的 BLE 整體架構(gòu) 這篇博客講解,不再進(jìn)行贅述。
    /* 釋放經(jīng)典藍(lán)牙 Control 層內(nèi)存 */ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));/* 初始化 BLE Control 層 */esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();esp_bt_controller_init(&bt_cfg);/* 啟動 BLE Control 層 */esp_bt_controller_enable(ESP_BT_MODE_BLE);/* BLE Ibeacon 功能初始化 */ble_ibeacon_init();

esp_ble_gap_config_adv_data_raw() 設(shè)置廣播數(shù)據(jù)

  1. 在設(shè)置廣播數(shù)據(jù)之前,我們需要先知道 BLE 的廣播數(shù)據(jù)包格式是什么樣的。下面兩張圖即可展示出廣播包的數(shù)據(jù)格式,具體含義請閱讀 BTHome數(shù)據(jù)格式解析 的 BLE 廣播包格式 章節(jié),此處不做贅述。
    在這里插入圖片描述
    在這里插入圖片描述
  2. 了解了 BLE 廣播格式之后,現(xiàn)在我們要做的就是分析一下 ibeacon 的廣播包 AD Structure 應(yīng)該如何編寫。
  3. 首先,一個 BLE 廣播包必須存在 0x01 類型的廣播數(shù)據(jù),該廣播主要是用于指示當(dāng)前設(shè)備能進(jìn)行的一些行為。因為我們當(dāng)前是單模,因此需要置位 bit1 和 bit2,因此 AD Data 為 0x06。
bit描述
0有限可發(fā)現(xiàn)模式
1一般可發(fā)現(xiàn)模式
2不支持 BR/EDR ,當(dāng)前為單模設(shè)備
3設(shè)備同時支持 LE 和 BR/EDR 的 Control
4設(shè)備同時支持 LE 和 BR/EDR 的 HOST,需要注意,在Core Specification Supplement 10 該位被取消
5~7保留
  1. 通過上面分析,因此我們可以得到,第一個 flags 應(yīng)該填入的數(shù)據(jù)內(nèi)容如下:
esp_ble_ibeacon_head_t ibeacon_common_head = {.flags = {0x02, 0x01, 0x06},// ...
};
  1. 分析完 Flags 的數(shù)據(jù)包,我們再來看看最關(guān)鍵的 ibeacon 數(shù)據(jù)格式。
    在這里插入圖片描述
byte描述
0數(shù)據(jù)長度,固定為 0x1A
1AD Type,固定為 0xFF 表示廠商自定義數(shù)據(jù)
2~3固定為 0x004C ,此為 Apple 公司的標(biāo)識符??稍贏ssigned Numbers Document (PDF) 7 Company Identifiers 章節(jié)查閱
4固定為 0x02,這個是由 Apple 公司定義的數(shù)據(jù)類型
5ibeacon 數(shù)據(jù)長度,固定為 0x15
6~21用戶定義的 iBeacon UUID,用于唯一標(biāo)識應(yīng)用場景
22~23用戶自定義的主要值,用于分組或區(qū)域標(biāo)識
24~25用戶自定義的次要值,用于更精細(xì)的分組或區(qū)域標(biāo)識
26發(fā)射功率,可通過該值配合 RSSI 獲得當(dāng)前位置與廣播設(shè)備距離
  1. 通過上述分析,我們就可以將固定的報頭數(shù)據(jù)先設(shè)置好。
// 注意:BLE 廣播為小端存儲
esp_ble_ibeacon_head_t ibeacon_common_head = {.flags = {0x02, 0x01, 0x06},.length = 0x1A,         // iBeacon 數(shù)據(jù)長度為 26 bytes.type = 0xFF,           // 自定義數(shù)據(jù)類型.company_id = 0x004C,   // Apple 公司的標(biāo)識符.beacon_type = 0x1502   // 0x02 表示 iBeacon 類型,0x15 表示接下來的 ibeacon 數(shù)據(jù)長度為 21 bytes。
};
  1. 之后我們就可以設(shè)置自己想要廣播的數(shù)據(jù)了。
/* Vendor part of iBeacon data*/
esp_ble_ibeacon_vendor_t vendor_config = {.proximity_uuid = ESP_UUID,  // 16 字節(jié),用戶定義的 iBeacon UUID,用于唯一標(biāo)識應(yīng)用場景。.major = ENDIAN_CHANGE_U16(ESP_MAJOR), // 2 字節(jié),用戶自定義的主要值,用于分組或區(qū)域標(biāo)識。.minor = ENDIAN_CHANGE_U16(ESP_MINOR), // 2 字節(jié),用戶自定義的次要值,用于更精細(xì)的分組或區(qū)域標(biāo)識。.measured_power = 0xC5    // 發(fā)射功率為 -59 dBm
};
  1. 一切設(shè)置完成后,我們只需要調(diào)用 esp_ble_config_ibeacon_data() 函數(shù)將數(shù)據(jù)進(jìn)行填充即可。該函數(shù)其實就是對 Payload 段數(shù)據(jù)進(jìn)行了一下配置,看如下日志打印信息就可知道。如果感興趣,各位可以看一下該函數(shù)實現(xiàn),其實是非常簡單的。

注意: esp_ble_config_ibeacon_data() 并不是 ESP32 官方的庫函數(shù)!!!這個是編寫例程的人寫的自定義函數(shù)!!!

I (538) IBEACON_DEMO: ibeacon_adv_data[0] = 0x2
I (538) IBEACON_DEMO: ibeacon_adv_data[1] = 0x1
I (548) IBEACON_DEMO: ibeacon_adv_data[2] = 0x6
I (548) IBEACON_DEMO: ibeacon_adv_data[3] = 0x1a
I (558) IBEACON_DEMO: ibeacon_adv_data[4] = 0xff
I (558) IBEACON_DEMO: ibeacon_adv_data[5] = 0x4c
I (568) IBEACON_DEMO: ibeacon_adv_data[6] = 0x0
I (568) IBEACON_DEMO: ibeacon_adv_data[7] = 0x2
I (578) IBEACON_DEMO: ibeacon_adv_data[8] = 0x15
I (588) IBEACON_DEMO: ibeacon_adv_data[9] = 0xfd
I (588) IBEACON_DEMO: ibeacon_adv_data[10] = 0xa5
I (598) IBEACON_DEMO: ibeacon_adv_data[11] = 0x6
I (598) IBEACON_DEMO: ibeacon_adv_data[12] = 0x93
I (608) IBEACON_DEMO: ibeacon_adv_data[13] = 0xa4
I (608) IBEACON_DEMO: ibeacon_adv_data[14] = 0xe2
I (618) IBEACON_DEMO: ibeacon_adv_data[15] = 0x4f
I (618) IBEACON_DEMO: ibeacon_adv_data[16] = 0xb1
I (628) IBEACON_DEMO: ibeacon_adv_data[17] = 0xaf
I (628) IBEACON_DEMO: ibeacon_adv_data[18] = 0xcf
I (638) IBEACON_DEMO: ibeacon_adv_data[19] = 0xc6
I (638) IBEACON_DEMO: ibeacon_adv_data[20] = 0xeb
I (648) IBEACON_DEMO: ibeacon_adv_data[21] = 0x7
I (648) IBEACON_DEMO: ibeacon_adv_data[22] = 0x64
I (658) IBEACON_DEMO: ibeacon_adv_data[23] = 0x78
I (668) IBEACON_DEMO: ibeacon_adv_data[24] = 0x25
I (668) IBEACON_DEMO: ibeacon_adv_data[25] = 0x27
I (678) IBEACON_DEMO: ibeacon_adv_data[26] = 0xb7
I (678) IBEACON_DEMO: ibeacon_adv_data[27] = 0xf2
I (688) IBEACON_DEMO: ibeacon_adv_data[28] = 0x6
I (688) IBEACON_DEMO: ibeacon_adv_data[29] = 0xc5
  1. 配置好要廣播的數(shù)據(jù)后,直接調(diào)用庫函數(shù) esp_ble_gap_config_adv_data_raw() 即可。我們來看看 nrf Connect 結(jié)合上述打印信息,就會發(fā)現(xiàn)這個函數(shù)就是將你需要廣播的數(shù)據(jù)存入 Payload 段 。

在這里插入圖片描述

esp_ble_gap_start_advertising() 啟動廣播

  1. 在上面,我們調(diào)用 esp_ble_gap_config_adv_data_raw() 函數(shù)設(shè)置原始廣播數(shù)據(jù)完成之后,將會觸發(fā) ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT 事件。
  2. 我們可以在該事件中判斷原始廣播數(shù)據(jù)是否設(shè)置成功,如果設(shè)置成功,那么我們即可調(diào)用 esp_ble_gap_start_advertising() 函數(shù)啟動廣播。
  3. 在調(diào)用 esp_ble_gap_start_advertising() 函數(shù)時,需要傳入如下結(jié)構(gòu)體。
typedef struct {uint16_t                adv_int_min;        /*!< 最小的廣告間隔無向和低占空比定向廣告。取值范圍:0x0020 ~ 0x4000  默認(rèn)值:N = 0x0800(1.28秒)時間 = N * 0.625 ms 時間范圍: 20 ms to 10.24 s */uint16_t                adv_int_max;        /*!< 無向和低占空比定向廣告的最大廣告間隔。取值范圍:0x0020 ~ 0x4000  默認(rèn)值:N = 0x0800(1.28秒)時間 = N * 0.625 ms 時間范圍: 20 ms to 10.24 s */esp_ble_adv_type_t      adv_type;           /*!< 廣播類型 */esp_ble_addr_type_t     own_addr_type;      /*!< 所有者藍(lán)牙設(shè)備地址類型 */esp_bd_addr_t           peer_addr;          /*!< 對端設(shè)備藍(lán)牙設(shè)備地址 */esp_ble_addr_type_t     peer_addr_type;     /*!< 對端設(shè)備藍(lán)牙設(shè)備地址類型,僅支持公網(wǎng)地址類型和隨機(jī)地址類型 */esp_ble_adv_channel_t   channel_map;        /*!< 廣告頻道圖 */esp_ble_adv_filter_t    adv_filter_policy;  /*!< 廣告過濾策略 */
} esp_ble_adv_params_t;
  1. 如果是對 BLE HCI 比較熟悉的朋友就會發(fā)現(xiàn),這個函數(shù)其實就是讓 HOST 層向 Control 層發(fā)送 LE Set Advertising Parameters command 命令。
  2. 我們可以打開 Core 5.3 的 2353 頁,會發(fā)現(xiàn)這個命令傳入的參數(shù)和 esp_ble_gap_start_advertising() 函數(shù)傳入的參數(shù)一模一樣。

在這里插入圖片描述
12. 關(guān)于這個命令,規(guī)范書中的描述如下:

  1. HCI_LE_Set_Advertising_Parameters 命令用于設(shè)置廣播參數(shù)。
  2. advertissing_interval_min 小于或等于 Advertising_Interval_Max 。advertissing_interval_min 和 Advertising_Interval_Max 不應(yīng)該是相同的值,以使控制器能夠確定給定其他活動的最佳廣告間隔。
  3. 對于高占空比定向廣告,即當(dāng) Advertising_Type 為 0x01 (ADV_DIRECT_IND,高占空比)時,不使用 Advertising_Interval_Min 和 Advertising_Interval_Max 參數(shù),應(yīng)忽略。
  4. Advertising_Type 用于確定在啟用發(fā)布時用于發(fā)布的數(shù)據(jù)包類型。
  5. “Own_Address_Type” 參數(shù)表示發(fā)布報文使用的地址類型。
  6. 如果 Own_Address_Type 等于 0x02 或 0x03, Peer_Address 參數(shù)包含對端設(shè)備的身份地址,Peer_Address_Type 參數(shù)包含對端設(shè)備的身份類型(即0x00或0x01)。這些參數(shù)用于在解析表中定位相應(yīng)的本地 IRK;此 IRK 用于生成廣告中使用的自己的地址。
  7. 如果是定向廣播,即當(dāng) Advertising_Type 設(shè)置為 0x01 (ADV_DIRECT_IND,高占空比)或0x04 (ADV_DIRECT_IND,低占空比模式)時,則 Peer_Address_Type 和 Peer_Address 有效。
  8. 如果 Own_Address_Type 等于 0x02 或 0x03,Control 使用 Peer_Address 參數(shù)中包含的對端設(shè)備的身份地址和 Peer_Address_Type 參數(shù)中包含的對端設(shè)備的身份地址類型(即0x00或0x01)對應(yīng)的對端設(shè)備的 IRK 生成對端設(shè)備的可解析私有地址。
  9. Advertising_Channel_Map 是一個位字段,表示發(fā)送廣播報文時應(yīng)使用的廣告通道索引。在 Advertising_Channel_Map 參數(shù)中至少要設(shè)置一個通道位。
  10. 當(dāng)定向廣播被啟用時,Advertising_Filter_Policy 參數(shù)應(yīng)該被忽略。
  11. 如果 Control 啟用了廣播功能,則 HOST 不得發(fā)出該命令;如果啟用了廣播功能,則應(yīng)使用 "命令禁用 "錯誤代碼。
  12. 如果 HOST 提供的發(fā)布間隔范圍(Advertising_Interval_Min, Advertising_Interval_Max)超出了 Control 支持的發(fā)布間隔范圍,則 Control 將返回不支持的特征或參數(shù)值(0x11)錯誤碼。
adv_int_min 和 adv_int_max
  1. adv_int_minadv_int_max 用于指示廣播的時間間隔。bluedroid 協(xié)議棧會選取該范圍內(nèi)的任意值作為廣播間隔,但是實測后發(fā)現(xiàn),他一般選取 adv_int_max 作為廣播間隔

  2. adv_int_minadv_int_max 范圍都要求在 0x0020 ~ 0x4000 之間,如果沒有設(shè)置該值,默認(rèn)為 0x0800 (1.28 s) 。時間計算公式為 Time = N * 0.625 ms,既最終的廣播時間范圍為 20 ms to 10.24 s。
    在這里插入圖片描述

  3. 此時有人可能會有疑問了,我代碼里面命令設(shè)置的最大廣播間隔時間為 40ms 啊,怎么抓包數(shù)據(jù)有些廣播間隔為 48ms 多呢?

  4. 這個就需要涉及到 SIG 規(guī)定的廣播間隔內(nèi)容了。SIG 規(guī)定,為了解決多個設(shè)備同時廣播時的沖突問題,從而避免廣播包的碰撞,確保更加可靠的廣播和接收,在 BLE 廣播過程中,存在一個 隨機(jī)延遲(random delay),通常稱為 廣播延遲(advertising delay)。

static esp_ble_adv_params_t ble_adv_params = {.adv_int_min        = 0x20,                 // 0x20*0.625ms=20ms,Range: 0x0020 to 0x4000 (20ms to 10240ms).adv_int_max        = 0x40,                 // 0x40*0.625ms=40ms// ...
};

在這里插入圖片描述

  1. 如果我們希望一個確切的廣播間隔,那么就可以讓adv_int_minadv_int_max 相等即可。

注: adv_int_minadv_int_max 相等只是讓 advInterval 為我們設(shè)定的固定值,advDelay 依舊會存在!而且 SIG 不建議讓 adv_int_minadv_int_max 相等!

  1. adv_int_max 必須大于 adv_int_min ,否則就會出現(xiàn)如下報錯。(部分日志信息是本例程用于調(diào)試寫的)
I (658) IBEACON_DEMO: ====> ESP_GAP_BLE_EVT 4 <====
E (668) BT_APPL: bta_dm_ble_set_adv_params_all(), fail to set ble adv params.
E (678) BT_HCI: hci write adv params error 0x12
I (678) IBEACON_DEMO: ====> ESP_GAP_BLE_EVT 6 <====
E (688) IBEACON_DEMO: Adv start failed: ERROR
adv_type
  1. 該參數(shù)用于設(shè)置 BLE 的廣播類型。
typedef enum {ADV_TYPE_IND                = 0x00, // 可連接和可掃描的無定向廣告(ADV_IND)(默認(rèn))ADV_TYPE_DIRECT_IND_HIGH    = 0x01, // 可連接的高占空比定向廣告(ADV_DIRECT_IND,高占空比)ADV_TYPE_SCAN_IND           = 0x02, // 可掃描的非定向廣告(ADV_SCAN_IND)ADV_TYPE_NONCONN_IND        = 0x03, // 不可連接非定向廣告(ADV_NONCONN_IND)ADV_TYPE_DIRECT_IND_LOW     = 0x04, // 可連接低占空比定向廣告(ADV_DIRECT_IND,低占空比)
} esp_ble_adv_type_t;
  1. 如果是學(xué)習(xí) 《低功耗權(quán)威指南》或者其他類型的熟記中會發(fā)現(xiàn),廣播類型只有四種:通用廣播定向廣播不可連接廣播可發(fā)現(xiàn)廣播。這個時候有人肯定會疑問,為什么這里的定向廣播有兩種。
  2. 這個就設(shè)計到版本更替的問題了,《低功耗權(quán)威指南》是用于講解 BLE 4.0 的權(quán)威書籍,但是 ESP32 的 Bluedroid 是支持 BLE 5.0 的。從 BLE 5.0 開始,廣播擁有第五種類型,即可連接低占空比定向廣告。
  3. 現(xiàn)在我就開始分別介紹一下這幾種廣播的區(qū)別:
廣播類型描述關(guān)閉方式
ADV_TYPE_IND這種廣播是最常用的廣播方式。進(jìn)行通用廣播的設(shè)備是能夠被掃描,被連接的。調(diào)用 esp_ble_gap_stop_advertising() 函數(shù)主動關(guān)閉廣播,或者連接建立。
ADV_TYPE_DIRECT_IND_HIGH該廣播類型主要針對希望快速建立連接的需求開啟定向廣播后,完整的廣播事件必須每 3.75ms 重復(fù)一次,正因如此之快的廣播速率,導(dǎo)致該廣播包將在占滿整個廣播信道,進(jìn)而導(dǎo)致該區(qū)域內(nèi)其他設(shè)備無法進(jìn)行廣播,因此定向廣播不可以持續(xù)超過 1.28s 之上。該廣播只有兩種結(jié)束方式,第一種是收到指定的對端設(shè)備連接請求,第二種是超過 1.28s。一旦超過 1.28s 還沒有建立連接,Control 層應(yīng)該向 HOST 層發(fā)送 Advertising Timeout 事件,告知廣播超時。(這里需要注意,ESP32 的該廣播事件似乎有 bug,并不會上報廣播超時事件)
ADV_TYPE_SCAN_IND該類型廣播不可以用于發(fā)起連接,但允許其他設(shè)備進(jìn)行掃描,可以理解為將連接功能去除的 ADV_TYPE_IND調(diào)用 esp_ble_gap_stop_advertising() 函數(shù)主動關(guān)閉廣播。
ADV_TYPE_NONCONN_IND該類型廣播針對的是不想被連接,僅進(jìn)行廣播的設(shè)備,例如本文的 Ibeacon 設(shè)備。這也是唯一可用于只有發(fā)射機(jī)而沒有接收機(jī)設(shè)備的廣播類型。調(diào)用 esp_ble_gap_stop_advertising() 函數(shù)主動關(guān)閉廣播。
ADV_TYPE_DIRECT_IND_LOW該廣播屬于定向廣播,但是并不會像 ADV_TYPE_DIRECT_IND_HIGH 那樣快速的將整個廣播信道占滿,他是會在 adv_int_minadv_int_max 范圍內(nèi)保持一定的頻率進(jìn)行廣播。調(diào)用 esp_ble_gap_stop_advertising() 函數(shù)主動關(guān)閉廣播,或者和指定的對端設(shè)備連接建立。
own_addr_type
  1. 這里設(shè)置設(shè)備的地址類型,沒有特殊需求,直接設(shè)置為公共地址即可。
typedef enum {BLE_ADDR_TYPE_PUBLIC        = 0x00,     /*!< 公共地址 */BLE_ADDR_TYPE_RANDOM        = 0x01,     /*!< 隨機(jī)設(shè)備地址。要設(shè)置此地址,請使用esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr)函數(shù) */BLE_ADDR_TYPE_RPA_PUBLIC    = 0x02,     /*!< 具有公共身份地址的可解析私有地址(RPA) */BLE_ADDR_TYPE_RPA_RANDOM    = 0x03,     /*!< 帶有隨機(jī)身份地址的可解析私有地址(RPA)。要設(shè)置此地址,請使用esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr)函數(shù) */
} esp_ble_addr_type_t;

在這里插入圖片描述

設(shè)備地址類型描述
公共地址(BLE_ADDR_TYPE_PUBLIC)全球唯一且固定的地址,需要向 IEEE 組織購買。因為全球唯一,因此容易被跟蹤
靜態(tài)地址(BLE_ADDR_TYPE_RANDOM)自己定義,上電初始化完成后不能再進(jìn)行修改。每次芯片啟動都可能會更換地址
可解析地址(BLE_ADDR_TYPE_RPA_PUBLIC)通訊雙方共享 IRK ,生成隨機(jī)可解析私有地址。只有擁有廣播者的 IRK 時,才能跟蹤其廣播活動。目的是為了防止惡意第三方跟蹤藍(lán)牙設(shè)備。
不可解析地址(BLE_ADDR_TYPE_RPA_RANDOM)定期更新地址,SIG 推薦15 min 更新一次,更新時間間隔不要超過 1 小時。通常用于設(shè)備只需要一次性廣播數(shù)據(jù),且不需要被接收方識別或跟蹤。例如,發(fā)送傳感器數(shù)據(jù)的設(shè)備、匿名設(shè)備發(fā)現(xiàn)、或僅廣播某些臨時數(shù)據(jù)的場景。
peer_addr
  1. 對端設(shè)備 MAC 地址。只有當(dāng) adv_typeADV_TYPE_DIRECT_IND_HIGH 或者 ADV_TYPE_DIRECT_IND_LOW 才有效。
peer_addr_type
  1. 對端設(shè)備地址類型。只有當(dāng) adv_typeADV_TYPE_DIRECT_IND_HIGH 或者 ADV_TYPE_DIRECT_IND_LOW 才有效。
channel_map
  1. 廣播的信道。你可以設(shè)置在指定的廣播信道進(jìn)行廣播,或者是所有廣播信道都廣播。
typedef enum {ADV_CHNL_37     = 0x01,  // 僅在 37 信道廣播ADV_CHNL_38     = 0x02,  // 僅在 38 信道廣播ADV_CHNL_39     = 0x04,  // 僅在 39 信道廣播ADV_CHNL_ALL    = 0x07,  // 在 37,38,39 信道廣播
} esp_ble_adv_channel_t;
adv_filter_policy
  1. 因為我們是 Ibeacon 所有需要讓所有人能夠掃描到,因此設(shè)置為 ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY 。
  2. 白名單是指的特定的對端設(shè)備地址,我們可以調(diào)用 esp_ble_gap_update_whitelist() 函數(shù)更新白名單。

如果開發(fā)過 Nordic 的相關(guān)芯片,會發(fā)現(xiàn)一個問題,怎么 Nordic 的芯片還可以過濾 UUID,名稱,外觀等信息呢?這個就是 Nordic 的協(xié)議棧中軟件實現(xiàn)的,和 SIG 相關(guān)規(guī)定無關(guān),如果你希望有這樣的功能,可以自行實現(xiàn)。

typedef enum {// 允許任何人的掃描和連接請求ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY  = 0x00,// 只允許來自白名單設(shè)備的掃描請求和來自任何人的連接請求ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY,// 只允許任何人的掃描請求和來自白名單設(shè)備的連接請求ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST,// 只允許來自白名單設(shè)備的掃描和連接請求ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST,
} esp_ble_adv_filter_t;

廣播啟動完成

  1. 當(dāng)調(diào)用 esp_ble_gap_start_advertising() 函數(shù)之后,將會觸發(fā) ESP_GAP_BLE_ADV_START_COMPLETE_EVT 事件。在該事件中,我們可以知道廣播是否完成。
  2. 當(dāng)廣播結(jié)束之后,將會觸發(fā) ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT 事件,不過當(dāng)前的 Ibeacon 例程中,不會停止廣播,因此該事件不會觸發(fā)。

參考

  1. Apple Ibeacon 官方介紹
  2. 低功耗藍(lán)牙開發(fā)者手冊
  3. BTHome數(shù)據(jù)格式解析
  4. nRF52832藍(lán)牙iBeacon廣播
  5. 谷雨文檔中心:BLE技術(shù)揭秘
  6. Core 5.3
http://www.risenshineclean.com/news/51351.html

相關(guān)文章:

  • 煙臺網(wǎng)站排名優(yōu)化公司網(wǎng)絡(luò)營銷案例分析
  • 找人做網(wǎng)站一般要多少錢免費檢測網(wǎng)站seo
  • 普通網(wǎng)站可以做商城求幾個微信推廣平臺
  • 男女怎么做那個視頻網(wǎng)站搜索引擎優(yōu)化與關(guān)鍵詞的關(guān)系
  • 個人網(wǎng)站首頁怎么做合肥推廣外包公司
  • 最牛視頻網(wǎng)站建設(shè)常州網(wǎng)絡(luò)推廣seo
  • wordpress 分類 如何修改seo搜索引擎優(yōu)化名詞解釋
  • 民宿網(wǎng)站開發(fā)方案網(wǎng)絡(luò)營銷的推廣方式
  • 建設(shè)銀行網(wǎng)上流覽網(wǎng)站做網(wǎng)站的軟件有哪些
  • 專門做學(xué)校政府的網(wǎng)站今天宣布疫情最新消息
  • 關(guān)于網(wǎng)站建設(shè)案例抖音關(guān)鍵詞推廣
  • 美食網(wǎng)站頁面設(shè)計源代碼網(wǎng)絡(luò)游戲推廣怎么做
  • 建站模板 discuz網(wǎng)絡(luò)推廣預(yù)算方案
  • 正規(guī)網(wǎng)站建設(shè)定制網(wǎng)站seo入門基礎(chǔ)教程
  • 昆明大型網(wǎng)站建設(shè)東莞網(wǎng)絡(luò)推廣及優(yōu)化
  • 網(wǎng)站設(shè)計風(fēng)格有哪幾種網(wǎng)站服務(wù)器查詢工具
  • 推廣之家邀請碼江西短視頻seo搜索報價
  • 唐山網(wǎng)站建設(shè)拓seo知識總結(jié)
  • 如何學(xué)做網(wǎng)頁做優(yōu)化的網(wǎng)站
  • 網(wǎng)站制作公司哪家專業(yè)免費私人網(wǎng)站建設(shè)平臺
  • 網(wǎng)站沒有備案seo怎么優(yōu)化武漢廠商
  • 企業(yè)做網(wǎng)站的公司有哪些游戲推廣員平臺
  • 嵐山網(wǎng)站建設(shè)公司南昌seo公司
  • 廣州正規(guī)網(wǎng)站建設(shè)公司產(chǎn)品市場營銷策劃書
  • 做美圖+網(wǎng)站有哪些可以免費做網(wǎng)站推廣的平臺
  • 個人風(fēng)采網(wǎng)站制作在線查網(wǎng)站的ip地址
  • django做的網(wǎng)站安全嗎seo 專業(yè)
  • 上饒網(wǎng)站開發(fā)2021百度熱搜年度榜
  • dede網(wǎng)站主頁打不開百度域名注冊
  • 政府部門網(wǎng)站建設(shè)意義小網(wǎng)站