Android通过BLE传输文件
1、遇到的问题
公司要通过Android设备给外围设备的固件进行OTA升级,最开始想到的有两种方案。
1、将当前Android设备所连接 Wifi名称,WiFi密码通过BLE发送给外围设备。 外围设备拿到当前环境的WiFi名称和密码连接热点, 然后自己去服务器下载OTA文件,进行升级
2、当前Android设备和外围设备通过经典蓝牙进行传输OTA文件, 外围设备拿到OTA文件进行升级
但是很遗憾,外围设备既没有WiFi芯片, 也没有经典蓝牙芯片, 只有一颗BLE(低功耗蓝牙)芯片。 这意味着上面的两种方案都行不通。 那我们能不能通过BLE芯片来做文章, 来传输OTA文件?
BLE设计之初就是为了传输简单的指令的, 传输一些小数据的, 每次发送的数据大小不能超过20个字节。到底靠不靠谱啊?
2、 能不能通过BLE传输文件
让我们来问问 GPT 吧
GPT 的回答, 是可以通过BLE传输文件的, 由于BLE 每次传输的内容最大为20个字节, 传输大文件时就需要分包传输,
同时需要确保分包传输的可靠性和稳定性。
3、 如何传输文件
让 GPT 给我们一些示例代码
可以看出, 发送端分包批量发送数据,接收端
4、如何保证可靠性和稳定性
1、超时重传
蓝牙在传输过程中, 可能会存在丢包的情况。分两种情况,
1、Android设备发送的数据,外设设备没有收到。
2、Android设备发送的数据,外设设备收到了,并且发送了回复确认。 回复确认包Android设备却没有收到。
出现了这两种情况的任意一种, 则认为发生了丢包的情况。 Android 对这个包进行重发。
2、序列号
针对超时重传的第二种情况, 外设设备会收到两个相同的包。 但是外设设备不清楚是不是重装包。 这时就要给每个数据包添加序列号。 等外设设备收到两个相同序列号的数据包时, 丢弃这个数据包, 回复Android设备收到此包, 开始发送下一个数据包。
3、数据校验
BLE在传输的过程中, 如果周围环境有强蓝牙干扰,或者其他传输通道, 可能会导致数据包变更, 所以需要在数据包添加一个校验位, 这个校验位根据特定的算法,由数据包的数据计算得来。 外设设备收到数据后, 重新计算校验位, 判断数据传输过程是否出现差错, 如果计算的校验位和包传输的校验位不一致, 则要求Android设备重新发送这个包。
5、 传输速度提升 RequestMtu
为了保证传输过程中的可靠性和稳定性,我们需要在传输包中,添加序列号,数据校验等信息。 Android默认每个BLE数据包不超过20个字节,当我们加了一些其他信息时, 每次传输的有效数据可能只有15个字节左右。 导致在传输的过程中分包更多, 传输时间更长。
为了提升传输的速度, 我们来提升BLE每个数据包的传输大小限制, 使每个分包可以传输更多的数据。 系统为我们提供了 RequestMtu这个接口。 需要在gatt连接成功时调用
private val bluetoothGattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
super.onConnectionStateChange(gatt, status, newState)
if (newState == BluetoothGatt.STATE_CONNECTED) {
Log.d(TAG, "gatt 连接成功")
gatt?.requestMtu(40)
} else {
Log.d(TAG, "gatt 连接失败 status $status newstate $newState")
}
}
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
super.onMtuChanged(gatt, mtu, status)
if (BluetoothGatt.GATT_SUCCESS == status) {
Log.d(TAG, "onMtuChanged suc : $mtu")
gatt?.discoverServices()
} else {
Log.d(TAG, "onMtuChanged fail : $status")
}
}
}
MTU改变成功后, 再去gatt.discoverServices()发现服务
链接:https://juejin.cn/post/7226223658775298107
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。