如何开发BLE数据透传应用程序?什么是BLE service和characteristic?如何开发自己的service和characteristic?如何区分ATT和GATT?有没有什么工具可以对BLE设备进行压力测试?如何提高BLE设备的数据上传速度?本文将对以上问题进行解答。 在很多应用场合,BLE只是作为一个数据透传模块,即将设备端数据上传给手机,同时接收手机端下发的数据。本文将和大家一起,一步一步演示如何开发一个BLE透传应用程序。按照本文的说明,大家可以很快就实现一个BLE透传应用,BLE透传应用已经是BLE应用中比较复杂的一种,一旦大家掌握了BLE透传应用,其他BLE应用开发就更不在话下了。本文还会以BLE透传为例子,来解释BLE service和characteristic等概念,以帮助大家理解如何定义和开发自己的BLE service和characteristic等,从而彻底理解BLE协议栈中的ATT和GATT的运行原理。然后,本文还将手把手教大家如何提高BLE数据传输速度(蓝牙4.2的理论吞吐率大概为100kB/s,而我们实际达到了80kB/s,已经非常接近理论值)。最后,我们将告诉大家如何使用安卓版nRF Connect来对你的BLE设备进行压力测试,以测试设备的稳定性和可靠性。当然,文章的最后也会告诉大家如何找到安卓和iOS手机app开发参考代码。
1. 开发准备2. 运行Nordic ble_app_uart应用程序Nordic SDK已经提供了一个直接就可以编译和运行的数据透传应用程序:ble_app_uart,Nordic将BLE透传服务称为Nordic UART Service(NUS),所以在Nordic SDK中,NUS就是BLE透传服务。请按照如下步骤运行SDK自带的ble_app_uart程序: 1) 确认自己的芯片型号或者开发板。如果采用Nordic官方开发板的话,芯片型号和开发板编号对应关系如下: 这里我会以nRF52832开发板PCA10040为例来阐述整个开发过程,其他开发板与之类似,大家自己可以举一反三来开始自己的开发之旅。 2) 将开发板与PC机通过USB线相连,同时打开开发板电源(将左下角的拨位开关打到“ON”位置),打开桌面版nRF Connect,选择启动“Programmer”应用,由于驱动之前已经安装好了,设备可以立即识别成功。执行“full erase”操作,以擦除芯片原始内容 最后我们来看main循环,它只有一个函数: idle_state_handle,idle_state_handle先把需要打印的日志打印完,然后让系统进入idle状态(Nordic SoC spec称其为System ON状态),一旦有协议栈事件或者中断事件发生,系统将唤醒,以处理相关事件回调函数,然后再执行一遍idle_state_handle。注意:在idle状态下,蓝牙连接或者广播可以正常进行而不受影响,蓝牙连接或者广播都是周期性的,在一个周期中,蓝牙连接或者广播只持续很短一段时间(这段时间CPU有可能会退出idle状态),其余时间系统都是处于idle状态的,从而大大节省系统功耗。
7. 定制你的BLE数据透传应用程序7.1 BLE数据上传吞吐率如何快速的把大量数据上传给手机?这是一个很常见的应用场合,现在我们尝试去修改一下Nordic的原生例程,以实现最高的数据吞吐率。下面我们通过几种不同的方法来看看每种方法下它的吞吐率能到多少。 方法1:(通过宏METHOD1来开关)蓝牙spec规定,蓝牙连接间隔最小只能为7.5m,为了达到最高的吞吐率,我们创建一个timer,让其每7ms发一次数据,看一看此时吞吐率能达到多少。7ms中断服务函数代码如下所示: [u
通过查看nRF connect日志,你会发现此时不会发生丢包了,但吞吐率直接降到了1.6kB/s左右。 方法1+:(通过宏METHOD1_PLUS来开关)
然后我们把连接间隔设为尽可能小,以期提高吞吐率,如下: [url=][/url]
#ifdef CONN_INTERVAL_OPTIMIZ#define MIN_CONN_INTERVAL MSEC_TO_UNITS(8, UNIT_1_25_MS) #define MAX_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_1_25_MS)#endif[url=][/url]
这种方法吞吐率能达到10kB/s,但离我们的目标还是很远。 最后我们把connection event length extension和data length extension都打开(我们将在方法2+中详细阐述这2个有效提高吞吐率的利器),即定义如下宏:
可以看到吞吐率将达到70kB/s,这个吞吐率还是不错的。但仔细查看nRF connect日志,你会发现这种模式下还是有小概率事件会导致“丢包”发生,而且整个发送逻辑也不是很优化,为此我们想到了METHOD2. 方法2:(通过宏METHOD2来开关)ble_nus_data_send每次成功发送数据包,都会产生一个BLE_NUS_EVT_TX_RDY事件,收到这个事件后,再去调用ble_nus_data_send,丢包的情况就不会再发生了,核心代码如下所示: 大家可以自己去查看一下nRF Connect的数据log,这种方式是没有丢包的,但是打开RTT viewer,你会发现他的吞吐率低得可怜,只有1kB/s。 方法2+:(通过宏METHOD2_PLUS来开关)与方法1+类似,我们在方法2基础上,持续往发送buffer送数据直到返回值不为0,如下: 然后我们增加gap event length extension功能,gap event length跟connection event length两者意思差不多,都是为了实现一个连接间隔可以发或收多个包的目的。为了使能gap event length extension功能,首先将gap event length修改成一个合适的值,以使其尽可能占满整个连接间隔,如下将gap event length修改为30ms #define NRF_SDH_BLE_GAP_EVENT_LENGTH 24
然后我们再将连接间隔设为尽可能小,以保证上述connection event可以占据整个连接间隔: [url=][/url]
#ifdef CONN_INTERVAL_OPTIMIZE#define MIN_CONN_INTERVAL MSEC_TO_UNITS(8, UNIT_1_25_MS) #define MAX_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_1_25_MS)#endif[url=][/url]
同时我们使能connection event extension功能,如下: [url=][/url]
#ifdef EVT_LEN_EXT_ON ble_opt_t opt; memset(&opt, 0x00, sizeof(opt)); opt.common_opt.conn_evt_ext.enable = true; err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt); APP_ERROR_CHECK(err_code);#endif[url=][/url]
我现在使用的是华为P9手机,它将把MTU设为241,在DLE不开的情况下(此时链路层每个数据包的长度还是只有27个字节!),我们可以看到throughput可以达到10kB以上,如下:
然后我们再打开DLE功能,此时链路层每个数据包的长度将变成251字节,如下: [url=][/url]
#ifdef DLE_ON case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: { NRF_LOG_DEBUG("DLE update request."); ble_gap_data_length_params_t dle_param; memset(&dle_param, 0, sizeof(ble_gap_data_length_params_t)); //0 means auto select DLE err_code = sd_ble_gap_data_length_update(p_ble_evt->evt.gap_evt.conn_handle, &dle_param, NULL); APP_ERROR_CHECK(err_code); } break;#endif[url=][/url]
此时我们可以看到throughput可以达到77kB/s,离蓝牙4.2的理论throughput已经很接近了。这里特别需要指出的是,当DLE使能情况下,connection interval不是越小吞吐率越高,我这里使用的connection interval大概为10ms,如果大家把这个connection interval提高到30ms,有可能吞吐率更高,这里就不再演示了。
上述代码工程已经上传到百度云盘中,有需要的同学可以到如下链接下载: 下载“tutorial_ble_app_uart_SDK15_0_0.rar”,然后解压缩到SDK15.0.0如下目录下:nRF5_SDK_15.0.0_a53641a\examples\ble_peripheral,即可成功编译运行。
7.2使用安卓版nRF connect测试BLE设备的稳定性和可靠性先说明一下,以下内容只能通过安卓版nRF Connect来实现,iOS版nRF Connect不支持如下特性。 手机端宏录制方式相信到现在大家对BLE数据上传机理和实践有个大概的了解,那如何测试BLE数据下行性能,即怎么测试数据从手机传到设备的稳定性和可靠性?我们是不是必须开发一款手机app来进行相关测试吗?答案是否定的,感谢Nordic给我们带来了nRF connect,nRF connect支持宏录制,我们可以通过nRF connect来对我们的设备进行压力测试。下面我们来讲讲宏录制是怎么工作的。 所谓宏录制,就是把你对nRF connect的操作录制下来,然后通过宏播放实现自动化操作。由于nRF connect是一个容器,并支持JavaScript和HTML语法,宏其实就是一个XML脚本,nRF connect定义了自己的一套XML标签操作,遵守这套XML标签操作,就可以对nRF connect进行自动化操作。nRF connect支持的所有XML语法都在手机安装目录\Nordic Semiconductor中的示例中体现,只要示例中出现过的标签就支持,相反示例中没有的标签就不支持。下面具体讲一下宏录制的操作过程。 当nRF connect连接设备成功后,你会发现右下角有一个红点,那个就是宏录制菜单。
点击下面的红点,我们开始宏录制操作
然后我们按照普通操作来操作nRF connect,这些操作最终对应的BLE指令会被录制下来,以便后续重复播放。我们先把“1234”发送给设备,如下:
发送完上述指令后,我们加一个300ms的延时,如下:
然后我们点击完成按钮,保存该宏,可以看出这个宏包括两条操作:发送“1234”到设备,然后睡眠300ms。
将宏命名为“test”并保存:
到此宏已经录制成功了,现在我们开始展示宏的神奇功能。如下,选择循环播放模式,然后点击“开始”按钮开始循环播放该录制宏。
大家可以看到,nRF connect先执行“Write 0x31323334 to RX characteristic”,然后睡眠300ms,然后又执行“Write 0x31323334 to RX characteristic”,如此循环往复。打开串口助手,你会发现设备已经收到了手机发过来的一连串“1234”,如下。
我们把刚才的test宏导出为XML,看一看它到底长什么样: [url=][/url]
<macro name="test" icon="PLAY"> <assert-service description="Ensure Nordic UART Service" uuid="6e400001-b5a3-f393-e0a9-e50e24dcca9e"> <assert-characteristic description="Ensure RX Characteristic" uuid="6e40002-b5a3-f393-e0a9-e50e24dcca9e"> <property name="WRITE" requirement="MANDATORY"/> </assert-characteristic> </assert-service> <write description="Write 0x31323334 to RX Characteristic" characteristic-uuid="6e400002-b5a3-f393-e0a9-e50e24dcca9e" service-uuid="6e400001-b5a3-f393-e0a9-e50e24dcca9e" val
大家可以看到,宏就是一些XML标记,大家也可以在此基础上,去修改该XML文件,以实现更复杂的自动化测试,然后通过nRF connect把最新的XML文件装载进来,就可以自动播放了。
电脑端XML方式前面的宏录制方式,功能还是比较单一,如果要实现更复杂的自动化测试,可以通过在PC端执行XML脚本方式来实现。通过安卓调试工具ADB,我们可以直接通过PC来操作nRF connect,而nRF connect又能识别XML脚本,这样就可以让nRF connect按照XML脚本意图去执行相关自动化操作。nRF connect支持的所有XML语法都在手机安装目录中(手机内部存储/ Nordic Semiconductor目录)的示例中体现,只要示例中出现过的标签就支持,相反示例中没有的标签就不支持。
|