当前位置: 首页 > news >正文

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

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

移动端进阶之蓝牙通讯需要综合考虑蓝牙版本选择、协议栈使用、服务匹配、设备连接、安全性和硬件支持等方面。
移动端

一、蓝牙版本选择

根据实际需求和应用场景选择合适的蓝牙版本;
1.0,1M/s。
2.0+EDR,2-3M/s,增加了简易配对的功能。
3.0+HS,24M/s-Generic Alternate MAC/PHY(AMP),支持802.11高速数据传输。
4.0,引入低功耗蓝牙BLE,适用于不需占用太多带宽的设备连接。
5.0,提升BLE的性能,增加了广播容量,扩大通信距离和速度。
5.1,增加定向定位和角度测量的功能。
5.2,增加多音频和低复杂度通信编码(LC3)的功能,可实现更好的音质和更低的功耗。
5.3,完善了BLE的周期性广播、连接更新、频道分级等功能,提高通讯效率、降低功耗并提高无线共存性。移除了AMP,不再支持24M/s。
5.4,新增带响应的周期性广播,带加密的EIR、广播数据加密、Host支持Advertising Coding选择等。
蓝牙版本

选择蓝牙版本时,主要应考虑以下几点:
蓝牙应用的需求:不同的蓝牙应用需要不同的蓝牙版本。例如,对于需要传输大量数据的应用,应选择蓝牙5.0或更高版本,因为它们提供了更高的传输速率和更低的功耗。而对于需要音频传输的应用,蓝牙4.0或更高版本即可满足需求。
设备兼容性:不同版本的蓝牙具有不同的兼容性。如果设备需要与其他蓝牙设备进行通信,应选择与这些设备兼容的蓝牙版本。
成本:不同版本的蓝牙模块成本不同。蓝牙5.0模块的成本高于蓝牙4.0模块,因此在预算有限的情况下,可以选择更低版本的蓝牙。
开发难度:不同版本的蓝牙模块开发难度不同。蓝牙5.0模块的开发难度高于蓝牙4.0模块,因此对于开发能力有限的企业或个人,可以选择更低版本的蓝牙。

二、蓝牙协议栈

蓝牙协议栈(Bluetooth Protocol Stack)是实现蓝牙通信的一组协议的集合,它定义了蓝牙设备之间如何进行数据传输和通信;
蓝牙协议栈包括多个层次,每个层次都有不同的功能和职责;
常见的蓝牙协议栈包括BlueCore、CSR8670/CSR8675和RTKBT11等。
蓝牙

物理层(Physical Layer):物理层负责无线信号的传输,包括信号的调制、解调、频率选择等。
数据链路层(Link Layer):数据链路层负责数据的打包和解包,以及设备间的连接和断开。它还负责处理数据传输中的错误检测和纠正。
网络层(Network Layer):网络层负责设备的寻址和连接管理,包括设备间的安全连接和数据传输。
传输层(Transport Layer):传输层负责数据的分段和重组,以及数据传输的可靠性和流量控制。
应用层(Application Layer):应用层负责提供各种蓝牙服务,如音频传输、文件传输、设备控制等。

BLUECORE(蓝牙核心动力)

这是长安汽车集团推出的高效节能环保动力总成(发动机+变速箱)的解决方案。BLUECORE 涵盖了长安汽车自主研发的多种技术,如TEi、GDi、D-VVT、TC、新能源等,致力于提供纯净、清新的动力系统。

CSR8670/CSR8675

这是CSR(Cambridge Silicon Radio)公司推出的蓝牙音频解决方案芯片。其中,CSR8670是CSR 86xx系列中的高级闪存产品,旨在提供高质量的无线音频性能并支持高差异优质无线音频产品的开发。而CSR8675是一款先进的蓝牙音频解决方案芯片,具有出色的音质表现,采用了aptX高清音频编解码器技术,可以在传输过程中保持音频的高质量。

RTKBT11

这是一款蓝牙模块,符合蓝牙5.0标准,支持经典蓝牙和低功耗蓝牙双模工作模式。该模块具有高性能、低功耗、易于集成等特点,适用于各种需要蓝牙连接的应用场景。

移动端开发通常使用的是Bluetooth Low Energy(BLE),常用的支持BLE的协议栈包括:
BlueZ:BlueZ是Linux操作系统下的开源蓝牙协议栈,支持蓝牙经典(Classic)和低功耗(Low Energy)两种模式。它是Linux下开发蓝牙应用程序的主要协议栈之一。
Windows Bluetooth API:Windows操作系统提供了对蓝牙的支持,包括对BLE的支持。Windows Bluetooth API提供了用于开发蓝牙应用程序的接口和协议栈。
Nordic Semiconductor SDK:Nordic Semiconductor是一家专注于蓝牙低功耗技术的芯片厂商,提供了针对其蓝牙SoC的软件开发套件(SDK),其中包括了完整的蓝牙协议栈和工具链,支持BLE和其他蓝牙技术。
CSR BLE SDK:CSR(Cambridge Silicon Radio)是一家提供蓝牙技术的芯片厂商,也提供了针对其蓝牙SoC的软件开发套件,支持BLE和其他蓝牙技术。

其中使用最多的就是CSR提供的CSR8670/CSR8675。

三、蓝牙服务

移动端需要提供或发现蓝牙服务,并进行服务匹配;
常见的蓝牙服务包括音频服务、文件传输服务、网络服务等;
需要了解并实现这些服务的通讯协议和逻辑。
蓝牙音频服务

蓝牙音频服务

在蓝牙音频服务中,主要有以下几个规范和协议:
A2DP(Advanced Audio Distribution Profile):这是一个专注于音频流传输的规范。它允许传输立体声音频信号,是蓝牙音频传输中的重要组成部分。典型的应用场景是将音乐内容从立体声音乐播放器流式传输到耳机或扬声器。音频数据以适当的格式压缩,以提高效率并使用有限的带宽。
HFP(Hands-free Profile):这是一个基于SCO(Synchronous Connection Oriented)链路的规范,用于双向传输通话语音。它让蓝牙设备可以控制电话,如接听、挂断、拒接、语音拨号等。
AVRCP(Audio/Video Remote Control Profile):这是一个用于远程控制音频和视频播放的规范。通过这个协议,用户可以通过无线方式控制音乐播放器和其他音频设备的基本操作,例如播放、暂停、下一曲和音量控制等。
aptX、aptX-HD和aptX voice:这些都是用于提升蓝牙音频质量的协议。它们通过不同的参数(如16bit/48k、24bit/48k和16bit/32k)提供更高质量的音频传输。
ANC(Active Noise Cancellation):这是一种主动降噪功能,通过消除外部噪音来提高音频质量。
TWS(True Wireless Stereo):这是一种蓝牙无线耳机技术,允许两个耳机在没有有线连接的情况下进行通信,从而提供真正的立体声体验。

四、蓝牙设备连接

移动端需要建立与蓝牙设备的连接,并进行数据传输。需要了解并实现连接的建立、管理和断开逻辑,以及数据传输的协议和流程。
例如在iOS开发中建立蓝牙连接的步骤如下:

  1. 导入蓝牙框架:在项目中使用蓝牙功能,需要导入CoreBluetooth框架。
  2. 创建CBCentralManager实例:CBCentralManager是iOS中用于管理蓝牙的中心管理者,负责扫描、连接和与外围设备的通信。
  3. 配置CBCentralManagerDelegate和CBPeripheralDelegate协议:需要遵守这两个协议,以便在蓝牙连接过程中处理相关事件。
  4. 初始化CBCentralManager:创建一个CBCentralManager实例,并传入self来遵守CBCentralManagerDelegate协议。
  5. 启动CBCentralManager:调用CBCentralManager的startScan方法开始扫描附近的蓝牙设备。
  6. 发现外围设备:当扫描到周围有可连接的蓝牙设备时,CBCentralManager会调用其代理方法并传入CBPeripheral对象。
  7. 连接外围设备:使用CBPeripheral对象的connect方法来连接指定的外围设备。
  8. 获取外围设备的服务:连接成功后,可以通过CBPeripheral对象获取外围设备提供的服务。
  9. 获取服务的特征:从服务中获取特征,这些特征用于读写数据。
  10. 读取和写入数据:通过特征值进行数据的读写操作。

五、蓝牙安全

移动端需要考虑蓝牙通讯的安全性。由于蓝牙通讯是一种无线通讯方式,容易被截获或干扰,因此需要进行安全设置和保护。需要了解并实现安全设置和保护的逻辑,如加密、认证等。
加解密

#include <iostream>  
#include <string>  
#include <cryptopp/aes.h>  
#include <cryptopp/modes.h>  
#include <cryptopp/filters.h>  std::string EncryptAES(const std::string& plainText, const std::string& key) {  CryptoPP::AES::Encryption aesEncryption(key.begin(), key.end());  CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, key.begin());  std::string cipherText;  CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(cipherText));  stfEncryptor.Put(reinterpret_cast<const unsigned char*>(plainText.c_str()), plainText.length() + 1);  stfEncryptor.MessageEnd();  return cipherText;  
}  std::string DecryptAES(const std::string& cipherText, const std::string& key) {  CryptoPP::AES::Decryption aesDecryption(key.begin(), key.end());  CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, key.begin());  std::string plainText;  CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(plainText));  stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipherText.c_str()), cipherText.size());  stfDecryptor.MessageEnd();  return plainText;  
}
#include <iostream>  
#include <string>  
#include <cryptopp/sha.h>  
#include <cryptopp/hex.h>  
#include <cryptopp/modes.h>  
#include <cryptopp/filters.h>  std::string sha256(const std::string& data) {  CryptoPP::SHA256 sha;  byte digest[CryptoPP::SHA256::DIGESTSIZE];  sha.CalculateDigest(digest, reinterpret_cast<const byte*>(data.c_str()), data.size());  std::string hash;  CryptoPP::HexEncoder encoder;  encoder.Attach(new CryptoPP::StringSink(hash));  encoder.Put(digest, sizeof(digest));  encoder.MessageEnd();  return hash;  
}  std::string encryptSha(const std::string& plainText, const std::string& key) {  CryptoPP::AES::Encryption aesEncryption(key.begin(), key.end());  CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, key.begin());  std::string cipherText;  CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(cipherText));  stfEncryptor.Put(reinterpret_cast<const unsigned char*>(plainText.c_str()), plainText.size());  stfEncryptor.MessageEnd();  std::string encryptedHash = sha256(cipherText);  return encryptedHash;  
}  std::string decryptSha(const std::string& cipherText, const std::string& key) {  std::string decryptedText = cipherText; // Assuming the SHA256 hash is the only encrypted data here.  CryptoPP::AES::Decryption aesDecryption(key.begin(), key.end());  CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, key.begin());  CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decryptedText));  stfDecryptor.Put(reinterpret_cast<const unsigned char*>(decryptedText.c_str()), decryptedText.size());  stfDecryptor.MessageEnd();  std::string decryptedHash = sha256(decryptedText); // Decrypted text should match the original hash.  return decryptedHash;  
}

校验

#include <bluetooth/bluetooth.h>  uint16_t crc16(const uint8_t *data, size_t len) {  uint16_t crc = 0xFFFF;  const uint8_t *ptr = data;  while (len--) {  crc ^= (*ptr++) << 8;  for (int i = 0; i < 8; i++) {  if (crc & 0x8000) {  crc = (crc << 1) ^ 0x1021; // Polynomial 0x1021 (CRC-CCITT)  } else {  crc <<= 1;  }  }  }  return crc & 0xFFFF;  
}

六、蓝牙硬件支持

移动端需要使用合适的蓝牙硬件模块来支持蓝牙通讯。常见的蓝牙硬件模块包括CSR、Broadcom、Freescale等厂商提供的模块。需要了解并选择适合自己应用的蓝牙硬件模块。

相关文章:

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

移动端开发进阶之蓝牙通讯&#xff08;一&#xff09; 移动端进阶之蓝牙通讯需要综合考虑蓝牙版本选择、协议栈使用、服务匹配、设备连接、安全性和硬件支持等方面。 一、蓝牙版本选择 根据实际需求和应用场景选择合适的蓝牙版本&#xff1b; 1.0&#xff0c;1M/s。 2.0EDR…...

一个完整的流程表单流转

1.写在前面 一个完整的流程表单审批&#xff08;起表单-->各环节审批-->回退-->重新审批-->完成&#xff09;&#xff0c;前端由Vue2jsElement UI升级为Vue3tsElement Plus&#xff0c;后端流程框架使用Flowable&#xff0c;项目参考了ruoyi-vue-pro(https://gite…...

2024杭州国际智慧城市,人工智能,安防展览会(杭州智博会)

在智能化浪潮的冲击下&#xff0c;我们的生活与环境正在经历一场深刻的变革。这是一场前所未有的技术革命&#xff0c;它以前所未有的速度和广度&#xff0c;改变着我们的生活方式、工作方式、思维方式和社会结构。在这场变革中&#xff0c;有的人选择激流勇进&#xff0c;拥抱…...

编程笔记 html5cssjs 031 HTML视频

编程笔记 html5&css&js 031 HTML视频 一、<video>: 视频元素二、属性三、事件四、嵌入视频页面五、练习小结 视频应用广泛&#xff0c;当前的互联网应用中&#xff0c;视频越来越重要&#xff0c;比如抖音、快手、腾讯视频等应用。 一、<video>: 视频元素 …...

SpringBoot外部配置文件

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:SpringBoot外部配置文件 📚个人知识库: Leo知识库,欢迎大家访问 1.前言☕…...

99个Python脚本实用实例

题目&#xff1a;有四个数字&#xff1a;1、2、3、4&#xff0c;能组成多少个互不相同且无重复数字的三位数&#xff1f;各是多少&#xff1f; #!/usr/bin/python# -*- coding: UTF-8 -*-for i in range(1,5): for j in range(1,5): for k in range(1,5): …...

HarmonyOS 工程目录介绍

工程目录 AppScope&#xff1a;存放应用全局所需要的资源文件 base element&#xff1a;文件夹主要存放公共的字符串、布局文件等资源media&#xff1a;存放全局公共的多媒体资源文件app.json5&#xff1a;应用的全局的配置文件&#xff0c;用于存放应用公共的配置信息 {"…...

门店管理系统驱动智慧零售升级

在当今数字化经济的大潮中&#xff0c;实体门店正在经历一场由内而外的深度变革。门店管理系统以其高效、便捷和全面的功能特性&#xff0c;为实体店提供了高效的运营解决方案。 门店管理系统拜托了传统零售业对本地化软件的依赖&#xff0c;它将复杂的信息技术转化为易于获取…...

Iterator迭代器操作集合元素时,不能用集合删除元素

在使用Iterator迭代器对集合中的元素进行迭代时&#xff0c;如果调用了集合对象的remove()方法删除元素或者调用add()方法添加元素之后&#xff0c;继续使用迭代器遍历元素&#xff0c;会出现异常(java.util.ConcurrentModificationException)。 import java.util.ArrayList; …...

Spring Boot是什么-特点介绍

什么是SpringBoot Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其中“Boot”的意思就是“引导”&#xff0c;Spring Boot 并不是对 Spring 功能上的增强&#xff0c;而是提供了一种快速开发 Spring应用的方式。 Spring Boot 特点 嵌入的 Tomcat&#xff0c;无需部署…...

相机成像之图像传感器与ISP【四】

文章目录 1、图像传感器基础1.1 基础原理——光电效应1.2 基础的图像传感器设计1.3 衡量传感器效率的一个关键指标&#xff1a;光量子效率&#xff08;QE&#xff09;1.4 感光单元的响应1.5 像素的满阱容量1.6 像素尺寸和填充比例1.7 微透镜的作用1.8 光学低通滤波器简介1.9 传…...

新手入门Java 方法带参,方法重载及面向对象和面向过程的区别介绍

第二章 方法带参 课前回顾 1.描述类和对象的关系 类是一组对象的共有特征和行为的描述。对象是类的其中一个具体的成员。 2.如何创建对象 类名 对象名 new 类名();3.如何定义和调用方法 public void 方法名(){}对象名.方法名();4.成员变量和局部变量的区别 成员变量有初…...

使用Sqoop将Hive数据导出到TiDB

关系型数据库与大数据平台之间的数据传输之前写过一些 使用Sqoop将数据在HDFS与MySQL互导 使用Sqoop将SQL Server视图中数据导入Hive 使用DataX将Hive与MySQL中的表互导 使用Sqoop将Hive数据导出到TiDB虽然没写过&#xff0c;但网上一堆写的&#xff0c;那为什么我要专门写一下…...

互联网上门洗衣洗鞋工厂系统搭建;

随着移动互联网的普及&#xff0c;人们越来越依赖手机应用程序来解决生活中的各种问题。通过手机预约服务、购买商品、获取信息已经成为一种生活习惯。因此&#xff0c;开发一款上门洗鞋小程序&#xff0c;可以满足消费者对于方便、快捷、专业的洗鞋服务的需求&#xff0c;同时…...

Redis面试题12

Redis 的主从复制是什么&#xff1f; Redis 的主从复制是一种数据备份和高可用性机制&#xff0c;通过将一个 Redis 服务器的数据复制到其他 Redis 从服务器上来实现数据的冗余备份和读写分离。 主从复制的工作原理如下&#xff1a; 配置主服务器并开启主从复制功能。从服务器…...

el-tree多个树进行节点同步联动(完整版)

2024.1.11今天我学习了如何对多个el-tree树进行相同节点的联动效果&#xff0c;如图&#xff1a; 这边有两棵树&#xff0c;我们发现第一个树和第二个树之间会有重复的指标&#xff0c;当我们选中第一个树的指标&#xff0c;我们希望第二个树如果也有重复的指标也能进行勾选上&…...

python两个字典合并,两个list合并

1.两个字典&#xff1a; a{‘a’:1,‘b’:2,‘c’:3} b {‘aa’:11,‘bb’:22,‘cc’:33} 合并1&#xff1a;dict(a, **b) 结果&#xff1a;{‘a’: 1,‘aa’: 11,‘c’: 3,‘b’: 2,‘bb’: 22,‘cc’: 33} 合并2&#xff1a;dict(a.items()b.items()) 结果&#xff1a;{‘…...

搜维尔科技:【简报】元宇宙数字人赛道,《全息影像技术应用》!

期待着看展的主角来到今天要参观的全息影像展&#xff0c;平时就喜欢看展的她对于所谓的全息影像非常好奇&#xff0c;于是她带着期待的心情进入展内。进入展内的主角看到的是与之前完全不同的画展&#xff0c;每幅画看起来就像真的一样&#xff0c;充满好奇的她在展览的各处游…...

SparkSQL和Hive语法差异

SparkSQL和Hive语法差异 1、仅支持Hive SparkSQL关联条件on不支持函数rand()创建零时表时&#xff0c;Spark不支持直接赋值nullSpark无法读取字段类型为void的表SparkSQL中如果表达式没有指定别名&#xff0c;SparkSQL会将整个表达式作为别名&#xff0c;如果表达式中包含特殊…...

XCODE IOS 静态链接库替换升级

XCODE 版本15.2. 一个很久需求没更新的IOS 应用&#xff0c;近来有新需求要开发。 拉下代码运行&#xff0c;出现了个BAD_ACCESS错误。出错的位置位于一个调用的第三方的.a静态库内部。因为调用代码并没有修改&#xff0c;很容易想到可能XCODE相关升级&#xff0c;导致的问题。…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...