#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