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阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容