iOS蓝牙空中升级(固件升级)
空中升级又叫固件升级,指你手机从服务器下载下来的包或者数据,通过蓝牙传输给你的外设升级固件。如果你能把蓝牙的基础搞懂,其实也并不是很难,我在这里只不过提供一下思路。
空中升级略难的地方在于数据处理和交互,尤其要以怎样简单完整的代码来实现数据的读写是重点,这就需要你和硬件工程师的交流和你自己的逻辑思维了。
在上代码以前,说一下有关蓝牙的传输速度的,因为我开发中碰到较大数据的传输,着实害我费了很多脑筋。
蓝牙数据传输中有连接延迟。其是为了低功耗考虑,允许从机在跳频过程中不理会主机的跳频指令,继续睡眠一段时间。而主机不能因为从机睡眠而认为其断开连接了。其是1.25毫秒一个单位。明显,这个数值越小,传输速度也高。
蓝牙BLE协议规定连接参数最小是5,即7.25毫秒;而Android手机规定连接参数最小是8,即10毫秒。iOS规定是16,即20毫秒。
连接参数完全由主机决定,但从机可以发出更新参数申请,主机可以接受也可以拒绝。Android手机一部接受,而ios比较严格,拒绝的概率比较高。
一般场景,连接参数设置16,即20毫秒,一般的传输速率是50* 20 = 1000字节/每秒。如果每个连接事件传输更多的包,可以获得更高的传输速率。
但是以上这种方法并不能真正解决传输的速度快慢,顶多也就相差2倍或者3倍。最好的方法就是在与app每次给蓝牙发送的包数,通畅可能考虑到数据不丢失,都是一包一包的发送,但是在空中升级这里不得已包数必须要多一点,比如一次发送十包,具体还是看你们硬件那边怎么写蓝牙协议了。
我下面的demo是这样的一个过程:
1.发送给外设指令,我要空中升级
->2.外设给我回OK之后我发送一个随机数(自定义了一种随机算法),验证开始固件升级
->3.判断随机数无误,准备发送打包好的数据
->4.真正发送打包好的数据(每次发送10包,一包20个字节),这里会重复N多次,看你的原数据包有多大;每次接到我发的包后,外设都会给我会OK否,我收到OK后才会发一下个数据包
->5.告诉外设我数据发送完毕,并发送一段指令(包括本次空中升级数据包的大小,还有加密参数什么的)
->6.外设给我回OK无误后,才算真正升级完成
//更新特征的value时调用
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
return;
}
//找到已经订阅的串口,输出看结果
if ([[characteristic.UUID UUIDString] isEqualToString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]) {
NSLog(@"返回的结果是 = %@",characteristic.value);
[_dataArray addObject:characteristic.value];
NSInteger arrayCount = _dataArray.count;
//蓝牙每次都会回三条数据
if (arrayCount%3 == 0) {
//返回的头
NSString *str=[[NSString alloc]initWithFormat:@"%@",_dataArray[arrayCount-3]];
/*第一种大情况
1.发送固件升级指令
2.发送随机数
3.验证随机数是否正确
*/
if ([str isEqualToString:@"<ab100000 00000000>"]) {
NSData * data2 = _dataArray[arrayCount-1];
NSString * string3 = [NSString stringWithFormat:@"%@",_dataArray[arrayCount-1]];
//keyHead
NSData * keyHead = [_dataArray[arrayCount-1] subdataWithRange:NSMakeRange(2, 1)];
NSString * keyHeadStr = [NSString stringWithFormat:@"%@",keyHead];
NSData * randomData1;
NSData * randomData2;
//随机数
if (data2.length == 7 ) {
randomData1 = [_dataArray[arrayCount-1] subdataWithRange:NSMakeRange(5, 1)];
randomData2 = [_dataArray[arrayCount-1] subdataWithRange:NSMakeRange(6, 1)];
}
//发起固件升级之后回的
if ([string3 isEqualToString:@"<01008204 00010000 00>"]) {
//写入随机数
[self.peripherale writeValue:self.randomData forCharacteristic:self.TX_Characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"写入的随机数 %@",self.randomData);
}
//写入随机数之后回的
if ([randomData1 isEqualToData:[_calculateRandom subdataWithRange:NSMakeRange(13, 1)]] && [randomData2 isEqualToData:[_calculateRandom subdataWithRange:NSMakeRange(14, 1)]] && [keyHeadStr isEqualToString:@"<06>"]){
//随机数验证成功
[self.peripherale writeValue:_successData forCharacteristic:self.TX_Characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"随机数验证成功");
}
//随机数验证成功之后
if ([string3 isEqualToString:@"<01000501 0080>"]) {
//发送第一包数据包
[self.peripherale writeValue:self.packArray[_sendNumber] forCharacteristic:self.TX_Characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"发送的包 %@",self.packArray[_sendNumber]);
_sendNumber++;
[self setValue:[NSString stringWithFormat:@"%d",_sendNumber] forKey:@"sendNumber"];
}
}
/*第二种大情况
1.校验发送的包是否收到了
2.取消升级
*/
else if ([str isEqualToString:@"<ab100000 00001000>"]) {
NSData * data3 = [_dataArray[arrayCount-1] subdataWithRange:NSMakeRange(0, 5)];
NSString * string3 = [NSString stringWithFormat:@"%@",data3];
if ([string3 isEqualToString:@"<01000804 00>"] && _sendNumber < self.allSection-1) {
//发送数据包
[self.peripherale writeValue:self.packArray[_sendNumber] forCharacteristic:self.TX_Characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"发送的包 %@",self.packArray[_sendNumber]);
_sendNumber++;
[self setValue:[NSString stringWithFormat:@"%d",_sendNumber] forKey:@"sendNumber"];
}
//发送至最后一包的时候
else if ([string3 isEqualToString:@"<01000804 00>"] && _sendNumber == self.allSection-1) {
[self.peripherale writeValue:self.lastData forCharacteristic:self.TX_Characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"发送了最后一条指令");
//确保进度条显示到100%
_sendNumber++;
[self setValue:[NSString stringWithFormat:@"%d",_sendNumber] forKey:@"sendNumber"];
//把包数重新归零
_sendNumber = 0;
NSLog(@"%lu %ld",(unsigned long)_dataArray.count,self.allSection);
}
}
/*第三种大情况
1.发送完毕 lastData 之后
*/
else if ([str isEqualToString:@"<ab100000 00000700>"]) {
NSString * string33 = [NSString stringWithFormat:@"%@",_dataArray[arrayCount-1]];
if ([string33 isEqualToString:@"<01008001 0000>"] && (_dataArray.count-9)/3 == self.allSection)
{
NSLog(@"蓝牙数据传输成功 %@",_dataArray.lastObject);
[DFULocalNotification registerLocalNotification:@"蓝牙数据传输完成"];
}
else if([string33 isEqualToString:@"<01008001 0000>"] == NO && (_dataArray.count-9)/3 == self.allSection)
{
NSLog(@"蓝牙数据传输错误 %@",_dataArray.lastObject);
[DFULocalNotification registerLocalNotification:@"蓝牙数据传输错误"];
}
}
}
}
}
重点就是在这个回调函数里面,至于其他的文件解读,加密,校验什么的我就不上代码了,主要还是给大家提供一种思路吧!
iOS蓝牙空中升级(固件升级)的更多相关文章
- nRF Connect SDK(NCS)/Zephyr固件升级详解 – 重点讲述MCUboot和蓝牙空中升级
如何在nRF Connect SDK(NCS)中实现蓝牙空中升级?MCUboot和B0两个Bootloader有什么区别?MCUboot升级使用的image格式是怎么样的?什么是SMP协议?CBOR编 ...
- 如何实现蓝牙空中升级BLE OTA
如何实现BLE OTA?什么叫DFU?如何通过UART实现固件升级?又如何通过USB实现固件升级?怎么保证升级的安全性?什么叫双备份(dual bank)DFU?什么叫单备份(single bank) ...
- iOS 蓝牙开发资料记录
一.蓝牙基础认识: 1.iOS蓝牙开发: iOS蓝牙开发:蓝牙连接和数据读写 iOS蓝牙后台运行 iOS关于app连接已配对设备的问题(ancs协议的锅) iOS蓝牙空中 ...
- BLE空中升级 谈(二)
BLE 空中升级谈 -- CC2541 的产品开发中OAD注意事项(续) TI CC2541支持多个硬件,多个软件对它进行空中升级,可以有不同的组合,硬件有 编号 名称 Hex 用法 1 Cc2540 ...
- https://github.com/coolnameismy/BabyBluetooth github上的一个ios 蓝牙4.0的库并带文档和教程
The easiest way to use Bluetooth (BLE )in ios,even bady can use. 简单易用的蓝牙库,基于CoreBluetooth的封装,并兼容ios和 ...
- BLE空中升级 谈(一)
BLE 空中升级谈 -- CC2541 的产品开发中OAD注意事项 现在的智能设备(可穿戴,智能家居,智能玩具等)是越来越多了,大公司的产品颜值高,功能强大而完备的应该说是比比皆是,这里不谈论它是满足 ...
- iOS蓝牙开发(二)蓝牙相关基础知识
原文链接: http://liuyanwei.jumppo.com/2015/07/17/ios-BLE-1.html iOS蓝牙开发(一)蓝牙相关基础知识: 蓝牙常见名称和缩写 MFI ====== ...
- 改进iOS客户端的升级提醒功能
改进iOS客户端的升级提醒功能 功能设计 先申明一下,我是码农,不是一个产品经理,但我觉得现有市面上的很多 App,设计的 "升级提示功能" 都不太友好.在此分享一下我的想法,欢迎 ...
- IOS应用程序升级
IOS应用程序升级流程介绍:IOS手机端应用程序需要升级时,打开服务器端html文件(本文为ucab.html文件)->点击在线安装->打开plist文件(本文中为ucab.plist文件 ...
随机推荐
- 日志回滚:python(日志分割)
日志回滚:python 什么是日志回滚? 答: 将日志信息输出到一个单一的文件中,随着应用程序的持续使用,该日志文件会越来越庞大,进而影响系统的性能.因此,有必要对日志文件按某种条件进行切分,要切分日 ...
- android 进程间通信 messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯? android 消息机制 进程间 android 进程间 可以用 handler么 messenger 与 handler 机制 messenger 机制 是不是 就是 handler 机制 或 , 是不是就是 消息机制 android messenge
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯 ...
- hdu CA Loves GCD(dp)
一道我想骂人的题,差点把我气炸了. 题意: 求一个数的集合中(非多重集,每个数只出现一次)所有子集的gcd的和.结果MOD10^8+7输出. 输入输出不说了,自己看吧,不想写了. 当时我真把它当作数论 ...
- tomcat配置问题:访问http://localhost:8080/ 遇到 Access Error: 404
win7: 8080端口已经被其他应用使用,比如nixxxxxxxxxxxxx When I had an error Access Error: 404 -- Not Found I fixed i ...
- 2010-2011 ACM-ICPC, NEERC, Moscow Subregional Contest Problem K. KMC Attacks 交互题 暴力
Problem K. KMC Attacks 题目连接: http://codeforces.com/gym/100714 Description Warrant VI is a remote pla ...
- $.ajax 方法参数总是记不住,在这里记录一下
jquery中的ajax方法参数总是记不住,这里记录一下. 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为String类型的参数,请求方式(p ...
- Java常用加密方案及实现——AES和DES
AES和DES都是对称加密算法,其中DES全称为Data Encryption Standard,AES全称为Advanced Encryption Standard即高级加密标准. DES现在已经不 ...
- 设置Azure WebSite黑白名单
Azure WebSite服务默认是不提供黑白名单,也就是说任何Internet用户都可以访问Azure WebSite,那么我们如何来给我们的网站设置黑白名单? 这里有一种方式,可以通过配置网站的配 ...
- IBM BR10i阵列卡配置Raid0/Raid1(转)
说明:IBM的阵列卡无论多旧多新操作步骤都基本差不多. RAID1的步骤: 开机自检过程中出现ctrl+c提示,按ctrl+c进入LSI Logic Config Utility v6.10.02.0 ...
- 一些收集的MikroTik RouterOS破解版虚拟机VMware
会不定期更新,也许后续自己来做,现在是收集.持续关注这个分享链接即可. 链接:https://pan.baidu.com/s/1j7ciesPm1yAgCJ26dLJ8sg 密码:i64w