zoukankan      html  css  js  c++  java
  • 第二篇、通过蓝牙连接外设

    简介:

      很早前就像总结一下手机通过蓝牙连接外设的知识点,但是由于项目比较急,也没有时间去总结。今天刚好看到一篇别人的博客,我就结合的总结了一下。

    实现的流程

    1. 建立中心角色

    2. 扫描外设(discover)

    3. 连接外设(connect)

    4. 扫描外设中的服务和特征(discover)

        - 4.1 获取外设的services

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

    5. 与外设做数据交互(explore and interact)

    6. 订阅Characteristic的通知

    7.断开连接(disconnect)

    8.模拟器蓝牙调试,慎用,最好还是用真机去调试。

    代码实现: 

    #import <Foundation/Foundation.h>
    #import <CoreBluetooth/CoreBluetooth.h>
    
    
    #define MyPeripheralName @"MyPeripheralName"
    #define MySUUID @"XXXX"
    #define MyCUUID @"XXXX"
    
    #define kNotificationConnected @"kNotificationConnected"
    #define kNotificationDisconnected @"kNotificationDisconnected"
    
    
    
    
    typedef enum _EN_Command_Type
    {
        EN_Command_Invalid = -1,
        EN_Command_Start = 0x0,
        EN_Command_Mode1 = 0x1,
        EN_Command_Mode2,
        EN_Command_Mode3,
        EN_Command_Mode4,
        EN_Command_Mode5,
        EN_Command_Mode6,
        EN_Command_Mode7,
        EN_Command_Mode8,
        EN_Command_Mode9,
        EN_Command_Stop,
        EN_Command_Shutdown,//关机
    }EN_CommandType;
    
    
    
    @interface MSBluetoothManager : NSObject<CBCentralManagerDelegate,CBPeripheralDelegate>
    
    
    @property (nonatomic,assign)BOOL bluetoothPowerOn;
    
    /**
     *  单例方法
     *
     *  @return 单例
     */
    +(MSBluetoothManager*)shareInstance;
    
    /**
     *  开始扫描
     */
    -(void)startScan;
    
    /**
     *  停止扫描
     */
    -(void)stopScan;
    
    
    /**
     *  连接
     */
    -(void)startconnect;
    
    /**
     *  取消连接
     */
    -(void)cancelConnect;
    
    
    /**
     *  向设备写数据
     */
    -(BOOL)writeData:(NSData*)data;
    
    /**
     *  是否可以准备好写数据
     *
     *  @return 是否可以准备好写数据
     */
    -(BOOL)isReady;
    
    /**
     *  发送命令
     *
     *  @param command 命令内容
     *
     *  @return 是否发送成功
     */
    -(BOOL)sendCommand:(EN_CommandType)command;
    
    
    @end
    View Code

    由于代理方法比较多,我就不一一做介绍 了

    #import "MSBluetoothManager.h"
    #import "TKAlertCenter.h"
    #define SCACN_INTERVALS 1.5
    
    
    @interface MSBluetoothManager()
    @property BOOL cbReady;
    @property (nonatomic,strong) CBCentralManager *cbCM;
    @property (strong,nonatomic) NSMutableArray *nDevices;
    @property (strong,nonatomic) NSMutableArray *nServices;
    @property (strong,nonatomic) NSMutableArray *nCharacteristics;
    
    @property (strong,nonatomic) CBPeripheral *cbPeripheral;
    @property (strong,nonatomic) CBService *cbServices;
    @property (strong,nonatomic) CBCharacteristic *cbCharacteristcs;
    
    
    @end
    
    
    
    @implementation MSBluetoothManager
    
    +(MSBluetoothManager*)shareInstance
    {
        static dispatch_once_t pred = 0;
        __strong static MSBluetoothManager *_sharedObject = nil;
        dispatch_once(&pred, ^{
            _sharedObject = [[self alloc] init]; // or some other init method
        });
        return _sharedObject;
    }
    
    
    #pragma mark -对外接口
    /**
     *  开始扫描
     */
    -(void)startScan
    {
        
        if(_bluetoothPowerOn)
        {
            if( !_cbReady   )
            {
                [self updateLog:@"Scan for Peripheral..."];
                [_cbCM scanForPeripheralsWithServices:nil options:nil];
                
                //        [self performSelector:@selector(startScan) withObject:nil afterDelay:SCACN_INTERVALS];
            }
        }
        else
        {
            //弹框提示,请去系统中打开蓝牙
            [[TKAlertCenter defaultCenter]postAlertWithMessage:NSLocalizedString(@"Please open the Bluetooth on system settings", @"请到系统设置中打开蓝牙")];
        }
        
    }
    
    /**
     *  停止扫描
     */
    -(void)stopScan
    {
        [self updateLog:@"stop scan..."];
        [_cbCM stopScan];
        
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startScan) object:nil];
    }
    
    
    /**
     *  连接
     */
    -(void)startconnect
    {
        if (_cbReady ==false)
        {
            [self.cbCM connectPeripheral:_cbPeripheral options:nil];
        }
    }
    
    /**
     *  取消连接
     */
    -(void)cancelConnect
    {
        if(_cbReady)
        {
            [_cbCM cancelPeripheralConnection:_cbPeripheral];
        }
        
    }
    
    
    /**
     *  向设备写数据
     */
    -(BOOL)writeData:(NSData*)data
    {
        BOOL ret = NO;
        if([data length] >0)
        {
            [self writeCharacteristic:_cbPeripheral sUUID:MySUUID cUUID:MyCUUID data:data];
            ret = YES;
        }
    
        return ret;
    }
    
    
    /**
     *  是否可以准备好写数据
     *
     *  @return 是否可以准备好写数据
     */
    -(BOOL)isReady
    {
        return _cbReady;
    }
    
    /**
     *  发送命令
     *
     *  @param command 命令内容
     *
     *  @return 是否发送成功
     */
    -(BOOL)sendCommand:(EN_CommandType)command
    {
        NSLog(@"begin send command:%d",command);
        BOOL ret  = NO;
        if([self isReady])
        {
            unsigned char data [6]= {0};
            data[0] = 0xa5;
            *(data+1) = 0x01;
            *(data+2) = 0x01;
    
            switch (command) {
                case EN_Command_Start:
                {
                   
                }
                    break;
                case EN_Command_Stop:
                {
                    command = 0x00;
                }
                    break;
                case EN_Command_Mode1:
                    break;
                case EN_Command_Mode2:
                    break;
                case EN_Command_Mode3:
                    break;
                case EN_Command_Mode4:
                case EN_Command_Mode5:
                case EN_Command_Mode6:
                case EN_Command_Mode7:
                case EN_Command_Mode8:
                case EN_Command_Mode9:
                {
    //                datastr = [NSString stringWithFormat:@"%d",command];
                }
                    break;
                case EN_Command_Shutdown:
                {
                    command = 0x5a;
                }
                default:
                    break;
            }
            
            NSLog(@"send command:%d",command);
            
     
            
            *(data+3) = command;
            
    //        datastr = @"1234567890";
            
    //        NSNumber* num = @(0x01);
            
    //        NSData* data = [datastr dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
            
            
                 do_crc(data,6);
          
    //        char a[10]= {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2};
            NSData *nsdata = [NSData dataWithBytes:data length: sizeof(char)*6];
            
            NSLog(@"send data: %@",nsdata);
            //真正发送命令
            ret = [self writeData:nsdata];
        }
        return ret;
    }
    
    
    
    #pragma mark -CBCentralManagerDelegate
    - (void)centralManagerDidUpdateState:(CBCentralManager *)central
    {
        switch (central.state) {
            case CBCentralManagerStatePoweredOff:
                [self updateLog:@"CoreBluetooth BLE hardware is Powered off"];
                //对外抛出断开连接的通知
                [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationDisconnected object:nil];
                _cbReady = FALSE;
                _bluetoothPowerOn = FALSE;
                break;
            case CBCentralManagerStatePoweredOn:
                [self updateLog:@"CoreBluetooth BLE hardware is Powered on and ready"];
                _bluetoothPowerOn = YES;
                break;
                //cbReady = true;
            case CBCentralManagerStateResetting:
    //            _cbReady = FALSE;
                [self updateLog:@"CoreBluetooth BLE hardware is resetting"];
                break;
            case CBCentralManagerStateUnauthorized:
                
                [self updateLog:@"CoreBluetooth BLE state is unauthorized"];
    //            _cbReady = FALSE;
                
                break;
            case CBCentralManagerStateUnknown:
                
                [self updateLog:@"CoreBluetooth BLE state is unknown"];
                break;
            case CBCentralManagerStateUnsupported:
    //            _cbReady = FALSE;
                [self updateLog:@"CoreBluetooth BLE hardware is unsupported on this platform"];
                break;
            default:
                break;
        }
    }
    
    
    //已发现从机设备
    - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
       
        [self updateLog:[NSString stringWithFormat:@"Did discover peripheral. peripheral: %@ rssi: %@, UUID: %@ advertisementData: %@ ", peripheral, RSSI, peripheral.identifier, advertisementData]];
        
        BOOL replace = NO;
        
        // Match if we have this device from before
        for (int ii=0; ii < _nDevices.count; ii++) {
            CBPeripheral *p = [_nDevices objectAtIndex:ii];
            if ([p isEqual:peripheral]) {
                [_nDevices replaceObjectAtIndex:ii withObject:peripheral];
                replace = YES;
            }
        }
        if (!replace) {
            if ([peripheral.name isEqualToString:MyPeripheralName]) {
                [_nDevices addObject:peripheral];
                [self updateLog:@"has found MyPeripheralName!
    "];
                
                _cbPeripheral = peripheral;
             
                
            }
            
        }
        if(_cbPeripheral )
        {
            //开始连接
            [self startconnect];
        }
    }
    
    
    //已链接到从机
    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
        
        
        //取消重连
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startScan) object:nil];
        
        [self updateLog:[NSString stringWithFormat:@"Connection successfull to peripheral: %@ with UUID: %@",peripheral,peripheral.identifier]];
        //Do somenthing after successfull connection.
        
        //发现services
        //设置peripheral的delegate未self非常重要,否则,didDiscoverServices无法回调
        peripheral.delegate = self;
        [_cbPeripheral discoverServices:nil];
        _cbReady = true;
        [self updateLog:@"didConnectPeripheral"];
        
        //对外抛出连接的通知
        [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationConnected object:nil];
        
        
        //统计
        [AVAnalytics event:@"ConnectToHardWare"];
        
    }
    
    
    //已断开从机的链接
    - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
        [self updateLog:[NSString stringWithFormat:@"Disconnected from peripheral: %@ with UUID: %@",peripheral,peripheral.identifier]];
        //Do something when a peripheral is disconnected.
        _cbReady = false;
        
        //对外抛出断开连接的通知
        [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationDisconnected object:nil];
        
        
        //统计
        [AVAnalytics event:@"DisconnectToHardWare"];
        
        //尝试重连
        dispatch_async(dispatch_get_main_queue(), ^{
            [self startScan];
            });
    }
    
    
    
    - (void) centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals {
        
        [self updateLog:[NSString stringWithFormat:@"Currently connected peripherals :"]];
        int i = 0;
        for(CBPeripheral *peripheral in peripherals) {
            [self updateLog:[NSString stringWithFormat:@"[%d] - peripheral : %@ with UUID : %@",i,peripheral,peripheral.identifier]];
            i++;
            //Do something on each connected peripheral.
        }
        
    }
    
    - (void) centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals {
        
        [self updateLog:[NSString stringWithFormat:@"Currently known peripherals :"]];
        int i = 0;
        for(CBPeripheral *peripheral in peripherals) {
            
            [self updateLog:[NSString stringWithFormat:@"[%d] - peripheral : %@ with UUID : %@",i,peripheral,peripheral.identifier]];
            i++;
            //Do something on each known peripheral.
        }
    }
    
    
    
    
    
    //delegate of CBPeripheral
    //已搜索到services
    -(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
        
        [self updateLog:@"Found Services."];
        
        int i=0;
        for (CBService *s in peripheral.services) {
            
            [self.nServices addObject:s];
            
        }
        
        
        for (CBService *s in peripheral.services) {
            [self updateLog:[NSString stringWithFormat:@"%d :Service UUID: %@(%@)",i,s.UUID.data,s.UUID]];
            i++;
            [peripheral discoverCharacteristics:nil forService:s];
        }
    }
    
    
    
    
    #pragma mark -CBPeripheralDelegate
    //
    ////已读到char
    //-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    //    if (error) {
    //        return;
    //    }
    //    unsigned char data[characteristic.value.length];
    //    [characteristic.value getBytes:&data];
    //    
    //    
    //}
    
    
    
    //已搜索到Characteristics
    -(void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
        [self updateLog:[NSString stringWithFormat:@"Found Characteristics in Service:%@ (%@)",service.UUID.data ,service.UUID]];
        
        for (CBCharacteristic *c in service.characteristics) {
            [self updateLog:[NSString stringWithFormat:@"Characteristic UUID: %@ (%@)",c.UUID.data,c.UUID]];
            [_nCharacteristics addObject:c];
            
        }
    }
    
    
    
    
    //已读到char
    -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
        if (error) {
            return;
        }
        unsigned char data[characteristic.value.length];
        [characteristic.value getBytes:&data];
        NSDate*date = [NSDate date];
        NSCalendar*calendar = [NSCalendar currentCalendar];
        NSDateComponents*comps;
        comps =[calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit |NSSecondCalendarUnit) fromDate:date];
        
        NSInteger hour = [comps hour];
        NSInteger minute = [comps minute];
        NSInteger second = [comps second];
        
        [self updateLog:[NSString stringWithFormat:@"char update! [%ld:%ld:%ld],char = %d",hour,minute,second,data[0]]];
    }
    
    
    #pragma mark -内部函数
    -(id)init
    {
        if(self = [super init])
        {
            _cbCM = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
            _cbServices =[[CBService alloc]init];
            _cbCharacteristcs =[[CBCharacteristic alloc]init];
            
            //列表初始化
            _nDevices = [[NSMutableArray alloc]init];
            _nServices = [[NSMutableArray alloc]init];
            _nCharacteristics = [[NSMutableArray alloc]init];
            
            _cbReady = FALSE;
            _bluetoothPowerOn = FALSE;
            
        }
        return self;
    }
    
    
    
    -(void)updateLog:(NSString *)s
    {
        //用回NSLog,
        NSLog(@"%@",s );
    }
    
    
    
    -(void)writeCharacteristic:(CBPeripheral *)peripheral sUUID:(NSString *)sUUID cUUID:(NSString *)cUUID data:(NSData *)data {
        // Sends data to BLE peripheral to process HID and send EHIF command to PC
        for ( CBService *service in peripheral.services ) {
            
            if ([service.UUID isEqual:[CBUUID UUIDWithString:sUUID]]) {
                
                for ( CBCharacteristic *characteristic in service.characteristics ) {
                    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:cUUID]]) {
                        [self updateLog:@"has reached
    "];
                        /* EVERYTHING IS FOUND, WRITE characteristic ! */
                        
                        [peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
                        
                    }
                }
            }
        }
    }
    
    
    -(void)setNotificationForCharacteristic:(CBPeripheral *)peripheral sUUID:(NSString *)sUUID cUUID:(NSString *)cUUID enable:(BOOL)enable {
        for ( CBService *service in peripheral.services ) {
            if ([service.UUID isEqual:[CBUUID UUIDWithString:sUUID]]) {
                for (CBCharacteristic *characteristic in service.characteristics ) {
                    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:cUUID]])
                    {
                        /* Everything is found, set notification ! */
                        [peripheral setNotifyValue:enable forCharacteristic:characteristic];
                    }
                    
                }
            }
        }
    }
    
    - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
    
    {
        
        [self updateLog:[NSString stringWithFormat:@"%@",error]];
        
        
    }
    
    
    void  do_crc(unsigned char *data,
                 unsigned short int length)
    {
       //此处为加密算法,略去
        
    }
    
    
    @end
    View Code
  • 相关阅读:
    160720、SSM-Shiro使用详解
    Python学习(4)运算符
    Python学习(3)变量类型
    Python学习(2)基本语法
    Python学习(1)安装Python
    MonkeyRunner学习(3)脚本编辑
    MonkeyRunner学习(2)常用命令
    MonkeyRunner学习(1)测试连接
    Monkey学习(4)简单测试实例
    Monkey学习(3)如何在Android模拟器中安装apk
  • 原文地址:https://www.cnblogs.com/HJQ2016/p/5790347.html
Copyright © 2011-2022 走看看