1. OAD升级机制
OAD升级有两个Bin格式文件 Image-A 和 Image-B
为了防止蓝牙升级
当在升级的时候,为了防止蓝牙升级出错,需要先查询当前蓝牙镜像 是 Image-A 还是 Image-B
如果当前是 A 就取 B文件去升级,否则 是B 就取 A文件去升级
FFC1 特征值用来发送查询版本信息 和 发送升级通知的蓝牙信息
分别发送 0 、1 给蓝牙设备
返回设备镜像信息如: <0204007c 42424242>
关于OAD运行机制 参考: http://blog.csdn.net/mirkerson/article/details/39007591
2.蓝牙镜像 类型 版本 大小查询
查询镜像信息的特征 Characteristic
#define BT_OAD_IMAGE_NOTIFY@"F000FFC1-0451-4000-B000-000000000000"
#define BT_OAD_IMAGE_BLOCK_REQUEST @"F000FFC2-0451-4000-B000-000000000000"
//FFC2 特征值用来传输升级信息
CBPeripheral *peripheral;
CBCharacteristic *characteristic_oad_1;
CBCharacteristic *characteristic_oad_2;
//蓝牙设备所以有特征值
NSDictionary *dic = [[BlueToothManagershareBluetoothManager]connectDic];
characteristic_oad_1 = [dicobjectForKey:BT_OAD_IMAGE_NOTIFY];
characteristic_oad_2 = [dicobjectForKey:BT_OAD_IMAGE_BLOCK_REQUEST];
[peripheralsetNotifyValue:YESforCharacteristic:characteristic_oad_1];
[peripheralsetNotifyValue:YESforCharacteristic:characteristic_oad_2];
3.发送查询蓝牙设备信息
Byte byte0[] = {0};
NSData *data0 = [NSDatadataWithBytes:byte0length:sizeof(byte0)];
[peripheralwriteValue:data0forCharacteristic:characteristic_oad_1type:CBCharacteristicWriteWithResponse];
sleep(1);
Byte byte1[] = {1};
NSData *data1 = [NSDatadataWithBytes:byte1length:sizeof(byte1)];
[peripheralwriteValue:data1forCharacteristic:characteristic_oad_1type:CBCharacteristicWriteWithResponse];
可写(0或1)、监听(返回8bytes数据)。
当写入0时若有8bytes数据返回,则说明当前硬件固件为镜像A,若写入0无返回数据,而写入1有8bytes数据返回,则说明当前硬件固件为镜像B。
Byte 0 和 Byte 1 表示 镜像的编译版本号 高低位要对调 应该为: 0402 => 4*16*16 + 2 = 1026
根据嵌入式对应的 应该再除以2 为编译版本号为513 (具体未去探究,知道的朋友告诉我下,暂时没明白。)
Byte 2 和 Byte 3 表示 镜像的大小 高低位要对调计算 应该为 : 7c00 => 7*16*16*16 + 12*16*16 = 31744 B
根据几个实际的bin文件 应该是 124KB 。 猜想应该是 31744 * 4 = 126976 B = 124 KB 。(知道的朋友告诉我下,暂时没明白。)
Byte 4 - Byte 7 表示 当前是B镜像 默认情况下,镜像A中这4bytes均为A的ASCII码(即4个0x41),而镜像B中均为B的ASCII码(即4个0x42)。
4.发送升级信息
根据3可以得知 设备是镜像A还是B 。
选择对应Bin文件 发送升级信息
NSString *filePathA = [[NSBundlemainBundle]pathForResource:@"IMAGE_A(8)"ofType:@"bin"];
oadData = [NSDatadataWithContentsOfFile:filePathA];
Byte *Dvalue = (Byte *)[oadDatabytes];
NSData *data = [oadDatasubdataWithRange:NSMakeRange(4,8)];
NSData *sendData = [NSDatadataWithBytes:bytelength:sizeof(byte)];
[peripheralwriteValue:sendDataforCharacteristic:characteristic_oad_1type:CBCharacteristicWriteWithResponse];
这里的截取oadData 4 —— 12 8个字节的信息 实际上是要升级包的包信息 发送给设备
比如要发送 A镜像 -> 发送 <0100007c 41414141>
在CBPeripheralDelegate
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullableNSError *)error
{
// 如果是返回的UUIDString 是升级的特征值 表示可以升级
if ([characteristic.UUID.UUIDStringisEqualToString:BT_OAD_IMAGE_BLOCK_REQUEST])
{
//启动定时器发送 升级文件 网上看了一些Demo说是 可以取消对这个特征值的监听 ()
[peripheralsetNotifyValue:NOforCharacteristic:characteristic];
[selfstartSendData];
}
}
5.分包发送升级文件
- (void)startSendData
{
if (!sendTime &&allowUpdate)
{
x =0;
// 这里以每秒 20ms 发送一个包 在iOS 20ms 没问题。 在安卓中 大于 50ms, 已经避免蓝牙拥堵造成升级失败。
sendTime = [NSTimerscheduledTimerWithTimeInterval:0.02target:selfselector:@selector(sendData:)userInfo:nilrepeats:YES];
}
}
- (void)sendData:(NSTimer *)t{
// 把Bin文件 转换成NSData 分包传输 每个包 为18个字节
// 前2个字节 表示包的索引 第几个Block 后16个字节表示 内容 。 固定
Byte *Dvalue = (Byte *)[oadDatabytes];
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 = [NSDatadataWithBytes:byte length:sizeof(byte)];
NSLog(@"\n%ld - \n%@",x,sendData);
[peripheralwriteValue:sendData forCharacteristic:characteristic_oad_2type:CBCharacteristicWriteWithoutResponse];
x++;
float sendValue = (float)x*16/(float)oadData.length;
NSLog(@"升级了 %.2f",x,sendValue);
// 此时设备蓝牙会断开
if (x*16 >=oadData.length) {
[sendTimeinvalidate];
NSLog(@"升级完毕");
}
}