ESP32S3蓝牙学习系列---Beacon信标之Eddystone

news/2024/10/19 19:42:10/

Beacon技术和Eddystone

Beacon是一种基于BLE的技术,以固定间隔广播发送固定格式的数据。信号强弱以RSSI相对强度来表示,遇到障碍物信号会很弱。
Beacon信标本质是一种蓝牙广播标准,该标准不是蓝牙技术联盟所制定的标准,它被称为“虚拟标准”,是由大型供应商或企业集团为首,针对广泛的Beacon应用所正式提出的蓝牙应用规范。
由苹果公司封装形成的标准是iBeacon,而Eddystone谷歌公司制定的标准。Eddystone相对于iBeacon功能更为广泛,可以广播自定义唯一的信标ID(UID)、广播网址(URL)、广播自身数据(TLM/ETLM)、加密的临时标识符(EID)。

BLE广播包格式

广播包

如下图所示为广播包的格式,它最终会被封装在LL层packet中的PDU中
在这里插入图片描述

  • 前导
    前导是一个8bit的交替序列,根据接入地址的第一个bit为0或者1,分为01010101和10101010两种,接收机可以根据前导的无线信号强度来配置自动增益控制。

  • 接入地址
    接入地址有两种类型:广播接入地址和数据接入地址。

    • 广播接入地址:固定为0x8E89BED6,在广播、扫描、发起连接时使用
    • 数据接入地址:随机值,不同的连接有不同的值,在连接建立后两个设备间使用。
  • 报头
    广播报文报头格式如下:
    在这里插入图片描述

    • 报文类型(PDU Type)
      在这里插入图片描述

    • 发送地址类型(TxAdd):如果广播设备的地址是随机的,该位置1,如果是公共的,该位置0。

    • 接收地址类型(RxAdd):如果目标设备的地址是随机的,该位置1,如果是公共的,该位置0。

  • 长度
    广播报文:长度域包含6个bit,有效范围是6~37。
    数据报文:长度域包含5bit,有效值范围是0~31。
    广播报文和数据报文的长度域有所不同,主要原因是:广播报文除了最多31byte的数据外,还必须要包含6byte的广播设备地址,所以需要6bit的长度域。

  • 数据
    广播报文中的数据格式如下:
    在这里插入图片描述

    • 有效载荷(PDU Payload)
      广播和扫描响应的数据格式如下图所示,由有效数据部分和无效数据部分组成:
      在这里插入图片描述
      有效数据部分包含N个AD Structure,每个AD Structure由Length,AD Type和AD Data组成,其中:length包含AD Type和AD Data的长度,AD Type指示AD Data数据的含义。

Eddystone数据结构

数据包格式如下:
在这里插入图片描述

  • UID
    这是由三个字段组成的主要Eddystone框架,即命名空间标识符(10byte),实例标识符(6byte)和功率校准(1byte)。他将有助于将字段直接配置到BLE信标中,实例标识符旨在唯一地表示一个信标,因为他们具有不同的实例ID,功率校准字段用于根据RSSI帮助计算移动设备和Eddystone信标之间的距离。
  • URL
    该框架的主要目的是提供一种传输URL的方法,以便蓝牙低功耗扫描仪设备检测和发现它,然后BLE设备将连接收到并为用户显示正确的网页。BLE信标发送Eddystone-URL资源,智能手机等移动设备在检测到信标数据后立即在浏览器中自动打开网址。同时该框架提供类似于Eddystone-UID的功率校准功能。
  • TLM
    Eddystone-TML 框架的主要是提供关于Eddystone的健康状况的完整报告。当前温度, 当前电池电量, 正常运行时间 (信标已通电的秒数), 和 PduCount (信标在最后一次供电后部署的广告数据包的数量).
  • EID
    这是负责小工具安全和隐私的框架。

代码验证

本例程再用ESP32S3芯片,ESP-IDF-V5.0版本做功能验证。两块ESP32S3电路板,一个作为发送方,一个作为接收方。接收方直接使用esp-idf-v5.0\examples\bluetooth\bluedroid\ble\ble_eddystone的例程,编译后直接烧录到板子中,发送方要在esp-idf-v5.0\examples\bluetooth\bluedroid\ble\ble_eddystone例程中做一些修改,让我们可以将Eddystone广播数据发送出去。

  • 配置uuid,广播参数,广播数据
static uint8_t adv_service_uuid128[16] = {/* LSB <--------------------------------------------------------------------------------> MSB *///first uuid, 16bit, [12],[13] is the value,注意该值要改为Google的UUID,即0xFEAA 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAA, 0xFE, 0x00, 0x00,
};
//配置广播数据
static esp_ble_adv_data_t adv_data = {.set_scan_rsp = false,.include_name = false,.include_txpower = false,.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec.max_interval = 0x000C, //slave connection max interval, Time = max_interval * 1.25 msec.appearance = 0x00,.manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,.p_manufacturer_data = NULL, 		//&test_manufacturer[0],.service_data_len = 0,.p_service_data = NULL,.service_uuid_len = 16,.p_service_uuid = adv_service_uuid128,.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};//配置广播参数
static esp_ble_adv_params_t adv_params = {.adv_int_min        = 0x20,.adv_int_max        = 0x40,.adv_type           = ADV_TYPE_IND,.own_addr_type      = BLE_ADDR_TYPE_PUBLIC,//.peer_addr            =//.peer_addr_type       =.channel_map        = ADV_CHNL_ALL,.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
  • 封装Eddystone服务数据

//封装一个发送eddystone-UID服务的函数
int eddystone_set_uid(esp_eddystone_frame_t *uid, char power, uint8_t *name_space, uint8_t *instance)
{if(uid == NULL || name_space == NULL || instance == NULL){return -1;}memset(uid, 0, sizeof(esp_eddystone_frame_t));uid->len = sizeof(esp_eddystone_frame_t);uid->type = 0x16;uid->uuid = EDDYSTONE_SERVICE_UUID;uid->frame_type = EDDYSTONE_FRAME_TYPE_UID;//注意SDK中esp_eddystone_frame_t中的定义u[0]改成uuid->u.uid.ranging_data = power;	memcpy(uid->u.uid.namespace_id, name_space, 10);memcpy(uid->u.uid.instance_id, instance, 6);return uid->len;
}
  • 在主函数中配置广播数据
void app_main(void)
{ESP_ERROR_CHECK(nvs_flash_init());ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();esp_bt_controller_init(&bt_cfg);esp_bt_controller_enable(ESP_BT_MODE_BLE);esp_eddystone_init();/*<! set scan parameters *///esp_ble_gap_set_scan_params(&ble_scan_params);esp_eddystone_frame_t eddystone_frame;adv_data.manufacturer_len = eddystone_set_uid(&eddystone_frame, 0, (uint8_t *)"helloworld", (uint8_t *)"654321");adv_data.p_manufacturer_data = (uint8_t *)&eddystone_frame;esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);if (ret){ESP_LOGE(DEMO_TAG, "config adv data failed, error code = %x", ret);}	
}
  • 在应用层的回调函数中添加数据处理
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param)
{esp_err_t err;switch(event){case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {uint32_t duration = 0;esp_ble_gap_start_scanning(duration);break;}case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: {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 {ESP_LOGI(DEMO_TAG,"Start scanning...");}break;}case ESP_GAP_BLE_SCAN_RESULT_EVT: {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: {esp_eddystone_result_t eddystone_res;memset(&eddystone_res, 0, sizeof(eddystone_res));esp_err_t ret = esp_eddystone_decode(scan_result->scan_rst.ble_adv, scan_result->scan_rst.adv_data_len, &eddystone_res);if (ret) {// error:The received data is not an eddystone frame packet or a correct eddystone frame packet.// just returnreturn;} else {// The received adv data is a correct eddystone frame packet.// Here, we get the eddystone infomation in eddystone_res, we can use the data in res to do other things.// For example, just print them:ESP_LOGI(DEMO_TAG, "--------Eddystone Found----------");esp_log_buffer_hex("EDDYSTONE_DEMO: Device address:", scan_result->scan_rst.bda, ESP_BD_ADDR_LEN);ESP_LOGI(DEMO_TAG, "RSSI of packet:%d dbm", scan_result->scan_rst.rssi);esp_eddystone_show_inform(&eddystone_res);}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;}//广播数据设置完成后开始广播数据case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:	{ESP_LOGI(DEMO_TAG,"start advertising .........");esp_ble_gap_start_advertising(&adv_params);break;}default:break;}
}
  • 最终执行效果
    在这里插入图片描述

http://www.ppmy.cn/news/345211.html

相关文章

合宙ESP32C3上手使用

概述 经典款是有ch343 ttl 转usb 需要安装驱动 GPIO20/21 新款使用usb 直连不需要驱动 USB GPIO18/19 ESP32C3 是ESP-RISC-V CPU 是基于 RISC-V ISA 的 32 位内核&#xff0c;包括基本整数 (I)&#xff0c;乘法/除法 (M) 和压缩 (C) 标准扩展。ESP-RISC-V CPU 内核具有 4 级有序…

基于M5StickC Plus的可定时电子沙漏电子沙漏(LCD+软SPI+Arduino/C++)

目录 项目介绍硬件介绍开发环境搭建硬件结构及说明软件结构及说明软SPI驱动类LED矩阵操作类矩阵沙的动态效果计算电子沙漏顶层类硬件定时器&#xff08;及中断服务&#xff09;与非阻塞延时函数硬件定时器非阻塞延时 LED矩阵刷新间隔外设初始化主循环按键扫描主循环的主循环 功…

【esp32-s3】7.1 I2S——录音及存储

文章目录 1 前言2 硬件3 代码4 结果 1 前言 本章介绍下使用mic录制音频存放到tf卡中。 使用的是官方示例&#xff1a;https://gitee.com/EspressifSystems/esp-idf/tree/master/examples/peripherals/i2s/i2s_audio_recorder_sdcard 2 硬件 主要两块&#xff0c;tf卡的spi接线…

乐鑫esp32-c2开发板 烧录演示

一、准备工作 数据线X 1 、 四博智联 ESPC2-12 开发板 X 1 二、环境搭建 1、进入https://code.visualstudio.com 官网下载VSCODE软件 2、安装完成后安装乐鑫插件如下图 3、插件安装完后&#xff0c;查看- 命令面板&#xff08;快捷键CtrlShiftP&#xff09;。 4、输入config…

[论文笔记] Atos: A Task-Parallel GPU Scheduler for Graph Analytics

Atos: A Task-Parallel GPU Scheduler for Graph Analytics Atos: 用于图分析的任务并行 GPU 调度程序 [Paper] [Slides] ICPP’22 摘要 提出了 Atos, 一个特别针对动态不规则应用的任务并行 GPU 动态调度框架. 支持消除依赖关系的应用的任务并行公式来暴露额外的并发性除了…

led显示屏是如何扫描驱动的

LED显示屏的扫描驱动是指将图像信号分解并按行或按列逐行/逐列地驱动LED点阵&#xff0c;以显示完整的图像。以下是LED显示屏常见的两种扫描驱动方式&#xff1a; 静态扫描驱动&#xff1a; 静态扫描驱动是最简单和最常见的驱动方式。在静态扫描驱动中&#xff0c;每个LED像素都…

js的一些工具函数以及方法

部分方法复制于&#xff1a;20 个 JS 工具函数助力高效开发 reduce 举例&#xff1a;数组求和 let a[1,3,6,5,7]; let init0;//累加的初始值&#xff0c;默认为0&#xff0c;可不写 let ba.reduce((pre,cur,index,arr)>{console.log(当前要加序号&#xff1a;,index);cons…

高能预警!融云WICC发布《社交泛娱乐出海作战地图》

最近圈子里风很大的《社交泛娱乐出海作战地图》, 必须说&#xff0c;真的有亿点点厉害&#xff01;这简直是一张集社交泛娱乐市场、品类知识和出海实战指南于一体的教材级地图&#xff0c;实感入手不亏。关注【融云全球互联网通信云】了解更多 首先&#xff0c;容我先秀一把实…