【IOS】BLE-蓝牙空中升级(OAD)

作者: huasali | 来源:发表于2016-10-31 15:32 被阅读1533次

蓝牙为CC2541 ios升级蓝牙固件;

1.头文件

#import <CoreBluetooth/CoreBluetooth.h>

升级要用到的ID

#define BT_OAD_SERVICE @"F000FFC0-0451-4000-B000-000000000000"

#define BT_OAD_IMAGE_NOTIFY @"F000FFC1-0451-4000-B000-000000000000"

#define BT_OAD_IMAGE_BLOCK_REQUEST @"F000FFC2-0451-4000-B000-000000000000"

2.获取蓝牙列表,选择需要升级的蓝牙

3.获取所有的特征值,找到我们需要的通道,设置通道的模式为监测通道变化

[peripheral setNotifyValue:YES forCharacteristic:characteristic];

传过去所需的参数

[controller setCharacteristic_oad_1:connectDic[BT_OAD_IMAGE_NOTIFY]];通道1

[controller setCharacteristic_oad_2:connectDic[BT_OAD_IMAGE_BLOCK_REQUEST]]通道2

[controller setDetailItem:self.detailItem];//蓝牙CBPeripheral

4.指定蓝牙的代理和代理方法

self.detailItem.delegate = self;

//[characteristic.value bytes]

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error

5.选择要升级的文件(这里是本地)

NSString *filePathA = [[NSBundle mainBundle] pathForResource:@"ImageA"    ofType:@"bin"];

NSString *filePathB = [[NSBundle mainBundle] pathForResource:@"ImageB"   ofType:@"bin"];

oad_A_Data = [NSData dataWithContentsOfFile:filePathA];

oad_B_Data = [NSData dataWithContentsOfFile:filePathB];

if (row == 1) {

oadData = oad_A_Data;

[self sendBlueToothUP];

}else if (row == 2) {

oadData = oad_B_Data;

[self sendBlueToothUP];

}

6.开始进行蓝牙升级:

(1)发送一个字节数据来获取蓝牙设备的当前设备信息

- (void)sendBlueToothUP{

if (!self.characteristic_oad_1||!self.characteristic_oad_2) {

[[AlertShowView sharedInstance] showMessage:@"通道错误"];return;}

Byte byte[] = {};

NSData *data = [NSData dataWithBytes:byte length:sizeof(byte)];

[self.detailItem writeValue:data forCharacteristic:self.characteristic_oad_1 type:CBCharacteristicWriteWithResponse];

}

(2)在代理处接收返回数据

- (void)readValueWithCharacteristics:(CBCharacteristic *)characteristic andPer:(CBPeripheral *)peripheral{

NSLog(@"\\nreadValue-%@",characteristic.value);

if ([characteristic.UUID.UUIDString isEqualToString:BT_OAD_IMAGE_NOTIFY]) {

if (characteristic.value) {

[self compareVerWithCharacteristics:characteristic];}

}}

(3)处理接收的数据,如果版本不相同,就把本地文件的固件信息通过通道1发送过去;

固件信息包含的信息有:固件版本、固件长度、固件类型

- (void)compareVerWithCharacteristics:(CBCharacteristic *)characteristic{

Byte *Cvalue = (Byte *)[characteristic.value bytes];

Byte *Dvalue = (Byte *)[oadData bytes];

if ((Cvalue[0] & 0x01) != ( Dvalue[4] & 0x01)) {//对比版本信息

NSLog(@"可以升级");

x = 0;

Byte byte[] = {Dvalue[4],Dvalue[5],Dvalue[6],Dvalue[7],Dvalue[8],Dvalue[9],Dvalue[10],Dvalue[11]};//本地数据的固件信息

NSData *sendData = [NSData dataWithBytes:byte length:sizeof(byte)];

NSLog(@"%@",sendData);

[self.detailItem writeValue:sendData forCharacteristic:self.characteristic_oad_1 type:CBCharacteristicWriteWithResponse];

}else{

[[AlertShowView sharedInstance] showInView:self.view andMessage:@"版本相同"];

}}

(4)在代理处接收返回数据(如果成功会通过通道2返回数据)

- (void)readValueWithCharacteristics:(CBCharacteristic *)characteristic andPer:(CBPeripheral *)peripheral{

NSLog(@"\\nreadValue-%@",characteristic.value);

if ([characteristic.UUID.UUIDString isEqualToString:BT_OAD_IMAGE_NOTIFY]) {

if (characteristic.value) {

[self compareVerWithCharacteristics:characteristic];}

}else if ([characteristic.UUID.UUIDString isEqualToString:BT_OAD_IMAGE_BLOCK_REQUEST]){

if (characteristic.value) {

[self.detailItem setNotifyValue:NO forCharacteristic:characteristic];//第二中方法才需要

[self startSendData];//第二种方法

//[self sendDataWithCharacteristics:characteristic];//第一种方法

}}}

(5)处理数据,开始发送本地文件;收到的数据是需要发送数据的序号(0000-FFFF,高位在后;0000,0100,0200...FF00,0001,0101...)

此时有两种方法:

第一种是每次都通过接收到的序号来发送数据,就不需要改变蓝牙的发送和接收模式;

第二种是直接按照一定的间隔去发送数据;只要和硬件规定好时间就可以基本保证成功;

由于第一种方法的速度很慢,所以我选择的第二种方式;

(6)设置定时器,间隔时间20ms;由于是直接发送不需要返回所以选择CBCharacteristicWriteWithoutResponse的方式;

- (void)startSendData{

if (!sendTime) {

x = 0;

sendTime = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(sendData:) userInfo:nil repeats:YES];

}}

- (void)sendData:(NSTimer *)t{

Byte *Dvalue = (Byte *)[oadData bytes];

Byte byte[18];

for (int i = 0; i < 18; i++) {

if (i <= 1 ) {

byte[0] = x%256;

byte[1] = x/256;

}else{

if (i - 2 + x*16 < oadData.length) {

byte[i] = Dvalue[i - 2 + x*16];

}else{

byte[i] = 0xFF;

}}}

NSData *sendData = [NSData dataWithBytes:byte length:sizeof(byte)];

NSLog(@"\\n%ld - \\n%@",x,sendData);

[self.detailItem writeValue:sendData forCharacteristic:self.characteristic_oad_2 type:CBCharacteristicWriteWithoutResponse];

x++;

float sendValue = (float)x*16/(float)oadData.length;//进度条

self.textView.titleL.text = [NSString stringWithFormat:@"%.2f%%",sendValue*100];

[self.textView setCCCount:sendValue];

if (x*16 >= oadData.length) {//传输结束

[sendTime invalidate];

[self.textView setCCCount:1.0];

NSString *timeStr = [NSString stringWithFormat:@"升级完毕 时间%f",[[NSDate date] timeIntervalSinceDate:countTime]];

}}

(7)传输结束后,硬件设备会自启,蓝牙会断开;


demo没整理 见谅

https://github.com/huasali/blueToothDemo

相关文章

网友评论

  • 勇丶闯天涯:升级的逻辑是我这边分包依次发送,那边如果收到错误的包或者丢包时,就给我传这个包的index,然后我从这个包index继续往下发送。问题是发送间隔我设置20ms时,回传给我错误包的index次数很多,设置80ms就没收到了。这是为什么
  • d252286885d7:您好,请问下是否是把bin文件改为自己设备要升级的文件就可以进行升级了
  • 慢走体:您好,遇到一个问题:OAD中写入数据过程中如果设备意外断后(非关闭蓝牙开关的断开),可以重新连接到但是所有的通道特征都无法读取,整个蓝牙失控,开关蓝牙无法回复正常,需要关机开机才能回复正常,不知道您有没有遇到过这个问题,有没有什么解决方案?
  • d5188b1d5dc3:大神,看了你的代码,明白很多,难得的是提供代码,其他人都只是描述流程。:+1:
  • 流年_橙子:楼主 你是如何判断需要升级的 代码里的判断 (Cvalue[0] & 0x01) != ( Dvalue[4] & 0x01)) 是通用的还是只适合你这一个包
  • 09aea3c98ba8:楼主,我将demo中的固件换成我的固件后,选择C1特征进行升级,升级完成后没效果啊,蓝牙没有重启,用工具检查发现设备的固件版本没变,求指教!
  • 代码移动工程师:直接运行demo 给我的蓝牙设备升级不行,求教
    代码移动工程师:@huasali 输入框是不是要写什么指令吗?我没写指令然后点击发送,选择OAD ,选择bin 文件结果 打印didWrite(null)
    huasali:如果文件没错 就试试降低传输的速度 我那时候和硬件协商了速度 都调到了 最快
    huasali:demo 按照步骤 应该没问题 你看下是不是 文件有没有选错
  • jianshu小赵:写的还不错 666
    huasali:@XWDong 我都以为我是发种子了 https://github.com/huasali/blueToothDemo
    summer_code:楼主 求一份ble OAD升级的Demo 596175302@qq.com 非常感谢
  • astring:楼主你好,请问如何将本地.bin发送?求指教
    huasali:@astring x 就是发送的次数
    astring:@huasali 请问x是如何定义取出来的,谢谢
    huasali:-先用NSdata读 本地文件
    NSString *filePathA = [[NSBundle mainBundle] pathForResource:@"ImageA" ofType:@"bin"];
    oad_A_Data = [NSData dataWithContentsOfFile:filePathA];

    -在用字节发送 就好了
    Byte *Dvalue = (Byte *)[oadData bytes];
    Byte byte[18];
    byte[i] = Dvalue[i - 2 + x*16];
    NSData *sendData = [NSData dataWithBytes:byte length:sizeof(byte)];
    [self.detailItem writeValue:sendData forCharacteristic:self.characteristic_oad_2 type:CBCharacteristicWriteWithoutResponse];

本文标题:【IOS】BLE-蓝牙空中升级(OAD)

本文链接:https://www.haomeiwen.com/subject/wihputtx.html