1. 程式人生 > >IOS Ble藍芽開發實現

IOS Ble藍芽開發實現

1.本篇博文闡述如何開發Ble藍芽。在藍芽中的一些常見服務,掃描,以及連結;

  • 主藍芽類檔案.h
  • 主藍芽類檔案.m
  • UUID檔案
  • 藍芽列表展示的檔案

一:引入Ble藍芽的框架<CoreBluetooth/CoreBluetooth.h>

BuleHelp.h

#import <Foundation/Foundation.h>
//匯入藍芽框架
#import <CoreBluetooth/CoreBluetooth.h>
#import "DeviceModel.h"
#import "Constants.h"
#import "CommonUserDefaults.h"
#import "CommonUtil.h"
#import "TempDB.h"

#define COMMAND_PACKET_MIN_SIZE  7

@interface BlueHelp : NSObject

//藍芽的裝置搜尋顯示在列表中
@property (nonatomic, strong) NSMutableArray <CBPeripheral*>*periperals;

//連線peripheral
@property(nonatomic,strong) CBPeripheral *peripheral;

//連線peripheral
@property(nonatomic,strong) CBPeripheral *selectperipheral;

//中心管理者
@property (nonatomic, strong) CBCentralManager *centerManager;

@property (nonatomic,strong) DeviceModel *deviceModel;

//裝置列表
@property (nonatomic,strong) NSMutableArray *deviceList;

@property (nonatomic,strong) NSMutableArray *commandArray;
//是否進行ota升級
@property (nonatomic) BOOL isOta;

@property (nonatomic) BOOL isWritePacketDataSuccess;

@property (strong,nonatomic) NSString * checkSumType;

/*!
 *  @property isApplicationValid
 *
 *  @discussion flag used to check whether the application writing is success
 *
 */
@property (nonatomic) BOOL isApplicationValid;
/*!
 *  @property checkSum
 *
 *  @discussion checkSum received from the device for writing a single row
 *
 */
@property (assign) uint8_t checkSum;

/*!
 *  @property startRowNumber
 *
 *  @discussion Device flash start row number
 *
 */
@property (nonatomic) int startRowNumber;

/*!
 *  @property endRowNumber
 *
 *  @discussion Device flash end row number
 *
 */
@property (nonatomic) int endRowNumber;

/*!
 *  @property siliconIDString
 *
 *  @discussion siliconID from the device response
 *
 */
@property (strong,nonatomic) NSString *siliconIDString;
/*!
 *  @property siliconRevString
 *
 *  @discussion silicon rev from the device response
 *
 */
@property (strong,nonatomic) NSString *siliconRevString;


//是否傳送資料
@property (nonatomic) BOOL isSendData;

@property (strong,nonatomic) CommonUtil *commonUtil;

@property (strong,nonatomic) TempDB *tempDB;

@property (strong,nonatomic) NSDate *currentDate;

//時間格式化
@property(strong,nonatomic) NSDateFormatter  *dateformatter;

@property(strong,nonatomic) NSString *deviceName;

//@property (nonatomic,strong) NSUserDefaults *userDefaults;

@property (nonatomic,strong) CommonUserDefaults *userDefaults;
//傳送溫度資料
@property (nonatomic,strong) CBCharacteristic *sendtempcharateristic;
//傳送OTA資料
@property (nonatomic,strong) CBCharacteristic *sendotacharateristic;
//高/低溫度資料
//@property (nonatomic,strong) CBCharacteristic *sendhighalarmcharateristic;
//
//@property (nonatomic,strong) CBCharacteristic *sendlowalarmcharateristic;
//ota
@property (nonatomic,strong) CBCharacteristic *senddfucharateristic;
//傳送字串'CR'清除機子上的最大值(3個位元組)
@property (nonatomic,strong) CBCharacteristic *senddcrstrateristic;
//傳送字串'PD'機子關機(3個位元組)
@property (nonatomic,strong) CBCharacteristic *senddoutstrateristic;
//靜音
@property (strong,nonatomic) CBCharacteristic *sendmutealarmcharateristic;
//calset
@property(strong,nonatomic) CBCharacteristic *sendcalsetcharateristic;
//intervaltime
@property(strong,nonatomic) CBCharacteristic *sendintervaltimecharateristic;
//alarmswitch
@property(strong,nonatomic) CBCharacteristic *sendalarmswitchcharateristic;
//tempunit
@property(strong,nonatomic) CBCharacteristic *sendtempunitcharateristic;

@property(strong,nonatomic) CBCharacteristic *sendlowalarmswitchcharateristic;

///<===============方法區塊=======================>
+ (id)sharedManager;

-(NSMutableArray *)getDeviceList;

-(NSMutableArray *)getPeriperalList;

-(void)startScan;
//連線藍芽
-(void)contentBlue:(int) row;
//斷開藍芽
-(void)disContentBle;

//斷開ota的藍芽連線
-(void)disContentOtaBle;

//溫度符號
-(void)writeTempUnit:(NSString *)value;

//寫入報警開關
-(void)writeAlarmSwitch:(NSString *)value;


//寫入mute alarm
-(void)writeMuteAlarm:(NSString *)value;

//寫入CR CLERVULE
-(void)writeClearCR:(NSString *)value;


//寫入interval time
-(void)writeIntervalTime:(NSString *)value;

//寫入cal set
-(void)writeCalSet:(NSString *)value;

//寫入裝置的開關按鈕
-(void)writeBluePD:(NSString *)value;

//寫入低溫報警
//-(void)writeLowAlarm:(NSString *)value;
//
////寫入高溫報警
//-(void)writeHighAlarm:(NSString *)value;

//OTA韌體升級 又稱為DFU
-(void)writeUpdateOTA:(NSString*)value;

-(void)writeBlueOTA:(NSString *)value;

-(void)wirteBlueOTAData:(NSData *)value;

-(void)writeLowAlarmSwitch:(NSString *)value;

-(void) discoverCharacteristicsWithCompletionHandler:(void (^) (BOOL success, NSError *error)) handler;

-(void)updateValueForCharacteristicWithCompletionHandler:(void (^) (BOOL success,id command,NSError *error)) handler;

-(void) stopUpdate;

-(void) setCheckSumType:(NSString *) type;

-(NSData *) createCommandPacketWithCommand:(uint8_t)commandCode dataLength:(unsigned short)dataLength data:(NSDictionary *)packetDataDictionary;

-(void) writeValueToCharacteristicWithData:(NSData *)data bootLoaderCommandCode:(unsigned short)commandCode;

/*
 * 停止掃描
 */
-(void)stopScan;

//是否是第一次連線裝置
@property(assign,nonatomic) BOOL isconnected;

//當前的時間
@property(nonatomic,assign) long currentTime;

@property(nonatomic,strong) NSString *macAddre;

@property(nonatomic,strong) NSString *macName;

-(void)disMainOtaBle;

@end

BuleHelp.m

//程式執行後,會自動呼叫的檢查藍芽的方法 並掃描藍芽的方法
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    if ([central state] == CBCentralManagerStatePoweredOff) {
        NSLog(@"CoreBluetooth BLE hardware is powered off");
    }
    else if ([central state] == CBCentralManagerStatePoweredOn) {
        NSLog(@"CoreBluetooth BLE hardware is powered on and ready");
        [self startScan];
    }
    else if ([central state] == CBCentralManagerStateUnauthorized) {
        NSLog(@"CoreBluetooth BLE state is unauthorized");
    }
    else if ([central state] == CBCentralManagerStateUnknown) {
        NSLog(@"CoreBluetooth BLE state is unknown");
    }
    else if ([central state] == CBCentralManagerStateUnsupported) {
        NSLog(@"CoreBluetooth BLE hardware is unsupported on this platform");
    }
}
/*
 * 程式執行的時候開始掃描
 */
-(void)startScan{
    _periperals = [[NSMutableArray alloc] init];
    _deviceList = [[NSMutableArray alloc] init];
    //2.利用中心裝置掃描外部裝置
    [_centerManager scanForPeripheralsWithServices:nil options:nil];
}

/*
 * 停止掃描
 */
-(void)stopScan{
    [_centerManager stopScan];
}
/*
 * 裝置中可以包含 Device addre地址 放在 key:kCBAdvDataManufacturerData中既可以得到
 * 1.硬體開發工程師 把地址寫入到裝置的廠家資訊中。
 */

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSS{
    //判斷如果陣列中不包含當前掃描到的外部裝置才儲存
    if (![_periperals containsObject:peripheral]){
        //包扣3種裝置 都需要去搜索
        if([peripheral.name containsString:@"TMW012BT"]||[peripheral.name containsString:@"OTA"]){
            NSLog(@"DATA: %@", advertisementData);
            NSArray *keys = [advertisementData allKeys];
            for (int i = 0; i < [keys count]; ++i) {
                id key = [keys objectAtIndex: i];
                NSString *keyName = (NSString *) key;
                NSData *value = [advertisementData objectForKey: key];
                
                if([keyName isEqualToString:@"kCBAdvDataManufacturerData"]){
                    NSLog(@"value is %@",value);
                    NSString *result = [self convertDataToHexStr:value];
                    NSLog(@"reslut is %@",result);
                    if(result!=nil&&result.length>4){
                        NSString *d = [result substringFromIndex:4];
                        NSLog(@"D IS %@",d);
                        // 小寫
                        //NSString *lower = [test lowercaseString];
                        // 大寫
                        NSString *upper = [d uppercaseString];
                        _macAddre = [NSString stringWithFormat:@"S/N:%@",upper];
                    }
                }
                
                if([keyName isEqualToString:@"kCBAdvDataLocalName"]){
                    NSString *aStr= (NSString*)value;
                    NSLog(@"astr is %@",aStr);
                    _macName = aStr;
                }
            }
            
            _deviceModel = [DeviceModel new];
            _deviceModel.deviceName = _macName;
            //藍芽地址
            _deviceModel.deviceAddre = _macAddre;
            
            int rssi = [RSS intValue];
            NSString *range = [NSString stringWithFormat:@"%d",rssi];
            NSString *rs = [NSString stringWithFormat:@"RSSI %@dBm",range];
            //新增到裡面
            [self.periperals addObject:peripheral];
            _deviceModel.deviceRssi = rs;
            [_deviceList addObject:_deviceModel];
        }
    }
}

//解析廣播裡面的資料
-(void)getAdvertisementData:(NSDictionary<NSString *,id> *) advertisementData{
    NSArray *keys = [advertisementData allKeys];
    for (int i = 0; i < [keys count]; ++i) {
        id key = [keys objectAtIndex: i];
        NSString *keyName = (NSString *) key;
        NSObject *value = [advertisementData objectForKey: key];
        
        if([keyName isEqualToString:@"kCBAdvDataManufacturerData"]){
            printf("   key: %s\n", [keyName cStringUsingEncoding: NSUTF8StringEncoding]);
            NSString *values = (NSString *) value;
            NSLog(@"values is %@",values);
        }
    }
}
/*
 * 連線藍芽裝置給外部呼叫的方法
 * 傳入的是相對應的行數
 */
-(void)contentBlue:(int) row{
    [_centerManager connectPeripheral:_periperals[row] options:nil];
}


-(void)disContentBle{
    //關鍵的斷開藍芽  通知也要停止掉
    if((_peripheral!=nil && _sendtempcharateristic!=nil)){
        [_peripheral setNotifyValue:NO forCharacteristic:_sendtempcharateristic];
        [self disconnectPeripheral:_peripheral];
    }
}


/*
 * 斷開ota的 連線
 */
-(void)disContentOtaBle{
    if(_peripheral!=nil && _sendotacharateristic!=nil){
        [_peripheral setNotifyValue:NO forCharacteristic:_sendotacharateristic];
        [self disconnectPeripheral:_peripheral];
    }
}

-(void)disMainOtaBle{
    if(_peripheral!=nil){
        [self disconnectPeripheral:_peripheral];
    }
}

- (void) disconnectPeripheral:(CBPeripheral*)peripheral
{
    [_centerManager cancelPeripheralConnection:peripheral];
}
//連線成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    NSLog(@"連線成功");
    if(peripheral!=nil){
        //停止掃描 這個用於自動連線的時候
        [_centerManager stopScan];
        //裝置名稱
        _deviceName = peripheral.name;
        
        _selectperipheral = peripheral;
        
        peripheral.delegate = self;
        //再去掃描服務
        [peripheral discoverServices:nil];
       
    }
}
//連線失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
    NSLog(@"連線失敗,失敗原因:%@",error);
    NSString *disContentBlue = @"discontentblue";
    NSDictionary *blueDiscontent = [NSDictionary dictionaryWithObject:disContentBlue forKey:@"disconnect"];
    //傳送廣播 連線失敗
    [[NSNotificationCenter defaultCenter] postNotificationName:@"disNofiction" object:nil userInfo:blueDiscontent];
}
//斷開連線
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    NSLog(@"斷開連線");
    NSString *disContentBlue = @"discontentblue";
    //_blueiscon = @"Disconnect";
    NSDictionary *blueDiscontent = [NSDictionary dictionaryWithObject:disContentBlue forKey:@"disconnect"];
    //傳送廣播 連線失敗
    [[NSNotificationCenter defaultCenter] postNotificationName:@"disNofiction" object:nil userInfo:blueDiscontent];
}
//只要掃描到服務就會呼叫,其中的外設就是服務所在的外設
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    if (error){
        NSLog(@"掃描服務出現錯誤,錯誤原因:%@",error);
    }else{
        //獲取外設中所掃描到的服務
        for (CBService *service in peripheral.services){
            //拿到需要掃描的服務,例如FFF0 比如列印溫度資料
            //把所有的service打印出來
            //從需要的服務中查詢需要的特徵
            //從peripheral的services中掃描特徵
            [peripheral discoverCharacteristics:nil forService:service];
        }
    }
}
//只要掃描到特徵就會呼叫,其中的外設和服務就是特徵所在的外設和服務
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error{
    if(error){
        NSLog(@"掃描特徵出現錯誤,錯誤原因:%@",error);
    }else{
        //遍歷特徵,拿到需要的特徵進行處理
        for (CBCharacteristic *characteristic in service.characteristics){
            NSLog(@"characteristic is %@",characteristic.UUID);
            //如果是溫度資料處理
            if([characteristic.UUID isEqual:BOOT_TEMPVALUE_UUID]){
                //將全部的特徵資訊打印出來
                _isconnected = true;
                _peripheral = peripheral;
                _sendtempcharateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            //如果是ota進行ota升級
            else if([characteristic.UUID isEqual:BOOT_OTA_WIRTE_UUID]){
                _peripheral = peripheral;
                _sendotacharateristic = characteristic;
                //設定通知
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                _isOta = TRUE;
                [_userDefaults saveOta:_isOta];
                //[_ setBool:_isOta forKey:@"isOTA"];
                NSString *s = @"OTA";
                NSDictionary *tempOta = [NSDictionary dictionaryWithObject:s forKey:@"ota"];
                [[NSNotificationCenter defaultCenter] postNotificationName:@"tempOTA" object:nil userInfo:tempOta];
            }
            //CAL
            else if([characteristic.UUID isEqual:BOOT_CAL_UUID]){
                _sendcalsetcharateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            //interval time
            else if([characteristic.UUID isEqual:BOOT_INTERVALTIME_UUID]){
                _sendintervaltimecharateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            //Tempunit
            else if([characteristic.UUID isEqual:BOOT_TEMPUNIT_UUID]){
                _sendtempunitcharateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            
            //DFU
            else if([characteristic.UUID isEqual:BOOT_DFU_UUID]){
                _senddfucharateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            //傳送字串'CR'清除機子上的最大值(3個位元組)
            else if([characteristic.UUID isEqual:BOOT_CRSTRING_UUID]){
                _senddcrstrateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            //傳送字串'PD'機子關機(3個位元組)
            else if([characteristic.UUID isEqual:BOOT_OUTSTRING_UUID]){
                _senddoutstrateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            else{
                
            }
        }
    }
}

/*
    設定通知
 */
-(void)notifyCharacteristic:(CBPeripheral *)peripheral
             characteristic:(CBCharacteristic *)characteristic{
    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
    [_centerManager stopScan];
}

/*
    取消通知
 */
-(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral
                   characteristic:(CBCharacteristic *)characteristic{
    [peripheral setNotifyValue:NO forCharacteristic:characteristic];
}

/*
    接收資料解析
 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    //是否為Ota
    if(!self.isSendOta){
        if(self.readtempcharater == characteristic){
            NSString *tmpData = [self.cmUtil getTempTMWData:characteristic];
            if(tmpData!=nil){
                //開始處理資料
                NSArray *data = [tmpData componentsSeparatedByString:@","];
                TmpModel *tp = [[TmpModel alloc] init];
                tp.tmp = data[0];
                tp.max = data[1];
                tp.unit = data[2];
                //電量
                tp.bat = data[3];
                
                NSDictionary *tempDict = [NSDictionary dictionaryWithObject:tp forKey:@"tempData"];
                [[NSNotificationCenter defaultCenter] postNotificationName:@"tempNofiction" object:nil userInfo:tempDict];
                if([tp.bat isEqual:@"1"]){
                    //低電量廣播
                    NSDictionary *LowDict = [NSDictionary dictionaryWithObject:tp forKey:@"lowData"];
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"lowNofiction" object:nil userInfo:LowDict];
                }
            }
        }
    }
//======================寫入資料區塊========================//

/*
    寫入傳送時間
 */
-(void)writeIntervalTime:(NSString *)value periperalData:(CBPeripheral*)periperal{
    if(value!=nil&&periperal!=nil&&self.sendtimecharater!=nil){
        [self writeData:value forCharacteristic:self.sendtimecharater periperalData:periperal];
    }
}

/*
    寫入溫度單位
 */
-(void)writeTmpUnit:(NSString*)value periperalData:(CBPeripheral*)periperal{
    if(value!=nil&&periperal!=nil&&self.sendunitcharater!=nil){
        [self writeData:value forCharacteristic:self.sendunitcharater periperalData:periperal];
    }
}

/*
    寫入Cal值
 */
-(void)writeCalValue:(NSString *)value periperalData:(CBPeripheral*)periperal{
    if(value!=nil&&periperal!=nil&&self.sendcalcharater!=nil){
        [self writeData:value forCharacteristic:self.sendcalcharater periperalData:periperal];
    }
}


/*
    傳送Ota使得裝置進入Ota
 */
-(void)writeDfuValue:(NSString *)value periperalData:(CBPeripheral*)periperal{
    if(value!=nil&&periperal!=nil&&self.senddfucharater!=nil){
        [self writeData:value forCharacteristic:self.senddfucharater periperalData:periperal];
    }
}

/*
    傳送Max Temp實現清零選項
 */
-(void)writeClearValue:(NSString *)value periperalData:(CBPeripheral*)periperal{
    if(value!=nil&&periperal!=nil&&self.sendclearcharater!=nil){
        [self writeData:value forCharacteristic:self.sendclearcharater periperalData:periperal];
    }
}

/*
    傳送關機選項實現遠端開關機
 */
-(void)writeCloseValue:(NSString *)value periperalData:(CBPeripheral*)periperal{
    if(value!=nil&&periperal!=nil&&self.sendclosecharater!=nil){
        [self writeData:value forCharacteristic:self.sendclosecharater periperalData:periperal];
    }
}


/*
    所有寫入的資料處理
 */
-(void)writeData:(NSString *)value forCharacteristic:(CBCharacteristic *)characteristic periperalData:(CBPeripheral*)periperal{
    NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
    if(characteristic.properties & CBCharacteristicPropertyWriteWithoutResponse)
    {
        [periperal writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
    }else
    {
        [periperal writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }
}

此篇文章闡述到這,基本BLE藍芽開發實現都詳細的描述了。謝謝看官的閱讀…不要忘了點贊,你的贊是博主往後繼續更新IOS系列藍芽文章的最大動力,嚶嚶嚶…