草庐IT

蓝牙模块测试那些事之从机测试

明解嵌入式 2023-03-28 原文
​  摘要:本文主要目的是在拿到一个蓝牙模块后,将其作为从机来对一些基本的软件功能进行测试,用以快速验证是否满足基本的使用需求和功能指标。针对测试的方法和测试的项目进行总结,作为对蓝牙模块从设备模式下的功能的一个初步评估。

一、测试目的

        1、快速验证蓝牙模块从机模式下的基本功能。

        2、初步评估蓝牙模块从机模式下通信参数指标是否满足软件功能需求。

        3、掌握蓝牙调试助手的使用方法。

        4、熟悉蓝牙模块从机相关测试方法。

        5、熟悉蓝牙模块相关设置命令和含义。


二、测试工具

硬件:

        1、蓝牙模块一个,后续需要根据蓝牙模块是单模还是双模进行针对性的协议测试。

        2、USB转串口线,用于连接蓝牙模块和PC端通信,设置命令和数据收发,当然蓝牙模块还有别的类型的接口,这里仅对串口蓝牙模块进行测试。

        3、手机一个或多个,用于连接上蓝牙模块后收发数据,可以使用多个品牌的手机,进行不同手机系统兼容性测试。

软件:

       1、PC端串口调试工具软件,用于收发从蓝牙模块串口的数据,如sscom,xcom,Secure CRT等。

        2、手机端蓝牙调试助手,用于和蓝牙模块连接后,通过手机蓝牙收发蓝牙模块的空中数据。根据用的蓝牙模块是单模还是双模选择,如BLE调试助手,SPP调试助手,调试全能王等。

关于蓝牙调试助手:

        1、针对不同协议进行测试时使用的蓝牙助手工具也不同,分别使用SPP蓝牙助手和BLE蓝牙助手。

        2、打开蓝牙调试助手,搜索蓝牙设备,找到需要测试的蓝牙模块进行连接。

        3、蓝牙服务相关

        连上之后,就会看到几个蓝牙服务,实时日志里也会看到连接状态的提示;使用蓝牙对外提供服务的设备,需要有对应的服务功能。蓝牙服务分为服务、特性、属性三个部分:

(1)、服务(Service)

        每一个具体的蓝牙应用是由多个服务(Service)组成的,而每一个服务(Service)又是由多个特性(Characteristic)组成的。服务(Service) 可以理解为一个房间,当这个房间为空的时候他什么也不是,不能提供任何的服务功能,所以,房间里面至少需要有一个或多个家俱,不同的家俱有不同的功能,这就是特性(Characteristic)。不同的服务(Service)应该有不同的编号(UUID),用以区分不同的服务(Service)。

        比如蓝牙连上之后,可以看到这几个蓝牙服务,Generic Access、Generic Attribute、Device Information以及Unknown Service。

(2)、特性(Characteristic)

        特性(Characteristic) 是依附于某个服务(Service)的,就像前面说到房间里每样家俱可以提供与之相关的不同功能。同样,我们需要给每样家俱分配一个编号,这就是特性(Characteristic)的UUID。我们知道,每种家俱会有一个或多个不同的子功能,这个子功能就是特性(Characteristic)所包含的属性(Property) 。例如床单可以更换、床的高低可以调整。

        比如服务Generic Access的含义是“通用访问”,下面有特性:

        DeviceName,设备名。

        Appearance,说明自己是个什么设备(比如蓝牙鼠标)。

        Peripheral Preferred Connection Parameters,外设首选连接参数。

        服务Generic Attribute的含义是“通用属性”,下面有特性:

        ServiceChanged,服务改变。

(3)、属性(Property)

        通常的数据交互的属性有如下几个:

        Read:读属性,具有这个属性的特性是可读的,也就是说这个属性允许手机来读取一些信息。手机可以发送指令来读取某个具有读属性UUID的信息。

        Notify:通知属性, 具有这个属性的特性是可以发送通知的,也就是说具有这个属性的特性(Characteristic),蓝牙模块可以主动发送信息给手机。Notify是一直读取,Read是想读取的时候读取。

        Write:写属性, 具有这个属性的特性是可以接收写入数据的。通常手机发送数据给蓝牙模块就是通过这个属性完成的。这个属性在Write 完成后,会发送写入完成结果的反馈给手机,然后手机再可以写入下一包或处理后续业务,这个属性在写入一包数据后,需要等待应用层返回写入结果,速度比较慢。

        WriteWithout Response:写属性,从字面意思上看,只是写,不需要返回写的结果,这个属性的特点是不需要应用层返回,完全依靠协议层完成,速度快,但是写入速度超过协议处理速度的时候,会丢包。

        Indication:在手机收到蓝牙模块数据后会主动回一个应答,有确认机制,蓝牙模块收到应答后才继续发送下一个数据,保证数据正确到达,也起到了流控的作用。Notify无确认机制,不会保证数据发送是否到达。

(4)、UUID

        通用唯一标识符。是蓝牙组织联盟定义的用于区分蓝牙服务和特性的的标识符,总长度为128 Bit。UUID 用于标识蓝牙服务以及通讯特征访问属性,不同的蓝牙服务和属性使用不同的访问方法,就像人们语言交流一样,语言相同才能正常交流(找到正确的UUID,才能使用正确的功能)。

        简单理解UUID就是编号,对应不同服务的一个唯一的编号,用于区分不同的服务及服务特性的个体。服务和特性都有各自的UUID。他很像网络应用中的端口号,例如80是HTTP协议的端口,他提供的是HTTP服务。

        为了明确标准的蓝牙服务,蓝牙技术联盟SIG定义UUID共用了一个基本的UUID。总共128Bit,据蓝牙官网Assigned Numbers | Bluetooth® Technology Website里的文档Service Discovery,可以看到基本的UUID为:

        128Bit的UUID占用16个字节,在变成个传输的时候都很不方便,所以蓝牙联盟定义了一个UUID的基地址,允许在此基础上使用16Bit的UUID,进一步简化基本UUID:

        0x0000xxxx-0000-1000-8000-00805F9B34FB

        每一个蓝牙技术联盟定义的属性有一个唯一的16BitUUID,以代替上面的基本UUID的‘x’部分。使用16Bit的UUID便于记忆和操作,如SIG定义了“Device Information”的16BitUUID为0x180A。

        也就是说,不管是什么样的蓝牙设备,只要你提供设备信息(Device Information) 的服务功能,就必须使用”0x180A“的UUID号。这样,当应用程序需要读取这蓝牙设备的设备信息时,只需要找到对应UUID号为0x180A的服务,就可以获取到。

        技术联盟已定义好较多的标准服务UUID。根据蓝牙官网的16bit UUID文档,可以看到:

        同时,也允许厂商定义自己的UUID,以满足已定义服务外的功能实现。很多厂家的蓝牙串口模块(及某些服务)并没真正使用规定的标准UUID编号,而使用自己定义的UUID。


三、测试项目

1、协议功能

        蓝牙模块按照对蓝牙协议栈支持的数量可以分为单模模块(经典蓝牙或低功耗蓝牙)和双模模块(经典蓝牙和低功耗蓝牙),如经典蓝牙的数据传输基于SPP协议,低功耗蓝牙的数据传输基于BLE协议。同样针对不同协议进行测试时使用的蓝牙助手工具也不同,分别使用SPP蓝牙助手和BLE蓝牙助手,后续的测试项目中针对蓝牙模块支持的协议的不同,要使用对应的蓝牙助手进行连接以应对不同协议的测试。

2、波特率支持

        主要是选用蓝牙模块规格书中支持的蓝牙串口波特率来进行和手机通信测试,一般蓝牙模块都有对应的命令对蓝牙模块的波特率进行修改。根据项目的蓝牙模块串口通信要求,为蓝牙模块设置对应的波特率,从而满足单位时间内数据带宽的要求,这里的波特率指的是蓝牙模块上硬件串口的数据吞吐量,实际要看透传理论最大空中速度(如一定距离内,数据从模块发送至手机的空中速度为10KB/s),只要串口的输入速度小于等于数据在空中的发送速度,模块就没有字节限制。实际速度会根据软硬件差异、环境、距离等的不同而有所差异。

        为蓝牙模块设置好固定的波特率后,需要在PC端串口调试工具上设置好对应的波特率进行数据收发。

3、发送间隔

        在对应的蓝牙协议模式下,分别在手机蓝牙助手上设置数据自动发送的间隔和PC端串口工具的自动发送间隔,设置好后,可以测试手机给蓝牙模块发送或者蓝牙模块给手机发送,以及手机和蓝牙模块同时互相发送这种全双工通信的情况,主要是为了模拟在软件程序开发中实际通信时的每包数据的发送间隔,验证在设置的数据包时间间隔下的通信效率。当然,测试时需要设置好相互发送的每包数据长度。

        分别在PC端串口调试工具和蓝牙调试助手上设置好每包数据循环发送的时间间隔,观察互发互收的情况。

4、丢包率

        指测试中所丢失数据包数量占所发送数据的比率。手机蓝牙助手和PC端的串口工具都可以检测到数据包发送的数量和接收的数量,因此可以为蓝牙模块设定好固定的波特率,以及分别在蓝牙助手和PC端串口工具上设置需要发送的数据包长度,在一定通信距离和时间内测试手机给蓝牙模块发送或者蓝牙模块给手机发送,以及手机和蓝牙模块同时互相发送这种全双工通信的情况,观察双方收发数据包的个数是否有丢失。

        可以分别在PC端串口调试工具和蓝牙调试助手上观察相互收发的数据字节长度,来确认是否有数据丢包的情况。

5、通信距离

        测量通信距离是使用用手机离蓝牙模块一段距离后通信的数据是否正常,当然,这个和具体蓝牙模块设计的射频发射功率,接收灵敏度,收发环境,空中速率,无线电压以及天线的类型和位置有关系,同样可以选定不同的场景测试,如直线或非直线距离,是否穿墙及穿墙的层数等。一般可以先通过命令修改好蓝牙模块的射频功率,同时配置好数据发送间隔和包长等参数后,进行一个初步模拟实际使用时的通信距离测试。

        可以在蓝牙调试助手上看到扫描到的模块信号的强度,dbm 中文是分贝毫瓦,是一个表示无线功率的绝对值。它的数值是以1mw功率为基准的一个比值。计算公式如下:dbm=10log(p/1mw)

        为什么常见的信号强度都是负数的值呢?因为1mw = 0 dbm, 而随着信号在空间内传播,又受到障碍物的干扰,能量会衰减,所以常见的接收端显示的信号强度都为负值,表示比1mw弱。由此也可以得知,信号强度这个值越大,表示信号越好。比如-30dbm比-90dbm好。

        尝试分别在近距离和远距离测试蓝牙模块,可以在蓝牙调试助手上观察到信号强度的变化。

  

6、通信回连测试

        如果一个蓝牙设备已经与蓝牙中心设备连接上,那么当该蓝牙设备的断电重启,其依然会和配对过的中心主设备连接上,而不需要重新走配对的流程,这个过程叫做回连。

        当设备重启之后,蓝牙协议栈以及所有的上层的profile都要重新进行初始化,之前的配对信息是保存在文件bt_config.conf中,蓝牙起来之后,会去加载这个文件,去解析曾经配对过的设备,对于已经配对过的设备,并且配对信息保持完整,那么就会对该设备发起回连。手机连接蓝牙模块后,蓝牙模块断电再上电,在蓝牙调试助手上观察蓝牙模块回连状态。

7、通信稳定性

        需要说明的是这里的通信稳定性仅仅是在正常的环境下,对蓝牙模块进行一个基本综合测试。主要是进行一个长时间的手机和蓝牙模块通信数据收发测试,选定好波特率、包长、通信包发送时间间隔、通信距离等参数后,进行例如1h或更长时间的数据收发测试后,检查是否有丢包,误码,断连等异常情况发生。

8、兼容性测试

        安卓手机版本众多,各大安卓品牌都深度定制,略有差异。所以为了达到好的效果,需要使用不同品牌和型号的手机来测试蓝牙模块的数据传输,这也是有必要的。


四、总结

        最后用一张思维导图作为蓝牙模块从机的测试总结。


 更多技术内容和书籍资料获取敬请关注微信公众号“明解嵌入式”

有关蓝牙模块测试那些事之从机测试的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  5. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  6. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  7. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  8. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  9. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  10. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

随机推荐