在做藍(lán)牙開發(fā)的時(shí)候,基本上都需要對藍(lán)牙設(shè)備進(jìn)行升級。當(dāng)時(shí)藍(lán)牙模塊應(yīng)用的是CC2640又沾,查閱了許多空中升級的相關(guān)資料。在查閱的過程中熙卡,發(fā)現(xiàn)關(guān)于iOS藍(lán)牙開發(fā)空中升級的材料非常少(也可能是我沒找到)杖刷,TI公司也沒有提供iOS空中升級的源碼,只提供了Android的源碼git驳癌。于是參考了Android的OAD源碼滑燃,并結(jié)合《CC2640 BLE OAD User's Guide》,最終實(shí)現(xiàn)了OAD升級颓鲜。
- OAD升級涉及到的服務(wù)及特征值
- OAD Service: F000FFC0-0451-4000-B000-000000000000
1. FFC1 F000FFC1-0451-4000-B000-000000000000
2. FFC2 F000FFC2-0451-4000-B000-000000000000
- OAD Service: F000FFC0-0451-4000-B000-000000000000
Off-Chip OAD升級大致過程
升級前準(zhǔn)備:下載藍(lán)牙設(shè)備待升級的Bin文件表窘,稱之為Image
- 開啟OAD相關(guān)特征值的通知典予。
- App向藍(lán)牙設(shè)備發(fā)送Image的Metadata
- App得到響應(yīng)后,開始發(fā)送一塊Image block信息
- 得到響應(yīng)后繼續(xù)發(fā)送下一塊信息
- 直到所有的Image Block信息發(fā)送成功乐严,藍(lán)牙設(shè)備升級也就完成了熙参。
Off-Chip OAD升級詳解
-
開啟OAD相關(guān)特征值的通知。
為了能夠得到藍(lán)牙設(shè)備的響應(yīng)信息開啟FFC1,FFC2的通知
-(void)configWithPeripheral:(CBPeripheral *)peripheral characteristics:(CBCharacteristic *)characteristic{
if([characteristic.service.UUID.UUIDString isEqualToString:OADService]){
if([characteristic.UUID.UUIDString isEqualToString:OADFFC1]){
if(!characteristic.isNotifying){
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
if([characteristic.UUID.UUIDString isEqualToString:OADFFC2]){
if(!characteristic.isNotifying){
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
if([characteristic.UUID.UUIDString isEqualToString:OADConfigNotifyCharacter]){
if(!characteristic.isNotifying){
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
}
-
App向藍(lán)牙設(shè)備發(fā)送Image的Metadata
(1)寫入到哪里麦备? FFC1負(fù)責(zé)接收Metadata孽椰,將Metadata寫入FFC1特征。 (2)如何得到Metadata? 需要根據(jù)Metadata數(shù)據(jù)格式自己生成凛篙。 CRC的生成方法是在Android源碼中找到的 Length為Image大小的1/4
- (Image_header)imageHeader{ Image_header image_header; image_header.crc0 = [self calcImageCRC:0]; image_header.crc1 = 0xffff; image_header.ver = 0; image_header.len = self.data.length / 4; image_header.uid[0] = image_header.uid[1] = image_header.uid[2] = image_header.uid[3] = 'E'; image_header.address = 0x1000 / 4; image_header.imgType = 1; image_header.state = 0xff; return image_header;
}
* 寫入成功后黍匾,藍(lán)牙設(shè)備會響應(yīng)第一個要寫入的Image Block塊數(shù),一般為0
(1)何為Image Block?
一個Block被規(guī)定為16個字節(jié)
比如:Image文件的大小為115k
115k*1024/16 = 7360塊
0就代表Image的前16個字節(jié)
(2)從哪里得到響應(yīng)信息呛梆?
因?yàn)镺ADService服務(wù)下已經(jīng)開啟了FFC2的通知锐涯,Block信息會從FFC2特征值響應(yīng)
(3)得到0后該如何做?
從Image提取第一塊Block填物,寫入FFC2特征纹腌。
(4)寫入Block的數(shù)據(jù)格式是什么?
2Byte + 16Bye = 18Byte
前兩個字節(jié)代表第幾個Block后16個字節(jié)表示Block內(nèi)容
requestData[0] = LO_UINT16(self.iBlocks);
requestData[1] = HI_UINT16(self.iBlocks);
memcpy(&requestData[2], &imageFileData[self.iBytes], OAD_BLOCK_SIZE);
[SPBLE writeNoResponseCharacteristic:currentPeripheral sCBUUID:self.oadServiceUUID cCBUUID:self.oadWriteUUID data:[NSData dataWithBytes:requestData length:(2 + OAD_BLOCK_SIZE)]];
* 得到響應(yīng)后繼續(xù)發(fā)送下一塊信息
寫入成功后會得到響應(yīng)1滞磺,從Image提取下一塊信息升薯,寫入 FFC2特征……直到所有的Block都寫入成功,升級結(jié)束击困。
(5)如何判斷升級成功涎劈?
升級完成后,藍(lán)牙設(shè)備會斷開連接阅茶,說明升級已成功了蛛枚。
通過代理可監(jiān)測升級進(jìn)度
@protocol SPBLEOADUpdaterDelegate <NSObject>
-(NSData *)updatedImage;
-(CBPeripheral *)updatedPeripheral;
-(void)updater:(SPBLEOADUpdater *)updater progress:(CGFloat)progress;
@end
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2286896-6e5be036a09cfdc1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
[源碼地址](https://github.com/somson/BLEOAD)