移动端开发进阶之蓝牙通讯(二)

news2024/9/24 23:15:03

移动端开发进阶之蓝牙通讯(二)

蓝牙广播是一种无线通讯技术,通过无线电波传输数据;
在蓝牙低功耗(BLE)协议中,广播通信是其重要组成部分,主要有两类使用场景:
单一方向的、无连接的数据通信,数据发送者在广播信道上广播数据,数据接收者扫描、接收数据;
连接的建立;
此外,每个设备在使用时,同一时刻,只会在一个信道进行工作,不会占用其他信道,这样可以有效地避免干扰,即使一个信道存在干扰,另外的信道也可以很好地工作;
在广播间隔上,设备每次广播时,会在3个广播信道发送相同的报文,这种设置能有效地避免干扰,因为即使一个信道存在干扰,另外的信道也可以很好地工作。
蓝牙通讯

一、广播参数

蓝牙广播的系统参数主要包括广播间隔和广播延时;
广播间隔是一个关键参数,其单位是毫秒,范围通常在20ms至10.24s之间,必须是0.625ms的整数倍;
根据不同的Advertising_Type,最小值可能会有所不同,例如,当Advertising_Type为0x02或0x03时,最小值为100ms。
另外,广播延时是在广播事件期间,链路层产生的一个0ms至10ms之间的伪随机时间量,这个延时被添加到两个广播事件之间,目的是为了防止多个设备间的干扰。

二、广播信道

任何带有信息的信号传递都要占用一定的带宽,不可能是一个单一的频率;
以BLE为例,BLE在2.4GHz频段安排了40个信道(channel),中心频率从2402MHz开始,以2MHz为间隔;
一个BLE设备在任一时刻只能选择40个信道之中一个进行发射或监听;
接收方需要在同一信道上监听才可能收到数据包,接收方还需要知道数据包长度才能进行CRC校验,包长度是包含在PDU段内;
BLE4.0和4.2时,信道37、38和39用于advertising;每次广播,会在3个广播信道上发送相同的报文;
广播信道的选择主要考虑了避免与WiFi等其他无线通信系统的干扰,通过将广播信道设置在非标准WiFi信道,可以降低广播通信受到的干扰,提高通信的可靠性和稳定性。

三、广播结构

蓝牙广播的最大长度是37个字节,其中设备地址占用了6个字节,只有31个字节是可用的,这意味着广播数据最大长度为31字节,包括广播内容类型和广播数据;
在有效广播数据长度方面,由于广播数据包的结构和组成较为复杂,实际上可用的有效广播数据长度可能会受到限制,具体有效长度取决于广播内容类型和广播数据的内容,不同的类型和内容对应不同的长度;
一般情况下蓝牙广播数据由以下部分组成:

  1. Preamble:这是一个长度为1字节的标识符,用于表示广播数据包的开始。
  2. Access Address:这是一个长度为4字节的地址,用于标识广播设备。
  3. PDU Header:这是一个长度为2字节的头部信息,包含广播数据包的长度和类型等信息。
  4. Payload Data:这是实际传输的数据,长度和内容根据具体应用而定。
  5. CRC:这是一个长度为3字节的校验码,用于检测数据传输的错误。

其中,PDU(Protocol Data Unit)是协议数据单元,用于传输数据;
PDU Header是PDU的头部信息,包含了PDU的一些基本信息,例如长度和类型等;
Payload Data是实际传输的数据内容,可以是设备名称、Mac地址、服务UUID等信息;
CRC是校验码,用于检测数据传输过程中是否出现了错误;
根据不同的需求配置,广播实际传输的数据也会有相应的不同。

#include <iostream>  
#include <bluetooth/bluetooth.h>  
#include <bluetooth/rfcomm.h>  
#include <bluetooth/sdp.h>  
  
int main() {  
    // 初始化Bluez库  
    int status = bluetooth_init(&bt_context, NULL);  
    if (status != 0) {  
        std::cerr << "Failed to initialize Bluez library." << std::endl;  
        return 1;  
    }  
  
    // 打开默认的RFCOMM通道(1)  
    int channel = 1;  
    int fd = bt_open_channel(channel);  
    if (fd < 0) {  
        std::cerr << "Failed to open RFCOMM channel." << std::endl;  
        return 1;  
    }  
  
    // 开始扫描附近的蓝牙设备  
    const int type = BLUETOOTH_DISCOV_ANY; // 扫描所有类型的设备  
    const int filter = 0; // 不使用过滤器  
    int err = bt_discovery(type, filter, NULL, NULL);  
    if (err != 0) {  
        std::cerr << "Failed to start device discovery." << std::endl;  
        return 1;  
    }  
  
    // 等待设备广播事件  
    struct sockaddr_rc addr = {0};  
    socklen_t len = sizeof(addr);  
    int events = POLLIN; // 等待数据可读的事件  
    int e = poll(&bt_event, 1, -1, &events); // -1 表示无限等待  
    if (e == -1) {  
        std::cerr << "Failed to wait for device discovery event." << std::endl;  
        return 1;  
    }  
  
    // 处理发现的设备广播事件  
    if (bt_event.revents & POLLIN) { // 数据可读事件发生时处理广播数据包  
        char buffer[256]; // 用于存储接收到的广播数据包  
        int bytes_read = recvfrom(bt_event.fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, &len); // 接收广播数据包  
        if (bytes_read > 0) { // 处理接收到的数据包  
            std::cout << "Received device broadcast." << std::endl;  
            // 在这里处理广播数据包,例如解析服务UUID等。你可以根据需要添加代码来识别特定的设备和服务。  
            // ...  
            // 应答广播并尝试建立连接的代码也放在这里。具体的实现取决于你希望如何应答和建立连接。你可能需要发送特定的命令或数据来响应设备,然后等待设备的响应以建立连接。这部分代码需要根据具体的设备和协议进行实现。  
        } else { // 处理接收错误的情况  
            std::cerr << "Failed to receive device broadcast." << std::endl;  
        }  
    } else if (bt_event.revents & POLLHUP) { // 处理连接断开事件(如果适用)  
        std::cerr << "RFCOMM channel disconnected." << std::endl;  
    } else if (bt_event.revents & POLLERR) { // 处理其他错误事件(如果适用)  
        std::cerr << "Error on RFCOMM channel." << std::endl;  
    } else { // 处理其他未知事件(如果适用)  
        std::cerr << "Unknown event on RFCOMM channel." << std::endl;  
    }  
  
    // 清理并关闭资源  
    close(bt_event.fd); // 关闭RFCOMM通道的文件描述符  
    bluetooth_cleanup(&bt_context); // 清理Bluez库资源  
    return 0; // 表示成功执行完毕或出现错误导致程序退出,具体取决于前面的错误处理逻辑。你可以根据需要添加更多的错误处理和资源清理逻辑。  
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基本BGP配置试验 :配置 IBGP 和 EBGP

一、预习&#xff1a; BGP&#xff1a;Border Gateway Protocol 没有精妙的算法&#xff0c;但能承载大量的路由&#xff0c;它不生产路由&#xff0c;它是路由的搬运工 使用TCP做为传输层协议&#xff0c;端口号179&#xff0c;使用触发式路由更新 1. BGP路由…

喜讯!矩阵起源子公司通过“国家高新技术企业”认定,引领数据库行业科技创新!

近日&#xff0c;全国高新技术企业认定管理工作领导小组办公室&#xff0c;公布了《上海市认定机构2023年认定报备的第二批高新技术企业备案公示名单》&#xff0c;矩阵起源子公司矩智原力&#xff08;上海&#xff09;信息科技有限公司&#xff08;以下简称“矩智原力”&#…

2024年【北京市安全员-C3证】复审考试及北京市安全员-C3证证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 北京市安全员-C3证复审考试考前必练&#xff01;安全生产模拟考试一点通每个月更新北京市安全员-C3证证考试题目及答案&#xff01;多做几遍&#xff0c;其实通过北京市安全员-C3证模拟考试题很简单。 1、【多选题】《…

vue前端开发自学,插槽练习,同时渲染父子组件的数据信息

vue前端开发自学,插槽练习,同时渲染父子组件的数据信息&#xff01; 如果想在slot插槽出口里面&#xff0c;同时渲染出来&#xff0c;来自父组件的数据&#xff0c;和子组件自身的数据呢。又有点绕口了。vue官方给的解决办法是。需要借助于&#xff0c;父组件的自定义属性。 …

利用低代码技术,企业怎样开拓数字化转型新路径?

近年来&#xff0c;随着技术的发展和市场竞争的加剧&#xff0c;企业数字化转型已成为一种趋势。许多企业已经完成了线上协作办公的初步转型&#xff0c;这主要得益于像钉钉、企微等发展完善的平台&#xff0c;只需将员工全部拉入这些平台&#xff0c;就能实现线上协作办公。 然…

2024java开发学习路线

文章目录 第一阶段【JAVA基础】第二阶段【数据库jdbc】第三阶段【JavaWeb】第四阶段【框架】第五阶段【微服务】第六阶段【常用中间件】第七阶段【查缺补漏】 别问&#xff0c;问就是Java已死&#xff01;这是在2023年疫情解封后&#xff0c;市场经济低迷的情况下&#xff0c;有…

编码技巧:如何在Golang中高效解析和生成XML

编码技巧&#xff1a;如何在Golang中高效解析和生成XML 引言Golang中的XML基础解析XML文件生成XML文件错误处理和调试高级技巧和最佳实践总结 引言 在当今数据驱动的编程世界中&#xff0c;有效地处理各种数据格式是每个开发人员必备的技能之一。其中&#xff0c;XML&#xff…

快速高效处理长图:按指定高度切长图的方法,提升设计品质

在现代视觉传达设计中&#xff0c;长图作为一种常见的表现形式&#xff0c;被广泛应用于各种场景。如何快速高效地处理长图&#xff0c;使其符合设计要求和用户体验&#xff0c;成为设计师们面临的一大挑战。现在来看“办公提效工具”如何按指定高度切长图&#xff0c;提升设计…

Python: locals()详细解释

locals() 是一个内置函数&#xff0c;用于返回当前局部作用域的字典。这个字典包含了当前函数或模块中所有局部变量的名称和值。具体来说&#xff1a; locals()返回值&#xff1a;一个字典&#xff0c;包含了当前局部作用域的所有局部变量。 这个函数在不同的上下文中有不同的…

SpringBoot项目的两种发布方式(jar包和war包)

SpringBoot项目的两种发布方式&#xff08;jar包和war包&#xff09; 在springboot入门和项目示例这个项目和application.yml配置端口号和访问url路径基础上进行修改 1、使用jar包方式发布 1.1、在pom.xml中添加一个SpringBoot的构建的插件 <build><plugins>&l…

Openlayer【四】—— 控件

控件 控件是一个可见的小部件&#xff0c;其 DOM 元素位于 屏幕。它们可以涉及用户输入&#xff08;按钮&#xff09;&#xff0c;也可以仅供参考; 位置是使用 CSS 确定的。默认情况下&#xff0c;它们位于 容器&#xff0c;但可以使用 任何外部 DOM 元素。 其中ol/control是…

存储的基本架构

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、存储的需求背景二、自下而上存储架构总结 一、存储的需求背景 1、人的身份信息需要存储 这种信息可以用关系型数据库&#xff0c;例如mysql&#xff0c;那种表…

4 - JdbcTemplate

spring 框架如何处理对数据库的操作呢? 1. 基本介绍 文档&#xff1a;JdbcTemplate APIs : /spring-framework-5.3.8/docs/javadoc-api/index.html JdbcTemplate 是 Spring 提供的访问数据库的技术。可以将 JDBC 的常用操作封装为模板方法 已经提供了特别多的 API 2. 使用…

说一说文件转换服务的系统设计

一、背景 我们需要把word/ppt转换为pdf&#xff0c;刚开始自研&#xff0c;后改为和第三方服务合作。 因为涉及到第三方服务的源码及软件著作的安全问题&#xff0c;我们约定把待转换的文件下载到对方管控的机器里&#xff0c;而不是在我们的机器上安装第三方的转换工具。 这…

从0开始学Git指令(3)

从0开始学Git指令 因为网上的git文章优劣难评&#xff0c;大部分没有实操展示&#xff0c;所以打算自己从头整理一份完整的git实战教程&#xff0c;希望对大家能够起到帮助&#xff01; 远程仓库 Git是分布式版本控制系统&#xff0c;同一个Git仓库&#xff0c;可以分布到不…

VUE项目快速打包发布

VUE项目快速打包发布 首先在你的VS Code中新建一个终端 输入 npm run build 回车等运行结束之后会在你的项目中生成一个dist目录 此时再iis部署的时候把你添加的网站指定的目录指向dist即可

202405读书笔记|《作家榜名著:宋词三百首(马未都亲笔推荐版)》——绿酒初尝人易醉,一枕小窗浓睡

《作家榜名著&#xff1a;宋词三百首&#xff08;马未都亲笔推荐版&#xff09;》画很美&#xff0c;词也是&#x1f618;&#x1f618;&#xff0c;既廖远又色彩明艳&#xff0c;丰富而丰盈&#xff0c;看的很欢乐的一本书。部分节选如下&#xff1a; 艳溢香融 天遥地远&…

为什么很多人不看好鸿蒙?轻舟已过万重山

其实这个争议存在很久了。但是到2023年9月份开始&#xff0c;华为秋季发布会上宣布了“鸿蒙不再兼容Android”当时就已经炸开了锅。这个消息让很多不看好鸿蒙的人都闭上了嘴。我们作为国人应该支持自己的操作系统。 鸿蒙4.0&#xff0c;轻舟已过万重山&#xff01; 鸿蒙Harmo…

第七在线智能商品计划签约潮流风向标Alexander Wang亚历山大·王

Alexander Wang&#xff08;亚历山大•王&#xff09;是由华裔设计师王大仁于2004年创立的同名服装品牌&#xff0c;源自纽约&#xff0c;隶属意大利YOOX集团。主营业务涉及成衣、包袋、鞋履、配饰等。并以其简洁、时尚、前卫的设计风格而备受瞩目&#xff0c;它的设计融入了时…

代码随想录算法训练营Day21| 93.复原IP地址、78.子集、90.子集||

LeetCode 93 复原 IP 地址 本题思路&#xff1a;最重要的是想到一个收集结果的条件&#xff0c;也就是终止条件。 当 . 的个数达到三个时候&#xff0c;并且&#xff0c;判断最后剩余的是否符合要求&#xff0c;如果符合&#xff0c;说明整个ip地址可以&#xff0c;就加入到结…