前言

  1. 前面我们已经了解了 ESP32 的 BLE 整体架构,现在我们开始实际学习一下Bluedroid 从机篇的广播和扫描。
  2. 本文将会以  ble_ibeacon demo 为例子进行讲解,需要注意的一点是。ibeacon 分为两个部分,一个是作为广播者,一个是作为观察者IBEACON_RECEIVER 这个宏表示作为观察者IBEACON_SENDER 这个宏被置 1 表示为广播者
  3. 需要注意的一点是,本文先仅介绍广播相关内容

ibeacon 介绍

ibeacon 是什么?

  1. 作为一名初学者,当听到 ibeacon 时候,大概率是一脸懵逼的。即使网上搜索大量资料,没有亲身体验,也是一头雾水。为了方便各位理解,就以我来上海实习,周末逛的第一个景点 – 豫园 为例子进行分析。
  2. 当我们进入景点,肯定会有一个二维码建议我们扫描,然后之后就会有电子讲解功能。例如我现在扫描了豫园的二维码,打开了一个微信小程序,此时微信小程序上就能够显示出我的位置在哪里。

ESP32 Bluedroid 篇(1)—— ibeacon 广播_#include

3. 如果你移动到一个地方,该小程序就会进行相关讲解当前景点的一些历史文化信息。此时,各位有没有想过一个问题,该小程序,是如何精确的知道我们当前是在哪个景点呢?

4. 此时,就是利用的 ibeacon 技术进行的。如果你有兴趣的话,可以在走到某个景点,发现微信小程序播报讲解时刻停下来,然后在这个附近十米内的范围转转,会惊奇的发现,一些地方藏有这种小方块。

ESP32 Bluedroid 篇(1)—— ibeacon 广播_GAP_02

ESP32 Bluedroid 篇(1)—— ibeacon 广播_单片机_03

5. 这个小方块,就是本文要进行讲解的,ESP32 作为广播者的功能。而你手机,就是充当的观察者

ibeacon 有什么用?

  1. 现在我们明白了 ibeacon 技术大概是什么东西了。那么这个有什么作用呢?从上面的例子我们就可以很好的知道,室内定位广播信息
  2. 当前,室内定位技术一直是一项值得探索的技术,ibeacon 可以说提供了一个不错的选择(不过个人感觉目前 BLE 室内定位更多的是聚焦于 AOA)。
  3. 同样,在商场,我们只需要打开微信小程序走到哪家店铺,就可以直接查看那家店铺的商品信息,这样一定程度上可以方便用户挑选商品。

ibeacon 工程介绍

工程源码

  1. 我们先拷贝  ble_ibeacon demo 例程出来,打开ibeacon_demo.c 文件,将其替换为如下内容。
/*
 * 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)
// 在停止扫描请求发送后,蓝牙堆栈可能还会处理一些尚未完成的扫描结果。因此需要通过这个标志位来设置是否需要继续处理扫描完成事件
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, // 允许扫描所有设备
    .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,  // 设置为高占空比定向广播
    // .peer_addr          = {0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6},  // 目标设备MAC地址
    // .peer_addr_type     = BLE_ADDR_TYPE_PUBLIC,      // 目标设备的地址类型

    .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, // 允许任何设备扫描和连接
};
#endif


static 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: { // 原始广播数据设置完成事件
        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 failed
        if ((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: { // 扫描参数设置完成事件
        //the unit of the duration is second, 0 means scan permanently
        uint32_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 failed
        if ((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: { // 扫描结果准备完毕事件
        if (is_scanning == false) { // 如果没有在扫描,则不处理扫描结果
            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 数据包 */
            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("