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

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

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

    NIO: Jdk 1.4+ New IO 面向通道和缓冲区 所在包:java.nio 执行流程: 数据总数由通道写入到buffer , 或者是从buffer写入通道 完全替换IO(面向流  单向的) ...

  2. 新手通过SVN向eclipse中导入项目注意事项

    该文章进行的前提是,jdk.eclipse.tomcat.maven已安装完成 要从svn上获取项目数据,首先要安装svn 1)通过help->installsoft->svn->a ...

  3. mysql存储引擎innodb、myisam区别

    MyISAM与InnoDB的区别是什么? 1. 存储结构 MyISAM:每个MyISAM在磁盘上存储成三个文件.第一个文件的名字以表的名字开始,扩展名指出文件类型..frm文件存储表定义.数据文件的扩 ...

  4. 2018 ACM 国际大学生程序设计竞赛上海大都会部分题解

    题目链接 2018 ACM 国际大学生程序设计竞赛上海大都会 下午午休起床被同学叫去打比赛233 然后已经过了2.5h了 先挑过得多的做了 .... A题 rand x*n 次点,每次judge一个点 ...

  5. KVM源代码阅读--内核版本3.17.4

    为了更加深入的学习虚拟化,因此我必须把KVM源代码搞清楚,这是一个必须要挖的坑.我会把自己的一些阅读的代码贴上来,可能会有理解不对的地方,希望和大家一起交流,请多提意见,以便于纠正错误.所用的内核版本 ...

  6. Codeforces Round #371 (Div. 2) C. Sonya and Queries 水题

    C. Sonya and Queries 题目连接: http://codeforces.com/contest/714/problem/C Description Today Sonya learn ...

  7. Ubuntu 中启用 root 帐号

    参考:http://linuxtoy.org/archives/howto_enable_ubuntu_root_account.html 如果你实在需要在 Ubuntu 中启用 root 帐号的话, ...

  8. 【Go命令教程】14. go env

    命令 go env 用于打印 Go 语言的环境信息.其中的一些信息我们在之前已经多次提及,但是却没有进行详细的说明.在本小节,我们会对这些信息进行深入介绍.我们先来看一看 go env 命令情况下都会 ...

  9. Programming 2D Games 读书笔记(第六章)

      http://www.programming2dgames.com/chapter6.htm 示例一:Bounce 边界碰撞测试 velocity为移动的速度, 超过右边界,velocity.x为 ...

  10. C#面向服务编程技术WCF从入门到实战演练

    一.WCF课程介绍 1.1.Web Service会被WCF取代吗? 对于这个问题阿笨的回答是:两者在功能特性上却是有新旧之分,但是对于特定的系统,适合自己的就是最好的.不能哪一个技术框架和行业标准作 ...