360独角兽实习,连载周记(gnuradio 低功耗蓝牙BLE 综合工具模块编写)
(有点乱,之后会有整理)
最近在用写一套gnuradio的OOT模块,主要用来进行BLE嗅探的,github上有了一些工具,可是他们并没有很好的模块化,于是打算自己写一个,这样以后做一些其他的项目,模块可以在grc流图里直接用,复用性会好很多。
我在github上找到了一个项目叫做BLE_dump,我参考了他的解调方式,事实证明这种解调方式的效果非常好,具体的细节可以参考我博客中转发的另外一篇文章。
先总的来看一下流图,目前可以输出二进制的BLE包,还没有解扰
首先就是bit规则,这点在蓝牙官方手册里说得并不太清晰(起码我没有看明白),bit 规则讲的是bit流是以何种顺序被发射出去,这是序列检查的关键,经过我很多天的尝试,大概确定了下来。以比较常见的广播信道为例。
在表述中,使用0x8E89BED6表示广播信道的Access Address地址,这是标准广播信道的部分数据包格式。于是就有了第一个模块——find_pack_by_preamble。检测前导码的时候,我没有采用上文中BLE_dump的方式,他的方式是先把二进制流转换为16进制,之后检查0xAA,但是这样可能会有同步的问题,前导码一半在一个16进制数里,另一半在后边。我使用了一个有376位的数组,每次从后往前位移,例如第375位的数,他是刚输入进来的,下一次被移动到375,然后374,最后到0,然后被丢弃。我检查从0位到7位,这8个bit是01010101,那么就是一个广播信道的前导码。按照BLE规则,无论什么信道,要保证9个的交替bit,所以前9个都可以作为识别。检查通过的话,就把这376位压缩为47个16进制数,交给下一个模块分析。
因为经过这个块之后,数据会变成异步,所以在使用gr_modtool创建的时候,选择的sink模板,这样是没有输出端口的。那么数据该如何异步输出呢,我使用了 Async Message 作为输出数据流。这里的输出端口的声明和常规的例子是不一样的,需要按照如下的规则声明
我还没有太搞懂set_output_multiple的作用,可能是缓冲区的设置,因为我把它删除之后,数据流会时不时发生异常,下面一句就是声明异步输出端口的其中pmt::mp(“out”)可以理解成端口的ID号码。
同时,对xml文件也要有所改动,如下图
手动添加了(makexml不可以)一个out端口,数据格式为message,也就是grc中灰色的小框。
下一个模块我用python写的,主要是根据access address对上级block过来的数据包再次筛选,首先,因为是接收异步数据,要多import一些东西
在获取数据之前,要声明一些东西
Message_port_register_in(pmt.inter(‘in’))是声明这个模块接收异步数据,下一个,是指示回调函数,第一个参数要pmt.inter(‘in’)保持一致,第二个参数是用来处理数据包的函数名,也就是相当于work函数,后面还有一个out端口,那是之后的任务,这里就把它留在那。
数据的获取和处理如下:
函数注意要和上文所提保持一致,上级模块发送过来的数据就在第二个参数里。数据传入之后,首先对数据调用pmt::cdr,这个函数在gnuradio-master\gnuradio-runtime\lib\pmt\pmt.cc中
查了一下,好像是有关梳理类型的转换和继承什么的,我不太熟悉,我这么写的原因是看很多模块都是这么写的,姑且先背下来,如果有哪位师傅知道请留言帮助补充,谢谢。
下面的函数也在gnuradio-master\gnuradio-runtime\lib\pmt\pmt.cc中,是一个类型检查。之后就是对广播信道的地址进行检查,
符合条件的,转变成字符串,去除头部的0x和尾部的L,并输出。
(2017,7,23)之后,我们开始解扰码。
我们现在先看一下解扰之后的效果:
我们先看看扰码的位置:
再读取了前导码之后和assess address之后,就是PDU包,PDU包整体是加扰的,我们先看看解扰码的序列生成:
这个生成器的初始bit详见蓝牙官方协议vol6的3.2,我写了一个简单的扰码生成序列,写的有点丑
他会生成一个二维数组,再解扰的时候,我直接调用这个二维数组作为查找表。
比起动态生成扰码序列,把值域和定义域都确定的函数做成查找表会节约很多耗时,我这里,大约可以节约0.3ms,占这个模块整体耗时的百分之60。
接下来,我们看看解完扰码之后的bit序列,下面是PDU包的定义:
前4bit是PDU类别,我们可以通过蓝牙官方协议确定这个包的种类。之前嗅探的是广播信道的数据包,所以很多是0000,这个代表是ADV_IND数据包,之后的RFU是保留位,为以后的预留,现在使用0代替,也就是说上图的第一个包,是有错的,之后是TxAdd和RxAdd,之后再说,之后的Length是表示长度,比如上文的第二个包,length是000110,LSB下是0b11000,就是24,表示整个PDU包不算PDU包头,有24个octets。
(2017,7,25)python模块异步输出
上面,我们已经留出了out端口用来输出,可是怎么进行输出呢?
比如,在我的流图中after_dewhite_str是我所需要从这个块输出的数据,类型位string,那么我需要首先
把它变成一个array类型,之后
after_dewhite_str就被通过异步的方式从模块中发送出去了
(2017,7,30)参数化函数
我们先来看一下一个可以被py脚本import导入的模块的流图应该是一个什么样子
在BLE中,有两个变量是很重要的,他们是Access Address和channel(信道编号),在链接过程中,Access Address会改变,而在跳频中,channel也会改变,所以我们需要在程序中留出动态设置他们的接口。
在流图中看起来,就是这个样子。
为了动态设置这两个参数,我们需要使用gr_modtool创建模块的时候对参数进行输入,
这样会在对这两个函数提供底层的支持,如果直接在已经创建好了的模块中修改,则会出现很多错误,很麻烦。
可以看到,_init_中在self之后多了两个参数,就是我们需要输入的,gr_modtool已经完成了底层的支持,在这里,我的channel是int型,而accaddr是string,这是为了在流图外更好的调用,所以进入模块之后要进行一些格式化,把最后的写入self.XXX,在后文就可以使用了。
在grc文件夹下的对应xml文件也需要进行修改,添加两个param标签。这样就完成了模块中的参数化。
接下来说一个小窍门,流图是没有办法完成跳频之类的任务的,它毕竟不如py脚本灵活,我们实际上是可以把流图作为一个py模块import进一个py脚本中的,这个时候,在使用流图生成py文件的时候,就需要大量的使用variable模块,下面是我给accaddr定义的variable模块。
ID是你需要代表的参数,value是值,但是,为什么我定义的accaddr是一个string,但是这里他是一int呢,
因为这个模块不支持string格式,支持string的我也没找到,所以只好用这种办法(逃。。。。)
好处是什么呢?
这样,我们就可以使用import XXX 来引入我们的流图,之后使用XXX.set_accaddr来在py脚本中动态改变这个值了,很方便。
现在我们已经可以动态改变流图的参数了,那么怎么获取数据呢,这时ZMQ异步消息机制就变得十分有用。
我们可以通过这种方式把grc流图中的数据送出来,进入消息队列。之后在py脚本中
先import gr_ble和zmq,之后在下面
进行一些设置,最后,函数socket.recv()的返回值就是流图中的数据了。
这里在使用的时候需要注意一下,由于channel是int,所以不能为空,如果空着流图会报错,而accaddr是string,控string是允许的,如果不填,流图不会报错,可是逻辑上是行不通的,运行会报错。使用其他模块的时候也要注意这一点。
(2017,8,3)模块动态参数支持
我之前以为模块会默认支持动态参数,可是在动态信道号设置的时候发现了解扰是有问题的,也就是跳频跳过去了,但是解扰信道号码没过去,换句话说,就是osm的源模块支持了动态参数而我自己的模块debugsink不支持,但是,这样我至少可以确定动态参数机制在grc中是支持的。
一般来说,动态参数有两种方式,第一是使用异步消息输入代替模块参数,就像我的grc流图中第二个模块那样,这样的好处是可以远程调用,但是我需要完成的是跳频,对之间精度要求比较高,我不知道zmq消息的时间精度,所以我使用了第二种方式。
gnuradio中提供了针对模块的回调机制,就是当发现参数被外部改变的时候,调用一个回调函数,在回调函数中完成对参数的动态设置。下面我说一下步骤。
首先,要在模块对应的xml文件中,在<make>块的下面,加入<callback>模块。(如果写在<make>上面,编译流图里就没这个模块,所以要注意一下顺序)
之后,在对应模块中要写这个两个回调函数,这两个回调函数有俩个参数(对于python模块),第一个是self,第二个是变量。
这样就完成了模块对动态参数的支持。对于C语言模块,gnuradio中有很多原生的模块都支持,可以参阅他们的代码。
(随时更新修改,爬虫网站上都是历史版本 http://www.cnblogs.com/backahasten/ 随时查看更新)
360独角兽实习,连载周记(gnuradio 低功耗蓝牙BLE 综合工具模块编写)的更多相关文章
- 低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端
低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端 Android对外模模式(peripheral)的支持 从Android5.0开始才支持 关键术语和概念 以下是关键BLE术语和 ...
- 深入浅出低功耗蓝牙(BLE)协议栈
深入浅出低功耗蓝牙(BLE)协议栈 BLE协议栈为什么要分层?怎么理解蓝牙"连接"?如果蓝牙协议只有ATT没有GATT会发生什么? 协议栈框架 一般而言,我们把某个协议的实现代码称 ...
- 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体解释
转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50909410 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体 ...
- 深入浅出讲解低功耗蓝牙(BLE)协议栈
详解BLE连接建立过程https://www.cnblogs.com/iini/p/8972635.html 详解BLE 空中包格式—兼BLE Link layer协议解析https://www.cn ...
- 低功耗蓝牙BLE之连接事件、连接参数和更新方法
转自:http://blog.csdn.net/zzfenglin/article/details/51304084 连接事件 在一个连接当中,主设备会在每个连接事件里向从设备发送数据包.一个连接事件 ...
- Android低功耗蓝牙(BLE)开发的一点感受
最近一段时间,因为产品的需要我做了一个基于低功耗蓝牙设备的Android应用,其中碰到了一些困难,使我深深体会到Android开发的难处:不同品牌,不同型号和不同版本之间的差异使得Android应用适 ...
- Android 低功耗蓝牙BLE 开发注意事项
基本概念和问题 1.蓝牙设计范式? 当手机通过扫描低功耗蓝牙设备并连接上后,手机与蓝牙设备构成了客户端-服务端架构.手机通过连接蓝牙设备,可以读取蓝牙设备上的信息.手机就是客户端,蓝牙设备是服务端. ...
- 低功耗蓝牙BLE [学习笔记]
手机设备会区分 "connecting" and "pairing" ,前者可以自动连接,后者则需要请求.BLE不再有pairing的麻烦,能直接连上目标设备, ...
- Android使用BLE(低功耗蓝牙,Bluetooth Low Energy)
背景 在学习BLE的过程中,积累了一些心得的DEMO,放到Github,形成本文.感兴趣的同学可以下载到源代码. github: https://github.com/vir56k/bluetooth ...
随机推荐
- Uncaught Error: Call to undefined function mcrypt_get_iv_size() 解决办法
函数 mcrypt_get_iv_size 在只在(PHP 4 >= 4.0.2, PHP 5, PHP 7 < 7.2.0, PECL mcrypt >= 1.0.0) 这几个版本 ...
- Shell脚本 一键重启
有个程序必须用 kill -9 pid号 关闭后,才能重新启动,每次都要手动查找pid号,麻烦容易出错,写个shell脚本 就三行很方便,自动查找pid号-关闭程序-重启程序 #!/bin/bas ...
- GO的方法值和方法表达式用法
手册上关于这块的解释感觉不是很详细清晰,经过几个示例自己总结了下这块的用法. 方法表达式:说简单点,其实就是方法对象赋值给变量. 这里有两种使用方式: 1)方法值:隐式调用, struct实例获取方法 ...
- JS正则表达式的创建、匹配字符串、转义、字符类、重复以及常用字符
正则表达式都是操作字符串的 作用:对数据进行查找.替换.有效性验证 创建正则表达式的两种方式: // 字面量方式 /js/ // 构造函数方式 regular expression new RegEx ...
- alpine安装telnet等工具
alpine确实是很精简,但是对于熟悉了centos和ununtu的个人来说,实在是不习惯. 因此,记录关于alpine的一些包安装,以及操作细节(逐渐补充). 1. telnet >>& ...
- ungetc--C语言中处理字符串常碰到的问题
如图,在学习C++速成课的时候发现了这个神奇的函数ungetc(),视频的UP主给的注释是将变量(字符串)中存放的字符退回给stdin输入流.这是什么意思 看UP主的函数 在上面getchar()是用 ...
- C#设计模式学习笔记:(6)适配器模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7640873.html,记录一下学习过程以备后续查用. 一.引言 从今天开始我们开始讲结构型设计模式,结构型设 ...
- 3Python脚本在linux环境下头文件解释
#!/usr/bin/python到底是什么意思 有这句的,加上执行权限后,可以直接用 ./ 执行,不然会出错,因为找不到 python 解释器. #!/usr/bin/python 是告诉操作系统执 ...
- day18 正则表达式初学
正则规则:客观存在的,世界上任何一种语言都能使用它. 在线测试网址:http://tool.chinaz.com/regex 正则语句:只和字符串相关,需要考虑的是:在同一个位置上可以出现的字符范围 ...
- 安装PHP到Ubuntu(APT)
运行环境 系统版本:Ubuntu 16.04.2 LTS 软件版本:PHP-5.6 硬件要求:无 安装过程 1.安装APT存储库 APT存储库由PPA提供. root@localhost:~# apt ...