iOS 通過藍牙給設備發送命令并接收回復信息

#import?<Foundation/Foundation.h>

#import?<CoreBluetooth/CoreBluetooth.h>

NS_ASSUME_NONNULL_BEGIN

#define kCharacteristicTXUUID @""

#define kCharacteristicRXUUID @""

#define kServicesID @""

@protocol EquipmentManagerDelegate <NSObject>

@optional

//發送命令返回的值

-(void)sendCommandABackWithdictionary:(NSDictionary *)dictionary;

-(void)sendCommandBBackWithdictionary:(NSDictionary *)dictionary;

-(void)sendCommandCBackWithdictionary:(NSDictionary *)dictionary;

-(void)sendCommandDBackWithdictionary:(NSDictionary *)dictionary byte2:(Byte)byte2;

-(void)sendCommandEBackWithdictionary:(NSDictionary *)dictionary;

//發送abc命令 一個循環

-(void)sendCommandABCForALoop;

//手機的的藍牙狀態

-(void)centralManagerDidUpdateWithState:(NSInteger )state;

//掃描到設備

-(void)scanToDeviceWithPeripheral:(CBPeripheral *)peripheral;

//連接失敗

-(void)failedToConnectDeviceWithPeripheral:(CBPeripheral *)peripheral;

@end

@interface EquipmentManager : NSObject

//中心設備管理

@property(nonatomic,strong)CBCentralManager *bluetoothManage;

//外圍設備

@property(nonatomic,strong)CBPeripheral *connectedPeripheral;

@property(nonatomic,strong)CBCharacteristic *characteristicTX;

@property(nonatomic,strong)CBCharacteristic *characteristicRX;

//是否連接

@property(nonatomic,assign)BOOL isConnection;

//命令

@property(nonatomic,strong)NSString *commandStr;

//命令是第幾個

@property(nonatomic,assign)NSInteger commandIndex;

//設備功率 設備編碼

@property(nonatomic,strong)NSArray *powerArr;

//當前設備對應的值

@property(nonatomic,strong)NSDictionary *equipmentData;

@property(nonatomic,weak)id <EquipmentManagerDelegate>delegate;

//掃描到的并存過本地的CBPeripheral 數組

@property(nonatomic,strong)NSArray *peripheralArray;

+(instancetype)shareCentralManager;

//停止鏈接

- (void)stopConnection;

//清除警告

-(void)clearAlarmWithIndex:(NSInteger)index;

//掃描設備

-(void)scanEquipment;

//停止掃描

-(void)stopScan;

//連接

-(void)connectPeripheralWithPeripheral:(CBPeripheral *)peripheral;

@end

.m文件

#import "EquipmentManager.h"

//#import <Bugly/Bugly.h>

@interface EquipmentManager ()<CBCentralManagerDelegate,CBPeripheralDelegate>

@property(nonatomic,assign)BOOL isManualPause;//手動暫停

@end

@implementation EquipmentManager

static EquipmentManager *_manager = nil;

+(instancetype)shareCentralManager{


? ? static?dispatch_once_toneToken;

? ? ? ? dispatch_once(&oneToken, ^{

? ? ? ? ? ? _manager= [[EquipmentManager alloc]init];

? ? ? ? });

? ? ? ? return_manager;

}

-(instancetype)init{

? ? if(self== [super?init]){

? ? ? ? [self?initData];

? ? }

? ? return self;

}

-(void)initData {

? ? self.bluetoothManage = [[CBCentralManager alloc]initWithDelegate:self queue:nil];



}

//掃描設備

-(void)scanEquipment{

//? ? BLYLogInfo(@"開始掃描設備");

? ? self.bluetoothManage.delegate = self;

? ? [self.bluetoothManage scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];

}

//停止鏈接

- (void)stopConnection

{

? ? self.isManualPause = YES;

? ? if(self.connectedPeripheral){

? ? ? ? [self.bluetoothManage cancelPeripheralConnection:self.connectedPeripheral];

? ? }

? ? self.isConnection = NO;

}

-(void)processingDataAWithdictionary:(NSDictionary*)oldDictionarycharacteristic:(CBCharacteristic*)characteristic{

//dataValue 接收發送命令的值

? ? NSData*dataValue= characteristic.value;

? ? if(dataValue.length!=17){

?? ? ? return;

?? }

//將返回的data拆分成對應的字符串字節數組

? ? NSArray*dataArr = [self?ConvertToNSString:dataValue];

//將dataArr里的字符串轉成Byte類型

? ? Byte byte[[dataValue length]];

? ? for(int?i =0; i< dataArr.count; i++) {

? ? ? ? NSString*str = [NSString stringWithFormat:@"0x%@",dataArr[i]];

//? ? ? ? NSLog(@"str===%d=%@",i,str);

? ? ? ? intstr_value;

? ? ? ? char *str_char = [str cStringUsingEncoding:NSASCIIStringEncoding];

? ? ? ? sscanf(str_char,"%x",&str_value);

? ? ? ? byte[i] = str_value;

? ? }

//CRC驗證

? ??if((byte[15] &0xff) != [self?getCrcCode:byte] ){

? ? ? ? return;

? ? }

//處理藍牙發過來的數據處理

? ? NSMutableDictionary *data = [NSMutableDictionary dictionaryWithDictionary:oldDictionary];

? ? self.equipmentData= data;

? ? if(self.delegate&& [self.delegaterespondsToSelector:@selector(sendCommandABackWithdictionary:)]){

? ? ? ? [self.delegate sendCommandABackWithdictionary:data];

? ? }

}


//VC調用命令后發送給藍牙

-(void)setCommandStr:(NSString*)commandStr{

? ? _commandStr= commandStr;

? ? [self sendMsgWithSubPackage:_commandStr];

}

//清除警告 向藍牙設備發送命令

-(void)clearAlarmWithIndex:(NSInteger)index{

//? ? BLYLogInfo(@"clearAlarmWithIndex======%ld",index);

? ? if(!self.characteristicRX){


? ? ? ? return;

? ? }

?Byte byteArr[] = {};

? ? ? ? ? ? NSData*data = [[NSData alloc]initWithBytes:byteArrlength:16];

[self.connectedPeripheral writeValue:data forCharacteristic:self.characteristicRX type:(CBCharacteristicWriteWithResponse)];

}

//停止掃描

-(void)stopScan{

//? ? BLYLogInfo(@"停止掃描");

? ? [self.bluetoothManage stopScan];

}

//連接

-(void)connectPeripheralWithPeripheral:(CBPeripheral *)peripheral{

? ? if(peripheral){

? ? ? ? self.connectedPeripheral= peripheral;

? ? ? ? self.connectedPeripheral.delegate = self;

? ? ? ? NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey];

//? ? ? ? BLYLogInfo(@"連接設備====%@=====UUIDString=%@",peripheral.name,peripheral.identifier.UUIDString);

? ? ? ? //1,連接藍牙

? ? ? ? [self.bluetoothManage connectPeripheral:? self.connectedPeripheral options:options];


? ? }

}

#pragma mark -----CBCentralManagerDelegate

- (void)centralManagerDidUpdateState:(CBCentralManager *)central{

? ? if(self.delegate&& [self.delegaterespondsToSelector:@selector(centralManagerDidUpdateWithState:)]){

? ? ? ? [self.delegate centralManagerDidUpdateWithState:central.state];

? ? }

}

//2.實現已連接外設的回調 查找服務

-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{


? ? [self.connectedPeripheral discoverServices:nil];

? ? self.isConnection = YES;

? ? self.isManualPause = NO;

? ? NSLog(@"連接成功");

//? ? BLYLogInfo(@"連接成功====%@=====UUIDString=%@",peripheral.name,peripheral.identifier.UUIDString);


}

// 斷開鏈接設備

-(void)centralManager:(CBCentralManager*)centraldidDisconnectPeripheral:(CBPeripheral*)peripheralerror:(NSError*)error{


? ? NSLog(@"斷開連接");

//? ? BLYLogWarn(@"斷開連接====%@=====UUIDString=%@",peripheral.name,peripheral.identifier.UUIDString);

? ? self.connectedPeripheral = nil;

? ? self.isConnection = NO;

? ? if(self.isManualPause == NO){

? ? ? ? if(self.delegate&& [self.delegaterespondsToSelector:@selector(failedToConnectDeviceWithPeripheral:)]){

? ? ? ? ? ? [self.delegate failedToConnectDeviceWithPeripheral:peripheral];

? ? ? ? }

? ? }




}

// 2.1未能連接的處理方法

-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{

? ? NSLog(@"連接失敗=========%@,(%@)",peripheral,[errorlocalizedDescription]);

//? ? BLYLogWarn(@"連接失敗====%@=====UUIDString=%@",peripheral.name,peripheral.identifier.UUIDString);

? ? self.isConnection = NO;

? ? if(self.delegate&& [self.delegaterespondsToSelector:@selector(failedToConnectDeviceWithPeripheral:)]){

? ? ? ? [self.delegate failedToConnectDeviceWithPeripheral:peripheral];

? ? }

}

-(void)centralManager:(CBCentralManager*)centraldidDiscoverPeripheral:(CBPeripheral*)peripheraladvertisementData:(NSDictionaryid> *)advertisementDataRSSI:(NSNumber*)RSSI{



? ? if(peripheral.name.length!=0){

//? ? ? ? NSData *data = [advertisementData objectForKey:@"kCBAdvDataManufacturerData"];

//

//? ? ? ? NSString *astr = [self hexadecimalString:data];

//? ? ? ? if(!astr){

//? ? ? ? ? ? return;

//? ? ? ? }

//? ? ? ? BLYLogInfo(@"掃描到設備====%@=====UUIDString=%@",peripheral.name,peripheral.identifier.UUIDString);


? ? ? ? if(self.delegate&& [self.delegaterespondsToSelector:@selector(scanToDeviceWithPeripheral:)]){

? ? ? ? ? ? [self.delegate scanToDeviceWithPeripheral:peripheral];

? ? ? ? }



? ? }



}

#pragma mark -------------------CBPeripheralDelegate

/**

?*? 3.發現服務就會調用代理方法

?*

?*? @param peripheral 外設

?*/

-(void)peripheral:(CBPeripheral*)peripheraldidDiscoverServices:(NSError*)error{

? ? // 掃描到設備的所有服務

? ? NSArray*services = peripheral.services;

? ? // 根據服務再次掃描每個服務對應的特征

? ? for(CBService*sesinservices) {

? ? ? ? if([ses.UUID.UUIDString isEqualToString:kServicesID]){

? ? ? ? ? ? [peripheraldiscoverCharacteristics:nil forService:ses];

? ? ? ? }

? ? }

}

/**

?*? 4.發現服務對應的特征

?*/

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{

? ? // 服務對應的特征

? ? NSArray*ctcs = service.characteristics;


? ? intcount =0;

? ? // 遍歷所有的特征

? ? for(inti =0; i < ctcs.count;i++) {

? ? ? ? CBCharacteristic*character = ctcs[i];

? ? ? ? // 根據特征的唯一標示過濾


? ? ? ? if([character.UUID.UUIDString isEqualToString:kCharacteristicRXUUID] ) {



? ? ? ? ? ? self.characteristicRX= character;

? ? ? ? ? ? [self.connectedPeripheral setNotifyValue:YES forCharacteristic:character];



? ? ? ? }

//? ? ? ? BLYLogInfo(@"服務特征===name=%@=====UUIDString=%@====.character.UUIDString=%@",peripheral.name,peripheral.identifier.UUIDString,character.UUID.UUIDString);

? ? ? ? if([character.UUID.UUIDString isEqualToString:kCharacteristicTXUUID]){

? ? ? ? ? ? self.characteristicTX= character;

? ? ? ? ? ? [self.connectedPeripheral setNotifyValue:YES forCharacteristic:character];

//? ? ? ? ? ? BLYLogInfo(@"服務特征正確===name=%@=====UUIDString=%@====.character.UUIDString=%@",peripheral.name,peripheral.identifier.UUIDString,character.UUID.UUIDString);

? ? ? ? ? ? [self sendMsgWithSubPackage:self.commandStr];

? ? ? ? }


? ? ? ? [peripheral discoverDescriptorsForCharacteristic:character];

? ? ? ? count++;

? ? }

? ? if(count == ctcs.count){

? ? ? ? if(self.characteristicTX == nil && self.characteristicRX == nil){

? ? ? ? ? ? [self?stopConnection];

? ? ? ? }

? ? }


}

-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{

? ? //? ? if(characteristic.isNotifying){

? ? [peripheralreadValueForCharacteristic:characteristic];

? ? //? ? }else{

? ? //? ? ? ? NSLog(@"Notification stopped on %@.? Disconnecting", characteristic);

? ? //? ? ? ? ? ? ? NSLog(@"%@", characteristic);

? ? //? ? ? ? [self.bluetoothManage cancelPeripheralConnection:peripheral];

? ? //? ? }

}

-(void)senderB{


}


#pragma mark - 中心接受外設信息,外設通知手機連接成功的時候并不會調用這個函數;手機向外設發送消息后,外設回應數據,這個函數會接受到數據。

-(void)peripheral:(CBPeripheral*)peripheral didUpdateValueForCharacteristic:(CBCharacteristic*)characteristicerror:(NSError*)error{

;

?? ? Byte* resultByte1 = (Byte*)[characteristic.valuebytes];


? ? if(resultByte1 ==NULL){

? ? ? ? return;

? ? }


? ? ? ? switch(self.commandIndex) {

? ? ? ? ? ? case1:

? ? ? ? ? ? {

? ? ? ? ? ? ? ? [self processingDataAWithdictionary:self.equipmentData characteristic:characteristic];

//命令1和命令2中間間隔300毫秒

? ? ? ? ? ? ? ? [self performSelector:@selector(senderB) withObject:nil afterDelay:0.3f];


? ? ? ? ? ? }

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case2:

? ? ? ? ? ? {

? ? ? ? ? ? ? ? [self processingDataBWithdictionary:self.equipmentData characteristic:characteristic];

? ? ? ? ? ? ? ? [self performSelector:@selector(senderC) withObject:nil afterDelay:0.3f];


? ? ? ? ? ? }

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case3:

? ? ? ? ? ? {

? ? ? ? ? ? ? ? [self processingDataCWithdictionary:self.equipmentData characteristic:characteristic];

? ? ? ? ? ? ? ? if(self.delegate&& [self.delegaterespondsToSelector:@selector(sendCommandABCForALoop)]){

//1,2,3命令查詢后調用停止鏈接的回調

? ? ? ? ? ? ? ? ? ? [self.delegate sendCommandABCForALoop];

? ? ? ? ? ? ? ? }



? ? ? ? ? ? }

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case4:

? ? ? ? ? ? {

? ? ? ? ? ? ? ? [self processingDataDWithdictionary:self.equipmentData characteristic:characteristic];




? ? ? ? ? ? }

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case5:

? ? ? ? ? ? {

? ? ? ? ? ? ? ? [self processingDataEWithdictionary:self.equipmentData characteristic:characteristic];




? ? ? ? ? ? }

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? default:

? ? ? ? ? ? ? ? break;

? ? ? ? }


? ? //? ? NSLog(@"dataDic=====%@",dataDic);

? ? //? ? NSLog(@"resultByte=====%s",resultByte);

//? ? NSLog(@"resultByte1=====%s",resultByte1);

}

-(void)peripheral:(CBPeripheral*)peripheraldidWriteValueForCharacteristic:(CBCharacteristic*)characteristicerror:(NSError*)error{

? ? NSLog(@"didWriteValueForCharacteristic=====%ld",characteristic.properties);

? ? [self.connectedPeripheral readValueForCharacteristic:self.characteristicTX];

}

//向藍牙發送命令

-(void)sendMsgWithSubPackage:(NSString*)msg? {

//將命令轉成NSData格式發送

? ? NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];


? ? if(self.characteristicRX){

? ? ? ? [self.connectedPeripheral writeValue:data forCharacteristic:self.characteristicRX type:(CBCharacteristicWriteWithResponse)];

? ? }

}

-(NSArray *)peripheralArray{

? ? if(!_peripheralArray){

? ? ? ? _peripheralArray = [NSArray array];


? ? }

? ? return _peripheralArray;

}

//CRC驗證

-(uint16_t)getCrcCode:(Byte*)bytes{

//這里一定得用uint16_t 格式的,安卓用的int,之前仿安卓的用int,打印的CRC一直都是0,找了很長時間

? ? uint16_t CRC =0x0000000;

? ? uint16_t POLYNOMIAL =;


? ? for(inti =0; i<13; i++) {

? ? ? ? CRC ^= (bytes[i] <<8);

? ? ? ? for(intj =0; j <8; j++) {


//? ? ? ? ? ? NSLog(@"CRC=%d=======%x ",j,CRC);

? ? ? ? ? ? if((CRC &0x8000) !=0){

? ? ? ? ? ? ? ? CRC <<=1;

? ? ? ? ? ? ? ? CRC ^= POLYNOMIAL;


? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? CRC <<=1;

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? returnCRC &0xff;

}


//將data轉16進制

-(NSArray *)ConvertToNSString:(NSData *)data{


? ? NSMutableArray *mutArr = [NSMutableArray array];

? ? for(inti =0; i < data.length; i++) {

? ? ? ? NSData*lengthData = [data subdataWithRange:NSMakeRange(i,1)];//取得長度數據

? ? ? ? NSString* hexString = [self?convertDataToHexStr:lengthData];

? ? ? ? [mutArr addObject:hexString];

? ? }

? ? return?mutArr;

}

//將藍牙發送的數據data轉成NSString

- (NSString *)convertDataToHexStr:(NSData *)data{

? ? if(!data || [data length] ==0) {

? ? ? ? return@"";

? ? }

? ? NSMutableString*string = [[NSMutableString alloc]initWithCapacity:[data length]];

? ? [data enumerateByteRangesUsingBlock:^(constvoid*bytes,NSRangebyteRange,BOOL*stop) {

? ? ? ? unsigned?char*dataBytes = (unsigned?char*)bytes;

? ? ? ? for(NSInteger i =0; i < byteRange.length; i++) {

? ? ? ? ? ? NSString*hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) &0xff];

? ? ? ? ? ? if([hexStr length] ==2) {

? ? ? ? ? ? ? ? [string appendString:hexStr];

? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? [string appendFormat:@"0%@", hexStr];

? ? ? ? ? ? }

? ? ? ? }

? ? }];

? ? return?string;

}

@end

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容