蓝牙OTA升级。把OTA升级的大概步骤记录下,逻辑上OTA升级和常规发送数据是一样的,只是OTA固件包相对较大,所以需要将数据分割发送,每次发送20byte,在此需注意的是需要每次记录已发送的数据长度。
蓝牙扫描连接就不提了,这里从点击升级按钮开始
/*
点击升级按钮获取到固件文件的路径 并执行bluetoothManager 中的Update方法
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *publicDocumentsDir = [pathsobjectAtIndex:0];
NSString *Path = [publicDocumentsDirstringByAppendingPathComponent:tagartStr];
NSURL *fileURL = [NSURLURLWithString:[NSStringstringWithFormat:@"file://%@",Path]];
fileStr ; 传入的固件路径转为的URL
step 自定义的一个int属性 用来判断执行的步骤
Nextstep 自定义的一个int属性,用来记录所执行的步骤
block size ;定义的每轮发送数据的大小
用到的所有的UUID 由蓝牙工程师的协议给定
expectedValue 有蓝牙协议写定,写入数据后外设会返回相应的值,用此判断下一执行步骤
*/
- (void)OTAupdate:(NSURL *)fileStr{
CBService *service = [selffindServiceFromUUID:[selfIntToCBUUID:OTA_SERVICE_UUID]p:_peripheral];
if (!service) {
NSLog(@"Could not find service");
return;
}
CBCharacteristic *characteristic = [selffindCharacteristicFromUUID:[CBUUIDUUIDWithString:OTA_SERV_STATUS_UUID]service:service];
if (!characteristic) {
NSLog(@"Could not find characteristic");
return;
}
//重新订阅通知
[_peripheral setNotifyValue:YESforCharacteristic:characteristic];
fileData = [[NSDatadataWithContentsOfURL:fileStr] mutableCopy];
step = 1;
blockSize = 240;
[self doStep];
}
//最重要的步骤:按照蓝牙回调的值执行相应步骤和写入数据- (void)doStep {
switch (step) {
case 1: {
step = 0;
expectedValue =0x00;
nextStep =2;
//memoryType:蓝牙协议定义的类型 memoryBank:蓝牙协议定义
int _memDevData = (memoryType <<24) | (memoryBank &0xFF);
NSData *memDevData = [NSDatadataWithBytes:&_memDevData length:sizeof(int)];
//写入文件头
[self writeValue:[selfIntToCBUUID:OTA_SERVICE_UUID]characteristicUUID:[CBUUIDUUIDWithString:OTA_MEM_DEV_UUID]p:_peripheraldata:memDevData];
break;
}
case 2: {
int _memInfoData;
_memInfoData = (spiMISOAddress <<24) | (spiMOSIAddress <<16) | (spiCSAddress <<8) | spiSCKAddress;
NSData *memInfoData = [NSDatadataWithBytes:&_memInfoData length:sizeof(int)];
step = 3;
[self writeValue:[selfIntToCBUUID:OTA_SERVICE_UUID]characteristicUUID:[CBUUIDUUIDWithString:OTA_GPIO_MAP_UUID]p:self.peripheraldata:memInfoData];
break;
}
case 3: {
//固件数据打包
uint8_t crc_code =0;
const char *bytes = [fileDatabytes];
for (int i =0; i < [fileDatalength]; i++) {
crc_code ^= bytes[i];
}
[fileData appendBytes:&crc_code length:sizeof(uint8_t)];
chunkSize =20; //每次发送数据的大小
blockStartByte =0; //用于累加数据值
step = 4;
[self doStep];
break;
}
case 4: {
NSData *patchLengthData = [NSDatadataWithBytes:&blockSizelength:sizeof(UInt16)];
step = 5;
[self writeValue:[selfIntToCBUUID:OTA_SERVICE_UUID]characteristicUUID:[CBUUIDUUIDWithString:OTA_PATCH_LEN_UUID]p:self.peripheraldata:patchLengthData];
break;
}
case 5: {
step = 0;
expectedValue =0x00; //蓝牙协议给定,根据回调判断用
nextStep =5;
int dataLength = (int) [fileDatalength];
int chunkStartByte =0;
//判断已发送的数据长度
while (chunkStartByte <blockSize) {
int bytesRemaining =blockSize - chunkStartByte;
if (bytesRemaining <chunkSize) {
chunkSize = bytesRemaining;
}
char bytes[chunkSize];
[fileDatagetBytes:bytes range:NSMakeRange(blockStartByte + chunkStartByte,chunkSize)];
NSData *byteData = [NSDatadataWithBytes:&bytes length:sizeof(char)*chunkSize];
chunkStartByte += chunkSize;
if (chunkStartByte >=blockSize) {
blockStartByte +=blockSize;
int bytesRemaining = dataLength -blockStartByte;
if (bytesRemaining ==0) {
nextStep =6;
} elseif (bytesRemaining < blockSize) {
blockSize = bytesRemaining;
nextStep =4;
}
}
//这里是向蓝牙写入数据
[self writeValue:[selfIntToCBUUID:OTA_SERVICE_UUID]characteristicUUID:[CBUUIDUUIDWithString:OTA_PATCH_DATA_UUID]p:self.peripheraldata:byteData andResponseType:CBCharacteristicWriteWithoutResponse];
}
break;
}
case 6: {
step = 0;
expectedValue =0x00;
nextStep =7;
//发送文件尾
int suotaEnd =0xFE000000;
NSData *suotaEndData = [NSDatadataWithBytes:&suotaEnd length:sizeof(int)];
[self writeValue:[selfIntToCBUUID:OTA_SERVICE_UUID]characteristicUUID:[CBUUIDUUIDWithString:OTA_MEM_DEV_UUID]p:_peripheraldata:suotaEndData];
break;
}
case 7: {
UIAlertView *alert = [[UIAlertViewalloc] initWithTitle:@"Device has been updated"message:@"Do you wish to reboot the device?"delegate:selfcancelButtonTitle:@"No"otherButtonTitles:@"Yes, reboot",nil];
[alert setTag:1];
[alert show];
break;
}
case 8: {
break;
}
}
}
//==========coreBluetooth 回调#PRagma mark 写数据后回调
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@"写入成功===%zd",step);
if (step &&step != 7) {
[self doStep];
}
}
if ([characteristic.UUIDisEqual:[CBUUIDUUIDWithString:OTA_SERV_STATUS_UUID]]) {
char value;
[characteristic.valuegetBytes:&value length:sizeof(char)];
if (expectedValue !=0) {
if (value ==expectedValue) {
step =nextStep;
expectedValue =0;
[self doStep];
} else {
UIAlertView *alertView = [[UIAlertViewalloc] initWithTitle:@"Error"message:@"hehe"delegate:nilcancelButtonTitle:@"OK"otherButtonTitles:nil];
[alertView show];
expectedValue =0; // Reset
}
}
}
//********** 用到的一些方法- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
//这里重启设备
if (alertView.tag ==1) {
if (buttonIndex != alertView.cancelButtonIndex) {
// Send reboot signal to device
step = 8;
int suotaEnd =0xFD000000;
NSData *suotaEndData = [NSDatadataWithBytes:&suotaEnd length:sizeof(int)];
[self writeValue:[selfIntToCBUUID:OTA_SERVICE_UUID]characteristicUUID:[CBUUIDUUIDWithString:OTA_MEM_DEV_UUID]p:_peripheraldata:suotaEndData];
}
}
}
- (void) writeValue:(CBUUID*)serviceUUID characteristicUUID:(CBUUID*)characteristicUUID p:(CBPeripheral *)p data:(NSData *)data {
CBService *service = [selffindServiceFromUUID:serviceUUID p:p];
if (!service) {
NSLog(@"Could not find service");
return;
}
CBCharacteristic *characteristic = [selffindCharacteristicFromUUID:characteristicUUIDservice:service];
if (!characteristic) {
NSLog(@"Could not find characteristic");
return;
}
[_peripheral writeValue:data forCharacteristic:characteristictype:CBCharacteristicWriteWithResponse];
}
- (void) writeValue:(CBUUID*)serviceUUID characteristicUUID:(CBUUID*)characteristicUUID p:(CBPeripheral *)p data:(NSData *)data andResponseType:(CBCharacteristicWriteType)responseType
{
CBService *service = [selffindServiceFromUUID:serviceUUID p:p];
if (!service) {
NSLog(@"Could not find service ");
return;
}
CBCharacteristic *characteristic = [selffindCharacteristicFromUUID:characteristicUUIDservice:service];
if (!characteristic) {
NSLog(@"Could not find characteristic");
return;
}
[p writeValue:dataforCharacteristic:characteristic type:responseType];
}
- (CBService *) findServiceFromUUID:(CBUUID *)UUID p:(CBPeripheral *)p {
for(int i =0; i < p.services.count; i++) {
CBService *s = [p.servicesobjectAtIndex:i];
if ([selfcompareCBUUID:s.UUIDUUID2:UUID]) return s;
}
return nil;//Service not found on this peripheral
}
-(int) compareCBUUID:(CBUUID *) UUID1 UUID2:(CBUUID *)UUID2 {
char b1[16];
char b2[16];
[UUID1.data getBytes:b1];
[UUID2.data getBytes:b2];
if (memcmp(b1, b2, UUID1.data.length) ==0)return1;
else return0;
}
-(CBUUID *) IntToCBUUID:(UInt16)UUID {
UInt16 cz = [selfswap:UUID];
NSData *cdz = [[NSDataalloc] initWithBytes:(char *)&czlength:2];
CBUUID *cuz = [CBUUIDUUIDWithData:cdz];
return cuz;
}
-(UInt16) CBUUIDToInt:(CBUUID *) UUID {
char b1[16];
[UUID.data getBytes:b1];
return ((b1[0] <<8) | b1[1]);
}
- (UInt16) swap:(UInt16)s {
UInt16 temp = s <<8;
temp |= (s >> 8);
return temp;
}
-(CBCharacteristic *) findCharacteristicFromUUID:(CBUUID *)UUID service:(CBService*)service {
for(int i=0; i < service.characteristics.count; i++) {
CBCharacteristic *c = [service.characteristicsobjectAtIndex:i];
if ([selfcompareCBUUID:c.UUIDUUID2:UUID]) return c;
}
return nil;//Characteristic not found on this service
}
新闻热点
疑难解答