Zephyr NRF7002 实现AppleJuice

BLE的基础知识

在这里插入图片描述

ble的信道和BR/EDR的信道是完全不一样的。但是范围是相同的,差不多也都是2.4Ghz的频道。可以简单理解为空中有40个信道0~39信道。两个设备在相同的信道里面可以进行相互通信。

而这些信道SIG又重新编号:

../../_images/adv_channel2.png

这个编号就是把37 38 39。 3个信道抽出来,作为广播信道,其他都是数据信道。这篇文章主要讲广播,所以基本数据信息都是围绕37 38 39这三个信道上面的通信来讲的。

我们可以看到这3个信道是分散排列的。大家可以思考下为什么。

其实看下面一张图就知道了。

../../_images/wifi_channel.png

数据广播

广播组成部分

广播分为如下几个部分:

  • 广播
  • 扫描请求
  • 扫描响应

在这里插入图片描述

广播的报文格式

在这里插入图片描述

{"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的拓展广播功能来增加最大数据长度。相关配置可以参考Demo periodic_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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/255921.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Seurat - 聚类教程 (1)

设置 Seurat 对象 在本教程[1]中&#xff0c;我们将分析 10X Genomics 免费提供的外周血单核细胞 (PBMC) 数据集。在 Illumina NextSeq 500 上对 2,700 个单细胞进行了测序。可以在此处[2]找到原始数据。 我们首先读取数据。 Read10X() 函数从 10X 读取 cellranger 管道的输出&…

Linux network namespace 访问外网以及多命名空间通信(经典容器组网 veth pair + bridge 模式认知)

写在前面 整理K8s网络相关笔记博文内容涉及 Linux network namespace 访问外网方案 Demo实际上也就是 经典容器组网 veth pair bridge 模式理解不足小伙伴帮忙指正 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#xff0c;眼前的风景已…

数据结构第十四天(树的存储/双亲表示法)

目录 前言 概述 接口&#xff1a; 源码&#xff1a; 测试函数&#xff1a; 运行结果&#xff1a; 往期精彩内容 前言 孩子&#xff0c;一定要记得你的父母啊&#xff01;&#xff01;&#xff01; 哈哈&#xff0c;今天开始学习树结构中的双亲表示法&#xff0c;让孩…

H12-821_74

74.在某路由器上查看LSP&#xff0c;看到如下结果&#xff1a; A.发送目标地址为3.3.3.3的数据包时&#xff0c;打上标签1026&#xff0c;然后发送。 B.发送目标地址为4.4.4.4的数据包时&#xff0c;不打标签直接发送。 C.当路由器收到标签为1024的数据包&#xff0c;将把标签…

MySQL数据库⑦_复合查询+内外链接(多表/子查询)

目录 1. 回顾基本查询 2. 多表查询 2.1 笛卡尔积初步过滤 3. 自连接 4. 子查询 4.1 单行子查询 4.2 多行子查询 4.2 多列子查询 4.2 from子句中使用子查询 5. 合并查询 6. 内外链接 6.1 内连接 6.2 左外链接 6.2 右外连接 本篇完。 1. 回顾基本查询 先回顾一下…

架构整洁之道-软件架构-展示器和谦卑对象、不完全边界、层次与边界、Main组件、服务

6 软件架构 6.9 展示器和谦卑对象 在《架构整洁之道-软件架构-策略与层次、业务逻辑、尖叫的软件架构、整洁架构》有我们提到了展示器&#xff08;presenter&#xff09;&#xff0c;展示器实际上是采用谦卑对象&#xff08;humble object&#xff09;模式的一种形式&#xff…

【深度优先搜索】【树】【图论】2973. 树中每个节点放置的金币数目

作者推荐 视频算法专题 本博文涉及知识点 深度优先搜索 树 图论 分类讨论 LeetCode2973. 树中每个节点放置的金币数目 给你一棵 n 个节点的 无向 树&#xff0c;节点编号为 0 到 n - 1 &#xff0c;树的根节点在节点 0 处。同时给你一个长度为 n - 1 的二维整数数组 edges…

寒假作业

手写盗版微信登入界面 #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);this->resize(421,575);this->setFixedSize(421,575);th…

05-Java原型模式 ( Prototype Pattern )

原型模式 摘要实现范例 原型模式&#xff08;Prototype Pattern&#xff09;是用于创建重复的对象&#xff0c;同时又能保证性能原型模式实现了一个原型接口&#xff0c;该接口用于创建当前对象的克隆当直接创建对象的代价比较大时&#xff0c;则采用这种模式 例如&#xff0c…

分享88个文字特效,总有一款适合您

分享88个文字特效&#xff0c;总有一款适合您 88个文字特效下载链接&#xff1a;https://pan.baidu.com/s/1Y0JCf4vLyxIJR6lfT9VHvg?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不…

SpringMVC第二天

一、SSM整合【重点】 1 SSM整合配置 问题导入 请描述“SSM整合流程”中各个配置类的作用&#xff1f; 1.1 SSM整合流程 创建工程 SSM整合 Spring SpringConfig MyBatis MybatisConfig JdbcConfig jdbc.properties SpringMVC ServletConfig SpringMvcConfig 功能模块…

【ES】--Elasticsearch的分词器深度研究

目录 一、问题描述及分析二、analyze分析器原理三、 multi-fields字段支持多场景搜索(如同时简繁体、拼音等)1、ts_match_analyzer配置分词2、ts_match_all_analyzer配置分词3、ts_match_1_analyzer配置分词4、ts_match_2_analyzer配置分词5、ts_match_3_analyzer配置分词6、ts…

Python爬虫http基本原理#2

Python爬虫逆向系列&#xff08;更新中&#xff09;&#xff1a;http://t.csdnimg.cn/5gvI3 HTTP 基本原理 在本节中&#xff0c;我们会详细了解 HTTP 的基本原理&#xff0c;了解在浏览器中敲入 URL 到获取网页内容之间发生了什么。了解了这些内容&#xff0c;有助于我们进一…

Elasticsearch:使用 LangChain 文档拆分器进行文档分块

使用 Elasticsearch 嵌套密集向量支持 这个交互式笔记本将&#xff1a; 将模型 “sentence-transformers__all-minilm-l6-v2” 从 Hugging Face 加载到 Elasticsearch ML Node 中使用 LangChain 分割器将段落分块成句子&#xff0c;并使用嵌套密集向量将它们索引到 Elasticse…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Toggle组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Toggle组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Toggle组件 组件提供勾选框样式、状态按钮样式及开关样式。 子组件 仅当Toggl…

计算机网络-差错控制(纠错编码 海明码 纠错方法)

文章目录 纠错编码-海明码海明距离1.确定校验码位数r2.确定校验码和数据的位置3.求出校验码的值4.检错并纠错纠错方法1纠错方法2 小结 纠错编码-海明码 奇偶校验码&#xff1a;只能发现错误不能找到错误位置和纠正错误 海明距离 如果找到码距为1&#xff0c;那肯定为1了&…

掌握高效秘诀:揭秘从容应对多任务管理的终极妙招

多任务管理是非常重要的技能&#xff0c;然而如何平衡任务和时间仍然是许多人的挑战。进行多任务管理一般可以从设定目标和清单、排除无关任务、执行任务的时间块化、利用团队合作、学会任务切换几个方面出发&#xff0c;在本文中我们将详细介绍如何利用有效的多任务管理技巧来…

Guava:Cache强大的本地缓存框架

Guava Cache是一款非常优秀的本地缓存框架。 一、 经典配置 Guava Cache 的数据结构跟 JDK1.7 的 ConcurrentHashMap 类似&#xff0c;提供了基于时间、容量、引用三种回收策略&#xff0c;以及自动加载、访问统计等功能。 基本的配置 Testpublic void testLoadingCache() th…

【linux系统体验】-archlinux简易折腾

archlinux 一、系统安装二、系统配置及美化2.1 中文输入法2.2 安装virtualbox增强工具2.3 终端美化2.4 桌面面板美化 三、常用命令 一、系统安装 安装步骤人们已经总结了很多很全: Arch Linux图文安装教程 大体步骤&#xff1a; 磁盘分区安装 Linux内核配置系统&#xff08;…

WordPress后台编辑个人资料页面直接修改用户名插件Change Username

前面跟大家介绍了『如何修改WordPress后台管理员用户名&#xff1f;推荐2种简单方法』一文&#xff0c;但是对于新站长或者有很多用户的站长来说&#xff0c;操作有点复杂&#xff0c;所以今天向大家推荐一款可以直接在WordPress后台编辑个人&#xff08;用户&#xff09;资料页…