空中升级又叫固件升级,指你手机从服务器下载下来的包或者数据,通过蓝牙传输给你的外设升级固件。如果你能把蓝牙的基础搞懂,其实也并不是很难,我在这里只不过提供一下思路。

空中升级略难的地方在于数据处理和交互,尤其要以怎样简单完整的代码来实现数据的读写是重点,这就需要你和硬件工程师的交流和你自己的逻辑思维了。

在上代码以前,说一下有关蓝牙的传输速度的,因为我开发中碰到较大数据的传输,着实害我费了很多脑筋。
蓝牙数据传输中有连接延迟。其是为了低功耗考虑,允许从机在跳频过程中不理会主机的跳频指令,继续睡眠一段时间。而主机不能因为从机睡眠而认为其断开连接了。其是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蓝牙空中升级(固件升级)的更多相关文章

  1. nRF Connect SDK(NCS)/Zephyr固件升级详解 – 重点讲述MCUboot和蓝牙空中升级

    如何在nRF Connect SDK(NCS)中实现蓝牙空中升级?MCUboot和B0两个Bootloader有什么区别?MCUboot升级使用的image格式是怎么样的?什么是SMP协议?CBOR编 ...

  2. 如何实现蓝牙空中升级BLE OTA

    如何实现BLE OTA?什么叫DFU?如何通过UART实现固件升级?又如何通过USB实现固件升级?怎么保证升级的安全性?什么叫双备份(dual bank)DFU?什么叫单备份(single bank) ...

  3. iOS 蓝牙开发资料记录

    一.蓝牙基础认识:   1.iOS蓝牙开发:  iOS蓝牙开发:蓝牙连接和数据读写   iOS蓝牙后台运行  iOS关于app连接已配对设备的问题(ancs协议的锅)          iOS蓝牙空中 ...

  4. BLE空中升级 谈(二)

    BLE 空中升级谈 -- CC2541 的产品开发中OAD注意事项(续) TI CC2541支持多个硬件,多个软件对它进行空中升级,可以有不同的组合,硬件有 编号 名称 Hex 用法 1 Cc2540 ...

  5. https://github.com/coolnameismy/BabyBluetooth github上的一个ios 蓝牙4.0的库并带文档和教程

    The easiest way to use Bluetooth (BLE )in ios,even bady can use. 简单易用的蓝牙库,基于CoreBluetooth的封装,并兼容ios和 ...

  6. BLE空中升级 谈(一)

    BLE 空中升级谈 -- CC2541 的产品开发中OAD注意事项 现在的智能设备(可穿戴,智能家居,智能玩具等)是越来越多了,大公司的产品颜值高,功能强大而完备的应该说是比比皆是,这里不谈论它是满足 ...

  7. iOS蓝牙开发(二)蓝牙相关基础知识

    原文链接: http://liuyanwei.jumppo.com/2015/07/17/ios-BLE-1.html iOS蓝牙开发(一)蓝牙相关基础知识: 蓝牙常见名称和缩写 MFI ====== ...

  8. 改进iOS客户端的升级提醒功能

    改进iOS客户端的升级提醒功能 功能设计 先申明一下,我是码农,不是一个产品经理,但我觉得现有市面上的很多 App,设计的 "升级提示功能" 都不太友好.在此分享一下我的想法,欢迎 ...

  9. IOS应用程序升级

    IOS应用程序升级流程介绍:IOS手机端应用程序需要升级时,打开服务器端html文件(本文为ucab.html文件)->点击在线安装->打开plist文件(本文中为ucab.plist文件 ...

随机推荐

  1. oracle批量插入優化方案

    今天聽DBA説如果從一個表批量查詢出一批數據之後批量插入另外一張表的優化方案: 1)不寫歸檔日誌: 2)採用獨佔 關於insert /*+ append */我們需要注意以下三點: a.非歸檔模式下, ...

  2. Spring重复扫描导致事务失败的解决方案及深入分析

    问题及日志使用Spring和mybatis,然后配置事务,出现SqlSession was not registered for synchronization because synchroniza ...

  3. 使用Synchronized块同步方法

    synchronized关键字有两种用法.第一种就是在<使用Synchronized关键字同步类方法>一文中所介绍的直接用在方法的定义中.另外一种就是synchronized块.我们不仅可 ...

  4. bzoj4289 Tax

    Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边 ...

  5. 使用pytorch构建神经网络的流程以及一些问题

    使用PyTorch构建神经网络十分的简单,下面是我总结的PyTorch构建神经网络的一般过程以及我在学习当中遇到的一些问题,期望对你有所帮助. PyTorch构建神经网络的一般过程 下面的程序是PyT ...

  6. Jack--10天学会IOS大纲;注意将图片放大观看!

    第一天:磨刀霍霍期 耐得住性子好好熟悉和认识开发环境 ---------Jack/版权全部     认识开发环境         操作系统认识             Mac系统是苹果机专用系统.是基 ...

  7. OOP设计模式[JAVA]——04命令模式

    命令模式 命令模式的意图 命令模式属于对象的行为模式.别名又叫:Action或Transaction. 命令模式把一个请求或者操作封装到一个对象中.命令模式允许系统使用不同的请求把客户端参数化,对请求 ...

  8. [置顶] 九度笔记之 1494:Dota

    题目1494:Dota 1 秒 内存限制:128 兆 特殊判题:否 提交:559 解决:122 题目描述: 大家都知道在dota游戏中,装备是对于英雄来说十分重要的要素. 英雄们不仅可以购买单个的装备 ...

  9. 线程池框架executor

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  10. 能在xcode5中开发基于IOS7sdk的应用程序兼容ios4.3之后的系统吗?

    能在xcode5中开发基于IOS7sdk的应用程序兼容ios4.3之后的系统吗?