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

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

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

    iOS 的最大特点就是运行时. 保证运行时的就是RunLoop 1.什么是RunLoop呢? 从字面理解就是:运行循环 引用下官方文档的介绍: A run loop is an event proce ...

  2. 循序渐进学.Net Core Web Api开发系列【11】:依赖注入

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...

  3. Xamarin iOS教程之使用按钮接接收用户输入

    Xamarin iOS教程之使用按钮接接收用户输入 Xamarin iOS使用按钮接接收用户输入 按钮是用户交互的最基础控件.即使是在iPhone或者iPad中,用户使用最多操作也是通过触摸实现点击. ...

  4. jquery获取系统当前时间

    //判断是否在前面加0function getNow(s) { return s < 10 ? '0' + s: s;} var myDate = new Date(); var year=my ...

  5. 堆排序的C++代码实现

    堆排序C++实现 堆排序的具体思路可以查看<算法导论>这本书,一下只提供笔者的C++实现代码,并且将笔者在编写程序的过程当中所遇到的一些细节问题拿出来作一番解释,希望能够对对堆排序有一个透 ...

  6. SlickOne 敏捷开发框架介绍(二) -- 多用户/多租户/SAAS软件基础框架实现

    前言:在应用于集团版客户或SAAS平台服务的业务系统中,流程管理系统需要支持多用户组织模型.其中包括角色数据.流程定义数据和流程实例数据的多用户标识绑定.本文旨在全面描述如何基于SlickOne敏捷开 ...

  7. CentOS 7搭建OpenVPN-Admin

    安装注意要点: 1.用户及目录权限 2.openvpn配置文件/etc/openvpn/server.conf,可以设置不同的转发模式等等 3.全程使用apache,不要用其它的如nginx这些,不然 ...

  8. Oracle绝对值函数

    1.绝对值:abs() select abs(-2) value from dual; 2.取整函数(大):ceil() select ceil(-2.001) value from dual;(-2 ...

  9. 酷播迷你flv,mp4网页视频播放器(CuPlayerMini)V2.2版[经典黑]演示实例

    酷播迷你flv,mp4网页视频播放器(CuPlayerMini)V2.2版[经典黑]演示实例 http://www.cuplayer.com/cu/FreeDown/

  10. Tomcat 负载均衡 及Session共享

    原文:https://www.sunjianhua.cn/archives/tomcat-high-availability.html 一.安装java环境 二.安装tomcat(apache-tom ...