Zephyr NRF7002 实现AppleJuice
BLE的基础知识
ble的信道和BR/EDR的信道是完全不一样的。但是范围是相同的,差不多也都是2.4Ghz的频道。可以简单理解为空中有40个信道0~39信道。两个设备在相同的信道里面可以进行相互通信。
而这些信道SIG又重新编号:
这个编号就是把37 38 39。 3个信道抽出来,作为广播信道,其他都是数据信道。这篇文章主要讲广播,所以基本数据信息都是围绕37 38 39这三个信道上面的通信来讲的。
我们可以看到这3个信道是分散排列的。大家可以思考下为什么。
其实看下面一张图就知道了。
数据广播
广播组成部分
广播分为如下几个部分:
- 广播
- 扫描请求
- 扫描响应
广播的报文格式
{"AD1":{"Length":12,"Data":{"AD_Type":12,"AD_Data":"123123"}},"AD2":{"Length":12,"Data":{"AD_Type":12,"AD_Data":"123123"}}
}
记忆要点
:每个元素里面有两个要素:1. 长度(length), 2. 数据(data)
每个数据里面又包含两个元素:1. 类型(type), 2. 数据(data)
总结一下就是一个L T V模型(length, type, data)
这个length代表的是后面数据有多长,不包含length的长度。
总的Len一般不超过31字节
参考:
2. BLE 广播和扫描 — bluetoothlover_wiki 0.0.1 文档 (supperthomas-wiki.readthedocs.io)
AD_Type 官方定义
抓包参考:
APPLE JUICE功能实现
1.流程梳理
主要需要实现如下功能点:
- ble 广播开启和关闭
- ble GAP层各种参数的设置
- ble MAC地址动态修改
2.Zephyr 中相关接口:
功能接口:
接口名 | 功能描述 | 备注 |
---|---|---|
bt_enable | 开启BLE功能 | |
bt_le_adv_start | 开启BLE广播 | |
bt_le_adv_update_data | 更新BLE广播内容 | 此接口是否实时?未找到对应生效CallBack |
bt_le_adv_stop | 关闭BLE广播 | |
bt_id_create | 更新广播随机地址 |
注:
上述接口在执行完成后均会抛出回调:
/*
参数回调注册
*/
void bt_conn_cb_register(struct bt_conn_cb *cb);struct bt_conn_cb {//已建立新连接void (*connected)(struct bt_conn *conn, uint8_t err);//连接已断开void (*disconnected)(struct bt_conn *conn, uint8_t reason);//LE 连接参数更新请求bool (*le_param_req)(struct bt_conn *conn,struct bt_le_conn_param *param);//LE 连接的参数已更新void (*le_param_updated)(struct bt_conn *conn, uint16_t interval,uint16_t latency, uint16_t timeout);
#if defined(CONFIG_BT_SMP)//远程身份地址通过void (*identity_resolved)(struct bt_conn *conn,const bt_addr_le_t *rpa,const bt_addr_le_t *identity);
#endif /* CONFIG_BT_SMP */
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)//连接的安全级别已更改void (*security_changed)(struct bt_conn *conn, bt_security_t level,enum bt_security_err err);
#endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */#if defined(CONFIG_BT_REMOTE_INFO)//远程信息程序已完成void (*remote_info_available)(struct bt_conn *conn,struct bt_conn_remote_info *remote_info);
#endif /* defined(CONFIG_BT_REMOTE_INFO) */#if defined(CONFIG_BT_USER_PHY_UPDATE)//连接的 PHY 已更改void (*le_phy_updated)(struct bt_conn *conn,struct bt_conn_le_phy_info *param);
#endif /* defined(CONFIG_BT_USER_PHY_UPDATE) */#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)//连接的数据长度参数已更改void (*le_data_len_updated)(struct bt_conn *conn,struct bt_conn_le_data_len_info *info);
#endif /* defined(CONFIG_BT_USER_DATA_LEN_UPDATE) */#if defined(CONFIG_BT_DF_CONNECTION_CTE_RX)void (*cte_report_cb)(struct bt_conn *conn,const struct bt_df_conn_iq_samples_report *iq_report);
#endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL)void (*tx_power_report)(struct bt_conn *conn,const struct bt_conn_le_tx_power_report *report);
#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */struct bt_conn_cb *_next;
};
bt_data接口
Zephyr 封装好了部分gap填充接口,在编写广播数据(bt_data)数组的时候可以通过以下宏来辅助:
/*** @brief Construct a new bt data object* * _type: GAP字段的类型* _data: GAP RAW 数据* _data_len: RAW数据长度*/
#define BT_DATA(_type, _data, _data_len) \{ \.type = (_type), \.data_len = (_data_len), \.data = (const uint8_t *)(_data), \}/*** @brief Construct a new bt data object* * _type: GAP字段的类型* _bytes: GAP RAW 数据*/
#define BT_DATA_BYTES(_type, _bytes...) \BT_DATA(_type, ((uint8_t []) { _bytes }), \sizeof((uint8_t []) { _bytes }))
参考:
5. BLE — BL_MCU_SDK 开发指南 0.3 文档 (gitee.io)
Zephyr API文档:通用访问配置文件(GAP) (zephyrproject.org)
3. 广播数据填充
AD_Data字段:
static const struct bt_data ad[] = {BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA,0x4c, 0x00, 0x07, 0x19, 0x07, 0x0a, 0x20,0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45,0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00)};
开启广播的时候将ad传入,即可完成广播数据设置。
4.随机地址切换
Apple对于相同MAC地址的设备仅会进行一次弹窗,因此如果想要让手机不断的弹出设备提示框就需要定期修改BLE的MAC地址,代码如下:
bt_addr_le_t local_mac_addr;size_t localmac_size = 1;static bt_addr_le_t myaddr = {.type = BT_ADDR_LE_RANDOM,/* fixed MAC addres */.a = {.val = {0x01, 0x02, 0x03, 0x04, 0x05, 0xc6},},};printk("bt_id_create\r\n");err = bt_id_create(&myaddr, NULL);if (err < 0){printk("bt_id_create err!\r\n");}
小思考:这里思考了下苹果的设计美学,以AirPods
为例。通常情况下设备为了节约电池电量并不会一直进行BLE广播,而是在每次打开电池仓时才唤醒ble芯片,关闭电池仓之后进入超低功耗模式。BLE设备的程序在每次唤醒的时候程序会从新启动,所以MAC地址发生改变。
效果演示
问题和解决方法
-
问题描述:使用
7002DK
开发板运行时出现如下问题。
-
原因分析:默认情况下adv字段允许的最大长度为31字节, 当数据填充超出会出现上述报警。
-
解决方法:可以开启ble的
拓展广播
功能来增加最大数据长度。相关配置可以参考Demoperiodic_adv
,相关Menuconfig
修改点如下图所示:
完整代码:
/*** @file main.c* @author Argon* @brief BLE Apple * @version 0.1* @date 2024-01-20* * @copyright Copyright (c) 2024* */
#include <zephyr/types.h>
#include <stddef.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>//扫描数据段
static const struct bt_data ad[] = {BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA,0x4c, 0x00, 0x07, 0x19, 0x07, 0x0a, 0x20,0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45,0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00)};//扫描响应数据段
static const struct bt_data sd[] = {BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),BT_DATA_BYTES(BT_DATA_PERIPHERAL_INT_RANGE, 0x20, 0x00, 0x40, 0x00),BT_DATA_BYTES(BT_DATA_TX_POWER, 0x09),
};//设备名
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)int main(void)
{int err;printk("BLE Starting\n");/* Initialize the Bluetooth Subsystem */err = bt_enable(NULL);if (err){printk("Ble init failed (err %d)\n", err);return 0;}printk("Ble initialized\n");do{//开启广播printk("Ble adv start\r\n");err = bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad),sd, ARRAY_SIZE(sd));if (err){printk("Advertising failed to start (err %d)\n", err);return 0;}k_sleep(K_SECONDS(4));//广播广播printk("Ble adv stop\r\n");err = bt_le_adv_stop();if (err){printk("Advertising failed to stop (err %d)\n", err);return 0;}//更新MACbt_addr_le_t local_mac_addr;static bt_addr_le_t myaddr = {.type = BT_ADDR_LE_RANDOM,/* fixed MAC addres */.a = {.val = {0x01, 0x02, 0x03, 0x04, 0x05, 0xc6},},};printk("Ble update MAC address\r\n");err = bt_id_create(&myaddr, NULL);if (err < 0){printk("bt_id_create err!\r\n");}k_sleep(K_SECONDS(4));} while (1);return 0;
}
相关文章:

Zephyr NRF7002 实现AppleJuice
BLE的基础知识 ble的信道和BR/EDR的信道是完全不一样的。但是范围是相同的,差不多也都是2.4Ghz的频道。可以简单理解为空中有40个信道0~39信道。两个设备在相同的信道里面可以进行相互通信。 而这些信道SIG又重新编号: 这个编号就是把37 38 39。 3个信道…...

(已解决)vue+element-ui实现个人中心,仿照原神
差一个个人中心页面,看到了这个博主的个人中心,真的很不错 地址:vueelement仿原神实现好看的个人中心 最终效果:...
Webpack插件浅析
常用的webpack插件功能介绍: 1.HotModuleReplacementPlugin 模块热更新插件。Hot-Module-Replacement的热更新是依赖于webpack-dev-server,有时是在打包文件改变时更新打包文件或者重新加载刷新整个页面,HMR是只更新修改的部分。 HotModul…...

【Java 数据结构】反射
反射 1 定义2 用途(了解)3 反射基本信息4 反射相关的类(重要)4.1 Class类(反射机制的起源 )4.1.1 Class类中的相关方法(方法的使用方法在后边的示例当中) 4.2 反射示例4.2.1 获得Class对象的三种方式4.2.2 反射的使用 5、反射优点和缺点 1 定义 Java的反…...

LangChain结合通义千问的自建知识库
LangChain结合通义千问的自建知识库 在使用了通义千问API了之后,下一步就是构建知识库文档,使用了比较有名的LangChian,最后成果将自己的txt生成了知识向量库,最后我还把自己的论文生成了一个知识向量库,然后问他我的…...

【证书管理】实验报告
证书管理实验 【实验环境】 ISES客户端 【实验步骤】 查看证书 查看证书详细信息 选择任意证书状态,在下方“证书列表”中出现符合要求的所有证书。在“证书列表”中点击要查看证书,在右侧“证书详细信息”栏出现被选证书信息。 上述操作如图1.2.…...

App Store外区账号分享
App Store外区账号分享及注意事项 外区苹果ID分享指南什么是外区苹果ID?为什么需要外区苹果ID?获取方法分享外区苹果ID的注意事项方式2获取步骤 外区苹果ID分享指南 在数字时代,我们的生活与各种应用和服务紧密相连。 对于苹果用户而言&#…...
判断字符串是否包含正则表达式默认的特殊字符c++
判断字符串是否包含正则表达式默认的特殊字符 业务描述: 上层配置的字符列表中,既有准确的字符串,又有可以进行正则匹配的字符串,这时候需要区分出来那些是正则匹配的字符串。 思路: 判断字符串中,是否存在正则表达…...

【蓝桥杯选拔赛真题64】python数字塔 第十五届青少年组蓝桥杯python 选拔赛比赛真题解析
python数字塔 第十五届蓝桥杯青少年组python比赛选拔赛真题 一、题目要求 (注:input()输入函数的括号中不允许添加任何信息) 提示信息: 数字塔是由 N 行数堆积而成,最顶层只有一个数,次顶层两个数,以此类推。相邻层之间的数用线连接,下一层的每个数与它上一层左上…...

javaEE - 23( 21000 字 Servlet 入门 -1 )
一:Servlet 1.1 Servlet 是什么 Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给程序猿的 API, 帮助程序猿简单高效的开发一个 web app. 构建动态页面的技术有很多, 每种语言都有一些相关的库/框架来做这件事,Servlet 就是 Tomcat 这个 HTTP…...
【sentinel流量卫兵搭建与微服务整合】
sentinel流量卫兵搭建与微服务整合 搭建sentinel dashboard控制台微服务整合搭建sentinel dashboard控制台 1、下载 官网链接 由于官网github网络原因,导致长时间下载失败。 网盘链接 网盘提取码:dwgj 2、运行 将下载jar包放在任意非中文、不包含特殊字符的目录下,重名为…...

Linux环境下配置mysql主从复制
主从配置需要注意的地方 1、主DB server和从DB server数据库的版本一致 2、主DB server和从DB server数据库数据一致[这里就会可以把主的备份在从上还原,也可以直接将主的数据目录拷贝到从的相应数据目录] 3、主DB server开启二进制日志,主DB server和从DB serve…...

生物素-PEG4-酪胺,Biotin-PEG4-TSA,应用于酶联免疫吸附实验
您好,欢迎来到新研之家 文章关键词:生物素-PEG4-酪胺,Biotin-PEG4-Tyramide,Biotin-PEG4-TSA 一、基本信息 产品简介:Biotin PEG4 Tyramine is a reagent used for tyramine signal amplification (TSA) through ca…...
Android:文件读写
3.10 Android读写文件 1、读写文件 Android读写文件操作,不能写入到系统根目录,只能在应用包下文件夹进行读写。 使用getCacheDir()方法,获取当前应用的Cache目录路径; 使用getFilesDir()方法,获取当前应用的files目录路径; 示例: //读取数据public void readData(){…...
2024/2/5
第四章 堆与拷贝构造函数 一 、程序阅读题 1、给出下面程序输出结果。 #include <iostream.h> class example {int a; public: example(int b5){ab;} void print(){aa1;cout <<a<<"";} void print()const {cout<<a<<endl;} …...

政安晨:示例演绎Python的函数与获取帮助的方法
调用函数和定义我们自己的函数,并使用Python内置的文档,是成为一位Pythoner的开始。 通过我的上篇文章,相信您已经看过并使用了print和abs等函数。但是Python还有许多其他函数,并且定义自己的函数是Python编程的重要部分。 在本…...

88 docker 环境下面 前端A连到后端B + 前端B连到后端A
前言 呵呵 最近出现了这样的一个问题, 我们有多个前端服务, 分别连接了对应的后端服务, 前端A -> 后端A, 前端B -> 后端B 但是 最近的时候 却会出现一种情况就是, 有些时候 前端A 连接到了 后端B, 前端B 连接到了 后端A 我们 前端服务使用 nginx 提供前端 html, js…...
k8s学习-Service Account和RBAC授权
1.1 ServiceAccount 介绍 首先Kubernetes中账户区分为:User Accounts(用户账户) 和 Service Accounts(服务账户) 两种,它们的设计及用途如下: UserAccount是给kubernetes集群外部用户使用的&am…...
SpringMVC-响应数据
一、引子 我们在上一篇文章SpringMVC-组件解析里介绍了SpringMVC框架执行一个请求的过程,并演示了快速使用Controller承接请求。本篇我们将深入介绍SpringMVC执行请求时,如何响应客户端。 二、响应类型 SpringMVC的数据响应方式主要分为两类ÿ…...

数学建模:数据相关性分析(Pearson和 Spearman相关系数)含python实现
相关性分析是一种用于衡量两个或多个变量之间关系密切程度的方法。相关性分析通常用于探索变量之间的关系,以及预测一个变量如何随着另一个变量的变化而变化。在数学建模中,这是常用的数据分析手段。 相关性分析的结果通常用相关系数来表示ÿ…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...