iOS 蓝牙

iOS 开发蓝牙4.0的框架是CoreBluetooth

在CoreBluetooth中有两个主要的部分,Central(中心)和Peripheral(周边)。

CBPeripheralManager作为周边设备是服务器,CBCentralManager作为中心设备是客户端。所有可用的iOS 设备可以作为周边 也可以作为中央,但不可以同时既是周边也是中央。

一般手机是客户端(中心设备),设备(魔法棒)---->硬件设备,因为是手机去连接手环这个服务器的。周边(Peripheral)是生成或者保存了数据的设备,中心是使用这些数据的设备。

可以认为周边是一个广播数据的设备,他广播到外部世界说他这儿有数据,并且也说明了能提供的服务。另一边,中央开始扫描附近有没有服务,如果中央发现了想要的服务,然后中央就会请求连接周边,一旦连接成功,两个设备之间就开始交换数据了。

除了中央和周边,还要考虑两者交换的数据结构,这些数据在服务中被结构化,每个服务由不同的特征组成,特征是包含一个单一逻辑值的属性类型。


BLE-----------buletouch low energy , 蓝牙4.0设备耗电低

peripheral--外设  central 中心 发起连接的是central 被连接的设备是peripheral


service and characteristics -- 服务和特征 每个设备都会提供服务和特征,类似于服务端的API,但是机构不同。每个外设会有很多服务,每个服务中包含很多字段,这些字段的权限一般分为  读read 和写write ,通知notify几种,就是我们连接设备后具体需要操作的内容。

Description 每个characteristics可以对应一个或多个Descrition用户描述characteristics的信息或属性



蓝牙一般有两种不同的业务场景,一种叫做中心模式,就是以你的app作为中心,连接其他的外设的场景;另一种是外设模式,使用手机作为外设识别其他中心设备操作的场景。


蓝牙中心模式流程

1 建立中心角色

2 扫描外设

3 连接外设

4扫描外设中的服务和特征

4.1 获取外设的services

4.2 获取外设的Characteristics,获取characteristics的值,获取characteristics的Descriptor和Descriptor的值

5 与外设做数据交互

6 订阅characteristics的通知

7 断开连接(disconnect)


蓝牙外设模式流程

1 启动一个Peripheral管理对象

2 本地Peraipheral设置服务、特性、描述、权限等等

3 Peripheral发送广告

4 设置处理订阅、取消订阅、读Characteristic 写characteristics的委托方法



蓝牙设备的状态

CBCentralManagerStateUnknown ------ 初始化中

CBCentralManagerStateResetting ------ 设备不支持状态

CBCentralManagerStateUnsupported --------设备未授权状态

CBCentralManagerStateUnauthorized ---------设备未授权状态

CBCentralManagerStatePoweredOff -------- 尚未打开蓝牙

CBCentralManagerStatePoweredOn ----------蓝牙已经成功开启



蓝牙设备中的五种工作状态

准备 广播 监听扫描 发起连接  已连接


蓝牙外设模式

1 打开peripheralManager,设置peripheralManager的委托
2 创建characteristics,characteristics的description  创建service ,把characteristics添加到service中
3 开启广播advertising
4 对central的操作进行响应
     4.1 读characteristics请求
     4.2 写characteristics请求
      4.4 订阅和取消订阅characteristics



//

//  HB_BindStickViewController.m

//  HomeBridge

//

//  Created by Jason on 15/9/9.

//  Copyright (c) 2015 ___HB___. All rights reserved.

//


#import "HB_BindStickViewController.h"

#import <CoreBluetooth/CoreBluetooth.h>

#import "Header.h"



#define OPENBLUETOOTH 100

#define BINDSUCCESS 101

#define ALREADYBIND 102


@interface HB_BindStickViewController ()<UITableViewDataSource,UITableViewDelegate,CBCentralManagerDelegate,CBPeripheralDelegate,UIAlertViewDelegate>

@property (weak, nonatomic) IBOutlet UITableView *tableView;

@property (weak, nonatomic) IBOutlet UIView *bindView;

@property (nonatomic,retain) NSMutableArray * dataArray;


@property(nonatomic,retain)CBCentralManager * manager;

@property(nonatomic,retain)CBPeripheral * peripheral;

@property(nonatomic,retain)CBCharacteristic * characteristic;

@property(nonatomic,assign)NSInteger type;

@property (nonatomic,copy) NSString * teacherID;

@property (nonatomic,assign) BOOL isShowAlert;

//@property (nonatomic,copy) NSMutableString * macID;



@end


@implementation HB_BindStickViewController


- (void)viewDidLoad {

    [super viewDidLoad];

   

    if (!_dataArray) {

        _dataArray = [[NSMutableArray alloc]initWithCapacity:1];

    }

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

    

}

- (void)getUserInfoWithID:(NSString *)user_id{

//    HB_UserInfoModel * userinfo = [HB_UserInfoModel defaultManager];

    

    //判断是否相同_macID

    [HB_UserService customsGetPropWithUserId:[NSNumber numberWithInteger:[user_id integerValue]] tn:@"customs" field:@"rftoken" withBlock:^(NSDictionary *result, NSError *error) {

        if (result) {

            NSString * str = [result valueForKey:@"Content"];

            NSString * _macID = [[NSUserDefaults standardUserDefaults]stringForKey:@"macID"];

            if ([str isEqual:_macID]) {

                [self showAL:user_id];

            }else{

                [self Bindbluetooth];

            }

        }

    }];

}

- (void)showAL:(NSString *)user_id{

    NSString * val = [NSString stringWithFormat:@"%@",user_id];

    [HB_UserService customsGetPropWithUserId:[NSNumber numberWithInteger:[user_id integerValue]] tn:@"customs" field:@"phone" withBlock:^(NSDictionary *result, NSError *error) {

        if (result) {

            NSString * phone = [result valueForKey:@"Content"];

            [HB_UserService getUserInfo:@"id" Val:val More:@1 withBlock:^(NSDictionary *result1, NSError *error1) {

                if (result1) {

                    NSArray * item = [result1 valueForKey:@"Content"];

                    NSString * name;

                    if (item.count > 0 ) {

                        name = [[item objectAtIndex:0] valueForKey:@"name_zh"];

                    }

                    NSString * string = [NSString stringWithFormat:@"此设备已绑定到其他教师,如需使用请联系此教师解锁此设备\n%@联系电话:%@",name,phone];

                    UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"教棒已被使用" message:string delegate:self cancelButtonTitle:@"确定" otherButtonTitles: nil];

                    alertView.tag = ALREADYBIND;

                    if (!_isShowAlert) {

                        _isShowAlert = YES;

                        [alertView show];

                    }

                }

            }];

        }

    }];


}

- (IBAction)ScanBluetoothBtnClick:(UIButton *)sender {

    if (_manager.state != CBCentralManagerStatePoweredOn) {

        UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"开启蓝牙" message:nil delegate:self cancelButtonTitle:@"不开启" otherButtonTitles:@"开启", nil];

        alertView.tag = OPENBLUETOOTH;

        [alertView show];

    }else{

        [self.manager scanForPeripheralsWithServices:nil options:nil];

    }

}

//蓝牙状态改变

- (void)centralManagerDidUpdateState:(CBCentralManager *)central

{

    NSString * message;

    switch (central.state) {

        case 0:

            message = @"初始化中,请稍后……";

            break;

        case 1:

            message = @"设备不支持状态,过会请重试……";

            break;

        case 2:

            message = @"设备未授权状态,过会请重试……";

            break;

        case 3:

            message = @"设备未授权状态,过会请重试……";

            break;

        case 4:

            message = @"尚未打开蓝牙,请在设置中打开……";

            break;

        case 5:

            message = @"蓝牙已经成功开启,稍后……";

            break;

        default:

            break;

    }

}

//扫描到设备

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{

    NSLog(@"发现蓝牙设备:%@",peripheral.name);

    if (_dataArray.count == 0) {

        [_dataArray addObject:peripheral];

    }else{

        for (NSInteger i = 0 ; i < _dataArray.count; i++) {

            CBPeripheral * ph = _dataArray[i];

            if (i == _dataArray.count - 1 && ph != peripheral) {

                [_dataArray addObject:peripheral];

            }

        }

    }

    

    [_tableView reloadData];

    if ([peripheral.name isEqual:BLUETOOTHNAME]) {

        self.peripheral = peripheral;

    }

}


//连接成功

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

    peripheral.delegate = self;

    [central stopScan];

    [peripheral discoverServices:nil];

}


//返回的蓝牙服务通知通过代理实现

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

    for (CBService * service in peripheral.services) {

        if (error) {

            NSLog(@"Error changing notification state: %@",[error localizedDescription]);

            return;

        }

        NSLog(@"Service found with UUID :%@",service.UUID);

        NSLog(@"%@",service.UUID.UUIDString);

        //        if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FFE0"]]) {

        [peripheral discoverCharacteristics:nil forService:service];

        //        }

    }

}


//查找到该设备所对应的服务

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

    if (error) {

        NSLog(@"Error changing notification state: %@",[error localizedDescription]);

        return;

    }

    NSLog(@"%@",service.UUID.UUIDString);

    for (CBCharacteristic * characteristic in service.characteristics) {

        NSLog(@"查找到的服务(属性)%@",characteristic.UUID);

        NSString * str1 = characteristic.UUID.UUIDString;

        NSLog(@"哈哈哈哈哈哈哈哈%@",str1);

        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A23"]]) {

            [peripheral readValueForCharacteristic:characteristic];

        }

        //所对应的属性用于接收和发送数据

        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2AF0"]]) {

            [peripheral setNotifyValue:YES forCharacteristic:characteristic];

            [peripheral readValueForCharacteristic:characteristic];

        }

        //        NSLog(@"%@",string);

        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2AF1"]]) {

            _characteristic = characteristic;

//            [self Bindbluetooth];

            [self LookForID];

        }

    }

}



//接收数据的函数.处理蓝牙发过来得数据   读数据代理

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

    if (error) {

        NSLog(@"Error changing notification state: %@",[error localizedDescription]);

        return;

    }

     NSLog(@"---------%@",[characteristic UUID]);

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2AF0"]]) {

        NSLog(@"收到蓝牙发来的数据%@",characteristic.value);

        NSString * string = [self hexadecimalString:characteristic.value];

        if ([string isEqual:@"00"]) {

            [self LookForID];

            return;

        }

        if ([string isEqual:@"0000ff00ff00"]) {

            if (_type == 2) {

                [self contect];

            }

        }

        

        NSLog(@"%@",string);

        [self getUserIDWithString:string];

    }else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A23"]]){

        NSLog(@"收到蓝牙发来的数据%@",characteristic.value);

        NSString * string = [self hexadecimalString:characteristic.value];

        NSLog(@"##############################%@",string);

        NSMutableString * _macID = [[NSMutableString alloc]init];

        for (NSInteger i = string.length - 1 ; i >= 0 ; i-= 2) {

            NSString * sr = [string substringWithRange:NSMakeRange(i - 1, 2)];

            if (i== 1) {

//                sr = [NSString stringWithFormat:@"%d",[self to10:sr].integerValue - 16];

                sr = [self to16:[self to10:sr].integerValue - 16];

            }

            [_macID appendString:sr];

            if (i % 2 != 0 && i > 1) {

                [_macID appendString:@":"];

            }

        }

        [[NSUserDefaults standardUserDefaults]setValue:_macID forKey:@"macID"];

    }

}



//写数据代理

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

    sleep(3);

    NSLog(@"%@",characteristic.UUID);

    if (error) {

        NSLog(@"Error changing notification state: %@",[error localizedDescription]);

        [HB_Utils showItoast:@"绑定失败"];

    }

}



- (void)contect{

    NSString * _macID = [[NSUserDefaults standardUserDefaults]stringForKey:@"macID"];

    [HB_UserService customsEditWithUserId:[HB_UserInfoModel defaultManager].user_id tn:@"customs" field:@"rftoken" val:_macID withBlock:^(NSDictionary *result, NSError *error) {

        if (result) {

            UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"魔法棒绑定成功,可以鼓励孩子了!" message:nil delegate:self cancelButtonTitle:@"确定" otherButtonTitles: nil];

            alertView.tag = BINDSUCCESS;

            if (!_isShowAlert) {

                _isShowAlert = YES;

                [alertView show];

            }

            return;

        }

    }];

}

#pragma mark - NSData and NSString


//将传入的NSData类型转换成NSString并返回

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

    NSString* result;

    const unsigned char* dataBuffer = (const unsigned char*)[data bytes];

    if(!dataBuffer){

        return nil;

    }

    NSUInteger dataLength = [data length];

    NSMutableString* hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];

    for(int i = 0; i < dataLength; i++){

        [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];

    }

    result = [NSString stringWithString:hexString];

    return result;

}

//将传入的NSString类型转换成NSData并返回

- (NSData*)dataWithHexstring:(NSString *)hexstring{

    NSData* aData;

    return aData = [hexstring dataUsingEncoding: NSUTF16StringEncoding];

}

// 十六进制转换为普通字符串的。

- (NSString *)stringFromHexString:(NSString *)hexString { //

    

    char *myBuffer = (char *)malloc((int)[hexString length] / 2 + 1);

    bzero(myBuffer, [hexString length] / 2 + 1);

    for (int i = 0; i < [hexString length] - 1; i += 2) {

        unsigned int anInt;

        NSString * hexCharStr = [hexString substringWithRange:NSMakeRange(i, 2)];

        NSScanner * scanner = [[NSScanner alloc] initWithString:hexCharStr];

        [scanner scanHexInt:&anInt];

        myBuffer[i / 2] = (char)anInt;

    }

    NSString *unicodeString = [NSString stringWithCString:myBuffer encoding:4];

    NSLog(@"------字符串=======%@",unicodeString);

    return unicodeString;

}




- (NSString *)to10:(NSString *)num

{

    NSString *result = [NSString stringWithFormat:@"%ld", strtoul([num UTF8String],0,16)];

    return result;

}

- (NSString *)to16:(int)num

{

    NSString *result = [NSString stringWithFormat:@"%@",[[NSString alloc] initWithFormat:@"%1x",num]];

    if ([result length] < 2) {

        result = [NSString stringWithFormat:@"0%@", result];

    }

    return result;

    

}

- (void)LookForID{

    _type = 1;

    if(_characteristic == nil){

        NSLog(@"_characteristic 为空");

        return;

    }

    u_int8_t packet[7] = {0x00, 0x00, 0xFF, 0x03, 0x01, 0x04, 0x00};

    

    NSMutableData *value = [NSMutableData data];

    

    for (NSInteger i = 0; i < 7; i ++) {

        NSData * data ;

        data = [NSData dataWithBytes:&packet[i] length:1];

        NSLog(@"%02lx",(unsigned long)packet[i]);

        [value appendData:data];

    }

    NSLog(@"十六进制:%@",value);

    sleep(3);

    [_peripheral writeValue:value forCharacteristic:_characteristic type:CBCharacteristicWriteWithResponse];

    NSLog(@"已经向外设%@的特征值%@写入数据",_peripheral.name,_characteristic.description);

}

- (void)Bindbluetooth{

    _type = 2;

    if(_characteristic == nil){

        NSLog(@"_characteristic 为空");

        return;

    }

    u_int8_t packet[8] = {0x00, 0x00, 0xFF, 0x07, 0x02, 0x00, 0x00, 0x00};

//    u_int16_t str = 539;

//    NSString * m = [self to16:540];

    NSInteger userid = [[HB_UserInfoModel defaultManager].user_id integerValue];

//    NSLog(@"----%@",[self stringFromHexString:s]);

    NSData * idData = [NSData dataWithBytes:&userid length:4];

    const unsigned char* dataBuffer = (const unsigned char*)[idData bytes];

    NSMutableData * Data5= [NSMutableData data];

    NSInteger length = 0;

    for (NSInteger i = idData.length - 1; i >= 0; i --) {

        [Data5 appendData:[NSData dataWithBytes:&dataBuffer[i] length:1]];

        length += [[self to10:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]]integerValue];

    }

    NSLog(@"%@",Data5);

    

    NSInteger checkNum = length + 9;

    NSData * checkNumData = [NSData dataWithBytes:&checkNum length:4];

    const unsigned char* dataBuffer2 = (const unsigned char*)[checkNumData bytes];

    NSMutableData * Data6= [NSMutableData data];

    for (NSInteger i = 0; i < 1; i ++) {

        [Data6 appendData:[NSData dataWithBytes:&dataBuffer2[i] length:1]];

    }

    NSLog(@"%@",Data6);

    

    

    NSMutableData *value = [NSMutableData data];


    for (NSInteger i = 0; i < 8; i ++) {

        NSData * data ;

        if (i == 5) {

            data = Data5;

        }else if(i == 6){

            data = Data6;

        }else{

            data = [NSData dataWithBytes:&packet[i] length:1];

        }

        NSLog(@"%02lx",(unsigned long)packet[i]);

        [value appendData:data];

    }

    NSLog(@"十六进制:%@",value);

    sleep(3);

    

    [_peripheral writeValue:value forCharacteristic:_characteristic type:CBCharacteristicWriteWithResponse];

    NSLog(@"已经向外设%@的特征值%@写入数据",_peripheral.name,_characteristic.description);

}



#pragma mark -tableViewDelegate

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    return _dataArray.count;

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    CBPeripheral * peripheral = _dataArray[indexPath.row];

    

    //NSLog(@"%@",peripheral.RSSI);

    cell.textLabel.text = peripheral.name;

    if ([peripheral.name isEqual:BLUETOOTHNAME]) {

        cell.detailTextLabel.text = @"魔法棒";

    }else{

        cell.detailTextLabel.text = nil;

    }

    

    return cell;

}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    CBPeripheral * peripheral = _dataArray[indexPath.row];

    if ([peripheral.name isEqual:BLUETOOTHNAME]) {

        self.peripheral = peripheral;

        [self.manager connectPeripheral:self.peripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];

    }else{

        UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"选择的设备有误" message:nil delegate:self cancelButtonTitle:@"重新选择" otherButtonTitles: nil];

        [alertView show];

    }

}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

    return 44;

}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{

    return 0.01;

}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{

    return 0.01;

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

//应答回复

- (void)answerBack{

    if(_characteristic == nil){

        NSLog(@"_characteristic 为空");

        return;

    }

    u_int8_t packet[6] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};

    NSMutableData *value = [NSMutableData data];

    for (NSInteger i = 0; i < 6; i ++) {

        NSData * data = [NSData dataWithBytes:&packet[i] length:1];

        [value appendData:data];

    }

    NSLog(@"十六进制:%@",value);

    sleep(3);

    [_peripheral writeValue:value forCharacteristic:_characteristic type:CBCharacteristicWriteWithResponse];

    NSLog(@"已经向外设%@的特征值%@回复数据",_peripheral.name,_characteristic.description);

}

#pragma mark - alertViewDelegate

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{

    if (alertView.tag == OPENBLUETOOTH) {

        if (buttonIndex == 1) {

            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=Bluetooth"]];

        }

    }else if (alertView.tag == BINDSUCCESS){

        [[NSUserDefaults standardUserDefaults]setBool:YES forKey:ISBINGING];

        if ([self.delegate respondsToSelector:@selector(updateUIWithBindSuccess:)]) {

            [self.delegate updateUIWithBindSuccess:YES];

        }

        [self.navigationController popViewControllerAnimated:YES];

    }else if (alertView.tag == ALREADYBIND){

        [self.navigationController popViewControllerAnimated:YES];

    }

}



- (void)getUserIDWithString:(NSString *)string{

    if (string.length > 15 && _type == 1) {

        _teacherID = [self to10:[string substringWithRange:NSMakeRange(8, 8)]];

        if (_teacherID.integerValue == 0) {

            [self Bindbluetooth];

        }else{

            [self getUserInfoWithID:_teacherID];

        }

        [self answerBack];

    }

    

}


@end




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值